• struts2基础


    注意:

    1.action对象是多例的,每次请求都创建一个对象,线程安全

    2.struts2默认拦截没有后缀,或者.action的请求

    3.struts2注解依赖的jar包:struts2-convention-plugin-2.3.15.3.jar,asm...jar[三个]

    4.jar包:

    1.struts2的配置文件

    default.properties:注意配置常量  【不可改,在jar包中】

    struts-default.xml :常量,bean,struts-default包【结果视图,拦截器】,默认动作类,动作方法【不可改,jar包中】

    struts-plugin.xml  【不可改】

    struts.xml  【自己创建】

    struts.properties  【自己创建】

    web.xml

    加载顺序:default.propeties ->struts-default.xml->struts-plugin.xml->struts.properties->web.xml

     2.struts2核心思想

    结果视图:

      以ServletDispatcherResult为例:继承StrutsResultSupport类,

    public class ServletDispatcherResult extends StrutsResultSupport {
        private static final long serialVersionUID = -1970659272360685627L;
        private static final Logger LOG = LoggerFactory.getLogger(ServletDispatcherResult.class);
        private UrlHelper urlHelper;
    
        public ServletDispatcherResult() {
        }
    
        public ServletDispatcherResult(String location) {
            super(location);
        }
    
        @Inject
        public void setUrlHelper(UrlHelper urlHelper) {
            this.urlHelper = urlHelper;
        }
    
        public void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {
            if (LOG.isDebugEnabled()) {
                LOG.debug("Forwarding to location " + finalLocation, new String[0]);
            }
    
            PageContext pageContext = ServletActionContext.getPageContext();
            if (pageContext != null) {
                pageContext.include(finalLocation);
            } else {
                HttpServletRequest request = ServletActionContext.getRequest();
                HttpServletResponse response = ServletActionContext.getResponse();
                RequestDispatcher dispatcher = request.getRequestDispatcher(finalLocation);
                if (StringUtils.isNotEmpty(finalLocation) && finalLocation.indexOf("?") > 0) {
                    String queryString = finalLocation.substring(finalLocation.indexOf("?") + 1);
                    Map<String, Object> parameters = this.getParameters(invocation);
                    Map<String, Object> queryParams = this.urlHelper.parseQueryString(queryString, true);
                    if (queryParams != null && !queryParams.isEmpty()) {
                        parameters.putAll(queryParams);
                    }
                }
    
                if (dispatcher == null) {
                    response.sendError(404, "result '" + finalLocation + "' not found");
                    return;
                }
    
                Boolean insideActionTag = (Boolean)ObjectUtils.defaultIfNull(request.getAttribute("struts.actiontag.invocation"), Boolean.FALSE);
                if (!insideActionTag.booleanValue() && !response.isCommitted() && request.getAttribute("javax.servlet.include.servlet_path") == null) {
                    request.setAttribute("struts.view_uri", finalLocation);
                    request.setAttribute("struts.request_uri", request.getRequestURI());
                    dispatcher.forward(request, response);
                } else {
                    dispatcher.include(request, response);
                }
            }
    
        }
    
        private Map<String, Object> getParameters(ActionInvocation invocation) {
            return (Map)invocation.getInvocationContext().getContextMap().get("parameters");
        }
    }
    ServletDispatcherResult

      

      最终执行的是request.getRequestDispatcher(location).forward(req, resp)方法,相当于一个处理请求的最终servlet

      因此,可以自定义结果视图类型,灵活的完成各种输出:

    下面以输出验证码为例:

    jar包:ValidateCode.jar

    package cn.getword.result;
    
    import cn.dsna.util.images.ValidateCode;
    import com.opensymphony.xwork2.ActionInvocation;
    import org.apache.struts2.ServletActionContext;
    import org.apache.struts2.dispatcher.StrutsResultSupport;
    
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * 自定义结果视图类型
     */
    public class CaptchaResult extends StrutsResultSupport {
        //配置图像的大小
        private int width;
        private int height;
    
    
        @Override
        protected void doExecute(String finalLocation, ActionInvocation invocation)
                throws Exception {
            // TODO Auto-generated method stub
            /***
             * 1.导入第三方验证码生成包
             * 2.创建ValidateCode对象
             * 3.获取相应对象
             * 4.输出验证码
             */
            ValidateCode code=new ValidateCode(width,height,4,150);
            HttpServletResponse response= ServletActionContext.getResponse();
    //        response.getWriter().print("hello world");
            code.write(response.getOutputStream());
    
        }
    
        public int getWidth() {
            return width;
        }
    
    
        public void setWidth(int width) {
            this.width = width;
        }
    
    
        public int getHeight() {
            return height;
        }
    
    
        public void setHeight(int height) {
            this.height = height;
        }
    
    }
    CaptchaResult

    在struts.xml中配置使用自定义结果视图类型:

        <!-- 验证码 -->
        <package name="validateCode" namespace="/validate" extends="struts-default">
    
            <!-- 自定义结果视图类型  局部 -->
            <result-types>
                <result-type name="catpcha" class="cn.getword.result.CaptchaResult"></result-type>
            </result-types>
            <!--
                使用默认动作类ActionSupport来处理,默认返回success,返回的结果视图类型为自定义结果视图catpcha(类似Servlet类),
             -->
            <action name="captcha">
                <!-- 视图结果处理类类似于一个Servlet类,不同的类型完成不同的任务,如请求转发、重定向、自定义处理类型 -->
                <result name="success" type="catpcha">
                    <!-- 配置图像的大小,依赖注入 -->
                    <param name="width">200</param>
                    <param name="height">50</param>
                </result>
            </action>
        </package>
    struts.xml

       

    运行结果:

    3.package标签

    package:

      name:包名,唯一

      extends:继承父包,默认继承struts-default,在struts-default.xml中配置

      abstract:是否为抽象包,抽象包中不允许出现action动作

      namespace:命名空间,模块化管理,必须以 / 开头,第一个字符必须是字母,

        默认值:""

     4.action标签

      name:

      class:

      method:

    action 的三种访问方式:

    • 全匹配方式:
    • 通配符:

    基本用法:

    <package name="user" extends="struts-default" namespace="/user">
        <!-- {1}:表示第一个匹配到的* -->
        <action name="*User" class="cn.getword.action.UserAction" method="{1}User">
            <result name="success" type="dispatcher">/index.jsp</result>
        </action>
    </package>

    更彻底的方式:

    <package name="user" extends="struts-default" namespace="/user">
        <!-- {1}:表示第一个匹配到的* -->
        <action name="*_*" class="cn.getword.action.{2}Action" method="{1}{2}">
            <result name="success" type="dispatcher">/index.jsp</result>
        </action>
    </package>
    • 动态方法调用
    <constant name="struts.enable.DynamicMethodInvocation" value="true" />
    <action name="user" class="cn.getword.action.UserAction">
        <result name="success" type="dispatcher">/index.jsp</result>
    </action>

    <a href="/user?addUser"> :  user对应action的name属性,addUser对应动作类的方法

     5.动作类的创建方式

    (1)无侵入低耦合的方式 POJO  【基本不用】

    (2)实现Action接口,实现excute方法【默认动作方法】

    package cn.getword.action;
    
    import com.opensymphony.xwork2.Action;
    
    
    public class MainAction implements Action{
    
        @Override
        public String execute() throws Exception {
            return null;
        }
    }
    MainAction

    (3)继承ActionSupport类

      默认的动作类为:ActionSupport

      默认动作方法:excute方法

     6.result结果视图

      常用逻辑结果视图:

    chain:转发到action【同包】

    dispatcher:只能转发到物理视图

    redirect:url原封不动的返回给客户端,客户端再次使用这个地址发起请求。

    redirectAction:重定向到action【同包或不同包】,默认会自动加上后缀名

     

    全局结果视图:

        <package name="mydefault" extends="struts-default" abstract="true">
            <global-results>
                <result name="error">/WEB-INF/views/error.jsp</result>
            </global-results>
        </package>
    
        <package name="p2" extends="mydefault">
            <action name="index" class="cn.getword.action.MainAction" method="index">
                <result name="success">/index.jsp</result>
            </action>
            <action name="login">
                <result type="dispatcher">/WEB-INF/views/login.jsp</result>
            </action>
        </package>
    View Code

    JSONResult结果视图:

    (1)jar包:struts2-json-plugin...jar

    (2)struts.xml

       <package name="p1" extends="json-default">
            <action name="getUsers" class="cn.getword.action.UserAction" method="allUsers">
                <result type="json">
                    <param name="noCache">true</param>
                    <param name="contentType">application/json</param>
                </result>
            </action>
        </package>

    (3)UserAction

    package cn.getword.action;
    
    import cn.getword.domain.User;
    import com.opensymphony.xwork2.ActionSupport;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class UserAction extends ActionSupport {
        private List<User> users;
        private User user;
    
        public User getUser() {
            return user;
        }
    
        public void setUser(User user) {
            this.user = user;
        }
    
        public List<User> getUsers() {
            return users;
        }
    
        public void setUsers(List<User> users) {
            this.users = users;
        }
    
        public String allUsers(){
            user = new User(){{
                setId(1);
                setUsername("admin");
                setAge(12);
            }};
            users = new ArrayList<User>();
            users.add(new User(){{
                setId(1);
                setUsername("admin");
                setAge(12);
            }});
            users.add(new User(){{
                setId(2);
                setUsername("张三");
                setAge(21);
            }});
            return SUCCESS;
        }
    }
    UserAction.java

    (4)结果

    7.访问Servlet API

    方式一:使用工具类:ServletActionContext【常用】

    public class MainAction extends ActionSupport {
        public String index(){
            ServletActionContext.getRequest();  //struts2提供的包装类
            ServletActionContext.getRequest();
            ServletActionContext.getRequest().getSession();
            ServletActionContext.getServletContext();
            return ERROR;
        }
    }

    方式二:通过实现接口的方式。拦截器ServletConfig封装参数

    public class MainAction extends ActionSupport implements ServletRequestAware{
        private HttpServletRequest request;
        public String index(){
            System.out.println(request);
            return ERROR;
        }
    
        @Override
        public void setServletRequest(HttpServletRequest request) {
            this.request = request;
        }
    }

     

    第三种方式:上面两种方式的底层都是通过ActionContext的get(key)获取的

      ActionContext

     8.请求参数的封装

      ParameterInterceptor拦截器做了数据类型转换。【注意,请求参数封装到动作类实例的成员变量中,是拦截器干的事情

    方式一:属性驱动-没有实体类

      注意:动作类中定义对应的成员变量,必须要有set和get 方法

      对于多个name相同的值转化成数组

    public class User1Action extends ActionSupport {
        private String username;
        private int age;
        private Date birthday;
        private String[] hobby;
    
        public String register(){
            System.out.println(username+","+age+","+birthday+","+ Arrays.toString(hobby));
            return "register";
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public Date getBirthday() {
            return birthday;
        }
    
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    
        public String[] getHobby() {
            return hobby;
        }
    
        public void setHobby(String[] hobby) {
            this.hobby = hobby;
        }
    }
    UserAction

     表单:

      <form method="post" action="${pageContext.request.contextPath}/user/register">
        username:<input type="text" name="username"><br>
        age:<input type="text" name="age"><br>
        birthday:<input type="text" name="birthday"><br>
        hobby:<input type="checkbox" name="hobby" value="篮球">篮球
        <input type="checkbox" name="hobby" value="足球">足球
        <input type="checkbox" name="hobby" value="排球">排球<br>
        <input type="submit" value="提交" />
      </form>
    View Code

      使用场景:不需要实体类的情况,如分页、查询等,不需要存储到数据库的表单数据。

    方式二:属性驱动:有实体类  【不常用】

      在动作类中定义一个实体类成员变量,提供get、set方法。

    Action:

    public class User2Action extends ActionSupport {
        private User user;
        public String register(){
            System.out.println(user);
            return SUCCESS;
        }
    
        public User getUser() {
            return user;
        }
    
        public void setUser(User user) {
            this.user = user;
        }
    }
    View Code

      表单的name为user.xxx【OGNL表达式】

    Form:

      <form method="get" action="${pageContext.request.contextPath}/user/register">
        username:<input type="text" name="user.username"><br>
        age:<input type="text" name="user.age"><br>
        birthday:<input type="text" name="user.birthday"><br>
        hobby:<input type="checkbox" name="user.hobby" value="篮球">篮球
        <input type="checkbox" name="user.hobby" value="足球">足球
        <input type="checkbox" name="user.hobby" value="排球">排球<br>
        <input type="submit" value="提交" />
      </form>
    View Code

     方式三:模型驱动,实现ModelDriven<>接口 【常用】

      规范:实现ModelDriver接口,模型属性必须new。

    public class User3Action extends ActionSupport implements ModelDriven<User> {
        private User user = new User();
    
        public String register(){
            System.out.println(user);
            return SUCCESS;
        }
    
        public User getUser() {
            return user;
        }
    
        public void setUser(User user) {
            this.user = user;
        }
    
        @Override
        public User getModel() {
            return user;
        }
    }
    View Code

    集合类型的参数封装:

      集合类型的参数只能通过属性驱动来封装。【OGNL】

    (1)list集合   name: users[0].xxx

    action:

    public class User4Action extends ActionSupport {
        private List<User> users;
    
        public String register(){
            System.out.println(users);
            return SUCCESS;
        }
    
        public List<User> getUsers() {
            return users;
        }
    
        public void setUsers(List<User> users) {
            this.users = users;
        }
    }
    View Code

    form:

    <form method="get" action="${pageContext.request.contextPath}/user/register">
        username:<input type="text" name="users[0].username"><br>
        age:<input type="text" name="users[0].age"><br>
        birthday:<input type="text" name="users[0].birthday"><br>
        hobby:<input type="checkbox" name="users[0].hobby" value="篮球">篮球
        <input type="checkbox" name="users[0].hobby" value="足球">足球
        <input type="checkbox" name="users[0].hobby" value="排球">排球<br>
        <input type="submit" value="提交" />
      </form>
    View Code

     (2)Map对象

      OGNL: name : users['key'].xxx

    action:

    public class User5Action extends ActionSupport {
        private Map<String, User> users;
    
        public String register(){
            for (String k :
                    users.keySet()) {
                System.out.println("key:"+k+", value:"+ users.get(k));
            }
            return SUCCESS;
        }
    
        public Map<String, User> getUsers() {
            return users;
        }
    
        public void setUsers(Map<String, User> users) {
            this.users = users;
        }
    }
    View Code

    form:

      <form method="get" action="${pageContext.request.contextPath}/user/register">
        username:<input type="text" name="users['user1'].username"><br>
        age:<input type="text" name="users['user1'].age"><br>
        birthday:<input type="text" name="users['user1'].birthday"><br>
        hobby:<input type="checkbox" name="users['user1'].hobby" value="篮球">篮球
        <input type="checkbox" name="users['user1'].hobby" value="足球">足球
        <input type="checkbox" name="users['user1'].hobby" value="排球">排球<br>
        <input type="submit" value="提交" />
      </form>
    View Code

    9.请求封装异常处理【封装失败,如日期转换失败,数字转换等】,数据回显(界面太丑,基本不用)

      适用于模型驱动,有实体类的属性驱动

      当ParameterInterceptor做类型转化时发生错误,将返回input逻辑视图,因此只要在action中配置input结果视图即可

    struts.xml:

       <package name="p3" extends="struts-default" namespace="/user">
            <action name="register" class="cn.getword.action.User3Action" method="register">
                <result name="success">/WEB-INF/views/success.jsp</result>
                <result name="input" type="redirect">/user/register</result>
            </action>
        </package>
    struts.xml

     action:

    public class User3Action extends ActionSupport implements ModelDriven<User> {
        private User user = new User();
    
        public String register(){
            System.out.println(user);
            return SUCCESS;
        }
    
        public User getUser() {
            return user;
        }
    
        public void setUser(User user) {
            this.user = user;
        }
    
        @Override
        public User getModel() {
            return user;
        }
    }
    View Code

    form:

    register.jsp

      或者使用struts提供的form表单: 

      <%--自动补齐项目前缀--%>
      <s:form action="user/register">
        <s:textfield name="username" label="姓名" />
        <s:textfield name="age" label="年龄" />
        <s:textfield name="birthday" label="生日" />
        <s:checkbox name="hobby" value="篮球" fieldValue="篮球" label="篮球" />
        <s:checkbox name="hobby" value="足球" fieldValue="足球" label="足球" />
        <s:checkbox name="hobby" value="排球" fieldValue="排球" label="排球" />
    
        <s:submit value="提交" />
      </s:form>
    View Code

    将提示信息改为中文:在模型类的同目录下创建User.properties属性文件。

    invalid.fieldvalue.birthday=日期格式不对

      在实际项目开发中,需要在前端进行表单验证,因此传到后台的数据基本合法,如何不合法(转换失败),需要提供input结果视图,以防止出现尴尬的界面(struts的报错界面)

       表单数据被保存在request域中,因此可以使用EL表达式进行数据回显。

      <form method="post" action="${pageContext.request.contextPath}/user/register">
        username:<input type="text" name="username" value="${username}"><br>
        age:<input type="text" name="age" value="${age}"><br>
        birthday:<input type="text" name="birthday" value="${birthday}" ><br>
        hobby:<input type="checkbox" name="hobby" value="篮球">篮球
        <input type="checkbox" name="hobby" value="足球">足球
        <input type="checkbox" name="hobby" value="排球">排球<br>
        <input type="submit" value="提交" />
      </form>
    View Code

      使用此方法,可以解决struts2的标签带来的bug,例如:封装失败后,第一次返回input结果视图,第二次返回error结果视图

       此外,还发现一个问题,struts2对于post和get请求没有过滤区分?

    end

  • 相关阅读:
    我很高兴,很欣慰:)
    任天堂Wii低价发布 游戏革命今冬开始
    血狮——当年号称已经超越C&C的游戏
    网络游戏《防沉迷系统开发标准(试行)》内容
    经典劣作《大卡车》演示视频
    SANTENDO的大脑训练计划
    linq
    对象构造者
    扩展方法
    隐式类型化本地变量
  • 原文地址:https://www.cnblogs.com/zhuxiang1633/p/9700378.html
Copyright © 2020-2023  润新知