struts2入门到精通教程

为什么要使用struts2以及Servlet的缺点

servlet的缺点:
   1、写一个servlet需要在web.xml文件中配置8行,如果一个系统中servlet很多,则会导致
       web.xml文件中的内容很多
   2、在项目中很多人编辑一个web.xml文件会出现版本冲突的问题
   3、在一个servlet中方法的入口只有一个,如果在servlet中写很多方法,这些方法应该传递参数,根据每次
       请求的参数不一致来判断执行哪个方法
   4、servlet中的方法都有两个参数request,response,这两个参数具有严重的容器依赖性,所以在
       servlet中写的代码是不能单独测试的
   5、现在写一个servlet,为注册servlet
           ResigterServlet{
               public void doPost(){
                1、权限的操作
            2、获取表单中的数据
            3、文件的上传的功能
            4、表单上的元素进行验证
            5、保存一个用户
           }
           }
    6、如果在表单中的元素很多,在servlet中要想获取表单中的数据,那么在servlet的方法中必要有大量的
        request.getParameter代码
    7、在一个servlet的属性中声明一个数据,会存在线程安全的问题
Servlet的优点:
因为是最低层的mvc,所以效率比较高
struts2中action是否安全

struts2的action的说明:
1、action是多实例的,每请求一次将会创建一个对象
2、是不存在线程安全的问题的

servletde 重构

第一步:写一个监听器在tomcat初始化的时候执行
public class ActionListener implements ServletContextListener{
    /**
     * tomcat销毁的时候执行
     */
    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        // TODO Auto-generated method stub
        /**
         * 在tomcat销毁的时候,清空application域中的所有的action的配置
         */
        arg0.getServletContext().setAttribute("actions", null);
    }
    /**
     * tomcat初始化的时候执行
     */
    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        /**
         * 1、创建一个map
         * 2、把key,value放入到map中
         * 3、把map放入到application域中
         */
        Map<String, String> map = new HashMap<String, String>();
        map.put("userAction", "cn.itcast.sh08.action.UserAction");
        arg0.getServletContext().setAttribute("actions", map);
    }

}
第二步:写一个ActionServlet:

在访问地址http://localhost8080//userAction.action的时候将这个url地址发送到Actionservlet中,然后解析这个url地址,

/**
         * 1、获取url
         * 2、对url进行解析,把"userAction"的部分解析出来
         * 3、获取到application
         * 4、从application中把map提取出来
         * 5、根据"userAction"从map中把value提取出来
         * 6、利用java的反射机制进行调用
         */
        //itcastsh08_super_servlet/userAction.action
        String uri = request.getRequestURI();
        /**
         * 把uri传递进去,解析出来userAction
         */
        String actionName = StringUtils.parse(uri);
        /**
         * 通过key:userAction,得到value:userAction的类名
         */
        Map<String, String> map = (HashMap<String, String>)this.getServletContext().getAttribute("actions");
        String actionClassName = map.get(actionName);
        try {
            /**
             * 得到了请求的action所对应的execute方法
             */
            Class classt = Class.forName(actionClassName);
            String httprequest = "javax.servlet.http.HttpServletRequest";
            Class requestClass = Class.forName(httprequest);
            String httpresponse = "javax.servlet.http.HttpServletResponse";
            Class responseClass = Class.forName(httpresponse);
            Method method = classt.getMethod("execute",requestClass,responseClass);
            String result = (String)method.invoke(classt.newInstance(),request,response);
            request.getRequestDispatcher(result).forward(request, response);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 

这里的StringUtils是用来获取userAction的

struts.xml详解

关于包的name的作用
 <package name="system" namespace="/" extends="struts-default">:其中的name=“”的作用是用来区分不同模块功能下的不同包( package代表一个模块,name为模块的名称,而且值是唯一的)
关于extend的功能
 extends="struts-default"实际上是把package中name为"struts-default"的包中的所有的功能
如果想要使用某一个包的action,可以使用继承<package name="aa" namespace="/world" extends="helloworld">
</package>这里面extend="这里面是某一个包的名字"

<package name="helloworld" namespace="/base" extends="struts-default">
    <action name="helloWorldAction" class="cn.itcast.sh08.struts2.action.HelloWorldAction">
        <result name="index">index.jsp</result>
    </action>

关于命名空间:
    1、上述的namespace和url有关系
    2、如果namespace为"/"
            那么在url中项目名称后面紧接着跟action中name的名称
        namespace="/"
        http://localhost:8088/itcastsh08_struts2_package_namespace/helloWorldAction.action
    3、如果namespace为"/base"
        http://localhost:8088/itcastsh08_struts2_package_namespace/base/helloWorldAction.action
    4、如果namespace为"/base"
         itcastsh08_struts2_package_namespace/helloWorldAction.action  
                 该url是请求不到的
         itcastsh08_struts2_package_namespace/base/helloWorldAction.action
                 该url可以请求到
         itcastsh08_struts2_package_namespace/base/a/helloWorldAction.action
                                       也可以请求到 ,查找规则:
                  1、先找base/a下的helloWorldAction
                  2、再查找base下的helloWorldAction
    5、在url中加了几层命名空间,则在转向到jsp页面时,jsp的路径也会加几个命名空间的名字的路径
            base/a/helloWorldAction.action
            base/a/b/index.jsp
    6、如果采用上述的命名空间的形式,命名空间有什么的名称,在webroot下就应该建立什么样的文件夹
关于两个配置文件struts.xml和struts-default.xml
1、这两个配置文件都是在服务器启动的时候加载的
2、这两个配置文件都放在了classpath的根目录
     struts.xml文件放在了src的根目录
     struts-default.xml文件是在struts2核心包的根目录下
3、struts.xml文件是供程序员使用的
   struts-default.xml文件是运行struts2低层的xml文件
4、先加载struts-default.xml文件,后加载struts.xml文件
5、因为dtd都一样,如果出现相同的元素,后者覆盖前者
关于result
<result name="list" >/admin/jsp/userAction/list.jsp</result>
        <result name="toList" type="redirectAction">user_list</result>
        一般用的就两种,result中间的是jsp页面这样的是转发的方式,或者是user_list这表示重定向,重新请求一个方法
关于include的使用
include保证了可以有很多个xml文件
<struts>
    <include file="struts-helloworld.xml"></include>
</struts>
在企业里最好保证人手一份xml文件,这样不会出现冲突的问题
关于action的几种写法
action的写法
   1、就是一个最简单的javabean
        public class HelloWorldAction {
            public String execute(){
                System.out.println("hello world");
                return "index";
            }
        }
   2、让一个action实现接口Action
        public class HelloWorld2Action implements Action{
            /**
             * 如果实现了Action接口,应该把方法写在execute里
             */
            public String execute(){
                System.out.println("hello world");
                return SUCCESS;
            }
        }
        <result>index.jsp</result>
    3、让一个类继承ActionSupport
        ActionSupport中含有一些功能:
           1、国际化
           2、表单验证
        如果让一个action类继承了ActionSupport就能直接使用ActionSupport中的国际化、表单验证等功能
    4、如果在action的配置中这样配置:
         <action name="helloWorld3Action">
            <result>index.jsp</result>
        </action>
        那么在struts-default.xml文件中有一句话将起作用:
           <default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
        这个时候将执行ActionSupport中的execute方法
通配符的映射
 1、第一种情况
   url:
      http://localhost:8088/itcastsh08_struts2_action/helloWorldAction.action
                 配置文件:
      <package name="helloworld" namespace="/" extends="struts-default">
        <action name="helloWorldAction" class="cn.itcast.sh08.struts2.action.HelloWorldAction">
            <result name="index">index.jsp</result>
        </action>
      </package>
         如果采用该结构,只能执行helloWorldAction中的execute方法
   2、第二种情况
        在配置文件的action标签中可以指定method属性
        <action name="userAction" method="saveUser" 
            class="cn.itcast.sh08.struts2.action.UserAction">
            <result>index.jsp</result>
        </action>
        url:http://localhost:8088/itcastsh08_struts2_methodpattern/userAction.action
        这个时候,将请求userAction中method属性的值指定的方法:saveUser
       缺点:
               如果在UserAction中出现很多个方法,因为每一个方法配置一个action,所以有几个方法就得配置几个action
   3、第三种情况
        <package name="method2" namespace="/m2" extends="struts-default">
            <action name="userAction" class="cn.itcast.sh08.struts2.action.UserAction">
                <result>index.jsp</result>
            </action>
        </package>
        url:
            http://localhost:8088/itcastsh08_struts2_methodpattern/m2/userAction!deleteUser.action
        UserAction中的其中的一个方法和userAction!deleteUser中的叹号后面的内容一样
        为动态调用该方法
    4、请求UserAction中的saveUser方法:
            要求:a_add.action,b_add.action,c_add.action都可以请求
    5、配置文件
        <action name="*_add" method="{1}" class="cn.itcast.sh08.struts2.action.UserAction">
            <result>index.jsp</result>
        </action>
    6、请求UserAction和PersonAction中的pattern方法
        <action name="*_pattern" method="pattern" class="cn.itcast.sh08.struts2.action.{1}">
            <result>index.jsp</result>
        </action>
    7、配置文件中
        <package name="method6" namespace="/" extends="struts-default">
            <action name="UserAction_*" method="{1}" class="cn.itcast.sh08.struts2.action.UserAction">
                <result>{1}.jsp</result>
            </action>
        </package>
    8、配置文件中
        <action name="*_*" method="{2}" class="cn.itcast.sh08.struts2.action.{1}">
            <result>{2}.jsp</result>
        </action>

        统配的程度越高,匹配的范围越大,越容易出问题
我通常情况下用的是这样的
    <action name="user_*" method="{1}" class="cn.itcast.sh08.struts2.action.userAction">
<result name=“list”>list.jsp</result>
</action>
    jsp页面请求的方式类似于user_list,method表示的是list,list是action中的list方法,result中的name中的list表示的是action中list方法中的return list
先介绍如何使用valueStack储存数据以及其储存数据的结构图

struts2的值栈valueStack (存储值)

前言

在servlet中解决数据的存储和显示
把一个数据放在request,session,application域中,在页面上利用ognl表达式就可以显示出来

概述
    1、ValueStack是一个接口,在struts2中使用OGNL表达式实际上是使用实现了ValueStack接口的类OgnlValueStack,这个类是OgnlValueStack的基础。
    2、ValueStack贯穿整个action的生命周期。每一个action实例都拥有一个ValueStack对象。其中保存了当前action对象和其他相关对象。
内存图

这里写图片描述

组织结构

这里写图片描述

从图上可以看出OgnlValueStack和我们有关的内容有两部分:即OgnlContext和CompoundRoot。所以把这两部分搞清楚很重要。

valueStack总体结构图

这里写图片描述

说明:
1、上图是ognl完整的数据结构图,可以清晰得看出数据的组成。
2、Context中的_root和ValueStack中的root(对象栈)里的数据结构和值是一样的。
3、这就意味着我们只需要操作OgnlContext就可以完成对数据的存和取的操作。
4、ValueStack内部有两个逻辑的组成部分:
a)ObjectStack
Struts会把动作和相关的对象压入到ObjectStack中。
b)ContextMap
Struts会把一些映射关系压入到ContextMap中

获取valueStack的三种方式
ValueStack valueStack = ActionContext.getContext().getValueStack();
    ValueStack valueStack2 = ServletActionContext.getContext().getValueStack();
    ValueStack valueStack3 = (ValueStack)ServletActionContext.getRequest().getAttribute("struts.valueStack");
valueStack的内存结构:
 root:对象栈
 context:OgnlContext
      _root:对象栈
      _values:map栈
对象栈的操作
 1、把数据放入到对象栈中
    valueStack.push  放入到对象栈的栈顶
    valueStack.getRoot().add("aaaa");  放入到了对象栈的栈底
    ActionContext.getContext().getValueStack().set("aaa", "asfd");  把一个map放入到了对象栈的栈顶
    valueStack.getRoot().add(0,"aaaa"); 放入到了对象栈的栈顶
2、从对象栈中把数据提取出来
    ActionContext.getContext().getValueStack().getRoot().get(0);
    ActionContext.getContext().getValueStack().peek();
       获取对象栈的栈顶的元素
3、移除栈顶元素
     ActionContext.getContext().getValueStack().getRoot().remove(0);
     ActionContext.getContext().getValueStack().pop();
map栈的操作
 1、可以把一个对象放入到map栈中的reuqest域中
    ServletActionContext.getRequest().setAttribute("aaa", "aaa");
2、可以把一个对象放入到map栈的application域中
    ServletActionContext.getServletContext().setAttribute("aaaa", "aaaa");
3、可以把一个对象放入到map栈中
    ActionContext.getContext().put("aaa", "aaaa");
如何将值放在valueStack
/*
     * 把数据放入对象栈中的第一种方式
     */
    public String addDataToObjectStack_1(){
        ValueStack valueStack = ActionContext.getContext().getValueStack();
        /**
         * 把字符串添加到了CompoundRoot的第一个位置,我们把第一个位置称为对象栈的栈顶
         */
        valueStack.push("aaaaa");
        return "";
    }

    /*
     * 把数据放入对象栈中的第二种方式
     */
    public String addDataToObjectStack_2(){
        ValueStack valueStack = ActionContext.getContext().getValueStack();
        /**
         * 把字符串添加到了对象栈中
         */
        valueStack.getRoot().add("aaaa");
        return "";
    }

    /*
     * 把数据放入对象栈中的第三种方式
     */
    public String addDataToObjectStack_3(){
        ValueStack valueStack = ActionContext.getContext().getValueStack();
        /**
         * 把字符串添加到了对象栈中
         *    把一个map放入到了对象栈的栈顶,"aaa"作为key,"asfd"作为value
         */
        ActionContext.getContext().getValueStack().set("aaa", "asfd");
        return "";
    }

    /**
     * 从对象栈中把数据提取出来的方式
     *    第一种方式
     */
    public String addDataFromObjectStack_1(){
        ValueStack valueStack = ActionContext.getContext().getValueStack();
        /**
         * 提取栈顶的元素
         */
        ActionContext.getContext().getValueStack().getRoot().get(0);
        return "";
    }

    /**
     * 从对象栈中把数据提取出来的方式
     *    第二种方式
     */
    public String addDataFromObjectStack_2(){
        ValueStack valueStack = ActionContext.getContext().getValueStack();
        /**
         * 提取栈顶的元素
         */
        ActionContext.getContext().getValueStack().peek();
        return "";
    }

    /*
     * 把对象栈的栈顶的元素移除
     */
    public String removeDataFromObjectStack_1(){
        ValueStack valueStack = ActionContext.getContext().getValueStack();
        /**
         * 移除栈顶的元素
         */
        ActionContext.getContext().getValueStack().getRoot().remove(0);
        return "";
    }

    /*
     * 把对象栈的栈顶的元素移除
     */
    public String removeDataFromObjectStack_2(){
        ValueStack valueStack = ActionContext.getContext().getValueStack();
        /**
         * 移除栈顶的元素
         */
        ActionContext.getContext().getValueStack().pop();
        return "";
    }

    /**
     * 把一个key,value键值对放入到request域中
     */
    public String putObjectToRequest(){
        ServletActionContext.getRequest().setAttribute("aaa", "aaa");
        ValueStack valueStack = ActionContext.getContext().getValueStack();
        return "";
    }

    /**
     * 把一个key,value键值对放入到application域中
     */
    public String putObjectToApplication(){
        ServletActionContext.getServletContext().setAttribute("aaaa", "aaaa");
        ValueStack valueStack = ActionContext.getContext().getValueStack();
        return "";
    }

    /**
     * 把一个key,value直接放在map栈中
     */
    public String putDataToMapStack_1(){
        ValueStack valueStack = ActionContext.getContext().getValueStack();
        ActionContext.getContext().put("aaa", "aaaa");
        return "";
    }
ognlContext组织结构(第一部分 数据存储主要在这里面)
_values(这里介绍如何把值放在map中的request application以及session中)
从上述可以看出,OgnlContext实际上有一部分功能是Map。所以可以看出_values就是一个Map属性。而运行一下下面的代码就可以看到:
//在request域中设置一个参数
ServletActionContext.getRequest().setAttribute("req_username","req_username");
//在request域中设置一个参数
ServletActionContext.getRequest().setAttribute("req_psw", "req_psw");
//在session域中设置一个参数
ActionContext.getContext().getSession().put("session_username", "session_username");
//在session域中设置一个参数
ActionContext.getContext().getSession().put("session_psw", "session_psw");

在_values的map中:
主要存储的地方是
        application     在 ApplicationMap
        request 在       RequestMap
        action  在       自己写的action
        session 在       SessionMap
_root(第二部分)

这里写图片描述

从图中可以看出_root实际上CompoundRoot类,从类的组织结构图中可以看出,这个类实际上是继承了ArrayList类,也就是说这个类具有集合的功能。而且在默认情况下,集合类的第一个为ValueStackAction,也就是我们自己写的action。

ognl表达式(显示操作标签)

使用方法:
 1、引入标签库
    <%@ taglib prefix="s" uri="/struts-tags" %>
        标签库的位置在struts2-core-2.3.1.2.jar包中的META-INF/struts-tags.tld
   2、s:debug
            是一个超级链接,当点击该超级链接的时候,valueStack中的内容显示出来了
   3、访问valueStack中的数据
       1、如果要访问map栈中的数据,加"#"
       2、如果要访问对象栈中的数据,直接访问属性即可
   4、s:property标签
                     说明:
          1、是一个输出标签
          2、如果不写value属性,输出栈顶的元素
          3、如果执行了下面的代码
                Person person = new Person();
                person.setPid(1L);
                person.setName("王二麻子");
                //把person对象放入到了栈顶
                ActionContext.getContext().getValueStack().push(person);
                       把对象放入到栈顶,其属性会直接暴漏出来,在页面上可以直接访问其属性
                <s:property value="name"/>
                    其页面上的对象栈中的属性的名称来自于方法
          4、如果一个对象在对象栈中,那么该对象如果有set或者get方法,例如:
               getAaa(){
                 return "xxx";
               }
                那么aaa会作为属性的名称,xxx会作为属性的值保存在对象栈中
          5、如果对象栈中出现相同的属性,则会从上向下找,直到找到就停止了
          6、如果把一个对象放入到request域中
               ServletActionContext.getRequest().setAttribute("person", person);
                页面上可以
                <s:property value="#request.person.name"/>
                <s:property value="#request.person.getName()"/>
          7、如果把一个对象放入到各种域中
                ServletActionContext.getServletContext().setAttribute("a_app", "a_app");
                在页面上可以利用
                   <s:property value="#attr.a_app"/>从各种域中查找相应的key值
          8、可以利用parameters输出表单中的内容
                <s:property value="#parameters.a[0]"/>
   5、s:iterator标签
        1、当value属性不写,则默认迭代栈顶的元素
        2、value属性指向了要迭代的集合List,Set,Map,[]
        3、当前正在迭代的元素在栈顶
        4、var属性的值表示正在遍历的元素,该值在map栈中
        5、status属性表示正在遍历的那一行的状态
            int getCount() 返回当前迭代的元素个数
            int getIndex() 返回当前迭代元素的索引
            boolean isEven() 返回当前迭代元素的索引是否是偶数
            boolean isOdd()  返回当前迭代元素的索引是否是奇数
            boolean isFirst()  返回当前迭代元素是否为第一个元素
            boolean isLast()  返回当前迭代元素是否为最后一个元素
        6、使行变色

ognl表达式(UI标签)

使用方法
1、在页面上可以写struts2的标签,但是浏览器是不识别struts2标签的
2、当在页面上写完struts2标签的时候,struts2内核会对标签进行翻译成html标签,在翻译的过程中会多增加很多内容
            <s:form action="">
                <s:textfield name="username" value="111"></s:textfield>
            </s:form>

            翻译成html:
            <table class="wwFormTable">
                <tbody>
                    <tr>
                        <td class="tdLabel"></td>
                    <td>
                        <input id="_username" type="text" value="111" name="username">
                    </td>
                    </tr>
                </tbody>
            </table>
3、修改方案:
          在服务器启动的时候,struts2内部会去org/apache/struts2下面加载一个properties文件:default.properties文件
          一些参数的说明:
          struts.i18n.encoding=UTF-8  默认的编码
          struts.action.extension=action,,  默认的扩展名
          struts.devMode = false   开发模式  
            默认值为false   改了配置文件以后必须重新启动
            值为true       改了配置文件以后,struts2内部会自动检查,重新加载
          struts.ui.theme=xhtml  ui的主题 
                可以把xhtml的值改成
4、改变default.properties文件中的配置
        在xml文件中,有一个元素为constant,为常量元素,该元素的作用就是为了改变default.properties文件中的值
          <constant name="struts.devMode" value="true"/>    开发模式
          <constant name="struts.ui.theme" value="simple"/>  简单样式

5、两个比较重要的标签
      s:select
          value属性    指向集合的位置
          listKey   option中的value
          listValue  option标签的内容
          headerKey  第一个option的value
          headerValue  第一个option的内容
      s:checkboxlist
            属性同上
            必须有name属性
6、ui标签的好处:
     1、在页面上如果使用struts2的ui标签,不用再写过滤器进行编码的处理
     2、使用struts2的ui标签对于数据的回显示很方便的
     3、一般情况下,在页面上需要对数据进行回显,则数据放在对象栈中
            ActionContext.getContext().getValueStack().push(person1);
     4、页面上可以根据struts2标签中的name属性进行回显
           <s:textfield name="name"></s:textfield>
     5、如果把数据放入到了map栈中,则页面上必须根据value进行回显
     6、在s:form标签的各种元素中:
           s:textfield
           s:textarea
           s:password
           ....
            如果要想用value属性进行回显,也就是说value属性内容要跟ognl表达式
                value="%{ognl表达式}"

拦截器interceptor

拦截器的目的:
    如果在一个业务逻辑方法中设计到的逻辑相当复杂,可以把这些业务分离开:
       例如:保存用户
            1、启动日志
            2、检查权限
            3、文件的上传
            4、保存用户
          如果用传统的方法做,以上4点都在同一个方法中,这样耦合性很强
目标:
          把这四方面的内容分开,完全松耦合
不用拦截器实现步骤:
1、准备页面:
        在页面中准备一个文本框,该文本框在一个表单中
2、准备action
                          在action中有一个方法:saveUser
                          在action中准备一个属性,该属性是为了获取文本框的值
                          在saveUser中做如下的工作:
                对该属性的值进行判断,如果值为"admin",输出"save user"
                                                         如果值不为"admin",输出"没有权限进行访问"
用拦截器实现的步骤:
1、准备页面
2、准备action
    public class InterceptorAction extends ActionSupport{
        public String saveUser(){
            ActionContext.getContext().put("message", "save user");
            return "privilege";
        }
    }
    说明:该action的saveUser方法和权限没有任何联系
3、创建一个拦截器
     public class PrivilegeInterceptor implements Interceptor{
        @Override
        public String intercept(ActionInvocation arg0) throws Exception {
            /**
                * 接受页面的参数进行判断
             */
            String username = ServletActionContext.getRequest().getParameter("username");
            if("admin".equals(username)){
                return arg0.invoke();
            }else{
                ActionContext.getContext().put("message", "权限不足,没有办法访问");
                return "privilege";
            }
        }
     }
  4、配置
        <interceptors>
            <!-- 
                声明一个拦截器
             -->
            <interceptor name="privilege" class="cn.itcast.sh08.struts2.interceptor.PrivilegeInterceptor"></interceptor>
            <!-- 
                声明了一个拦截器栈
             -->
            <interceptor-stack name="privilegeStack">
                <!-- 
                    引用默认的拦截器栈
                 -->
                <interceptor-ref name="defaultStack"></interceptor-ref>
                <!-- 
                    引用自己创建的拦截器
                 -->
                <interceptor-ref name="privilege"></interceptor-ref>
            </interceptor-stack>
        </interceptors>
        <default-interceptor-ref name="privilegeStack"></default-interceptor-ref>
拦截器的意义以及其参数解析
拦截器的意义在于:可以把一些和业务逻辑没有关系的代码放入到拦截器中,做到这些代码和业务逻辑的松耦合

概念:
        1、拦截器:实质上是一个类,实现了Interceptor接口的一个类
        2、拦截器栈:把很多个拦截器集中在一起就是拦截器栈
        3、struts2有一个默认的拦截器栈,该栈在struts-default.xml文件中的struts-default包中
            结构为:
                <package name="struts-default">
                    <interceptors>
                        //声明一个拦截器
                        <interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
                        //声明一个拦截器栈
                        <interceptor-stack name="defaultStack">
                            //引用上面声明的拦截器
                            <interceptor-ref name="exception"/>
                            <interceptor-ref name="alias"/>
                            <interceptor-ref name="servletConfig"/>
                            <interceptor-ref name="i18n"/>
                            <interceptor-ref name="prepare"/>
                            <interceptor-ref name="chain"/>
                            <interceptor-ref name="debugging"/>
                            <interceptor-ref name="scopedModelDriven"/>
                            <interceptor-ref name="modelDriven"/>
                            <interceptor-ref name="fileUpload"/>
                            <interceptor-ref name="checkbox"/>
                            <interceptor-ref name="multiselect"/>
                            <interceptor-ref name="staticParams"/>
                            <interceptor-ref name="actionMappingParams"/>
                            <interceptor-ref name="params">
                              <param name="excludeParams">dojo\..*,^struts\..*</param>
                            </interceptor-ref>
                            <interceptor-ref name="conversionError"/>
                            <interceptor-ref name="validation">
                                <param name="excludeMethods">input,back,cancel,browse</param>
                            </interceptor-ref>
                            <interceptor-ref name="workflow">
                                <param name="excludeMethods">input,back,cancel,browse</param>
                            </interceptor-ref>
                        </interceptor-stack>
                    </interceptors>
                    //让struts2内部执行默认的拦截器栈或者拦截器
                    <default-interceptor-ref name="defaultStack"/>
                </package>
       4、拦截器的执行顺序:
                按照拦截器栈从上到下执行,执行完拦截器以后,再执行action,例如:
                  <interceptor-stack name="privilegeStack">
                    <interceptor-ref name="defaultStack"></interceptor-ref>
                    <interceptor-ref name="privilege"></interceptor-ref>
                  </interceptor-stack>
                 先执行默认的拦截器栈,后执行privilege
                 <interceptor-stack name="privilegeStack">
                    <interceptor-ref name="privilege"></interceptor-ref>
                    <interceptor-ref name="defaultStack"></interceptor-ref>
                  </interceptor-stack>
                  先执行privilege,后执行默认的拦截器栈

属性驱动(可用但不常用)

解决的问题就是在jsp页面写一个表单,通过name就可以在action中获取jsp页面中表单的值

属性驱动:
1、目的:在action中声明一些属性,这些属性能够获取到表单中的值
2、步骤:
1、在action中声明一些属性,属性的名称和页面上name属性的名称一致
2、这些属性在action中必须有setter和getter方法
3、原理:
在浏览器提交一个url请求时,先创建一个action,并且把action放入到对象栈中,这个时候
action的属性会出现在对象栈中,然后经过一个拦截器ParametersInterceptor拦截器
做的事情:
1、获取页面上表单中的name和value的值
2、把上述的name和value的值封装成一个map
3、根据valueStack.setValue(name,value);来把页面上的值设置到对象栈的name属性中

模型驱动 (常用)

模型驱动和属性驱动是的区别
区别:模型驱动是先建立一个bean将所有的字段封装进去,而属性驱动是直接在action中写字段,然后实现get和set方法

属性驱动:
    1、创建一个javabean,javabean中的属性和页面中表单中的name属性的内容保持一致
    2、在action里实现一个接口ModelDriven<Person>
    3、在action中声明一个属性,并且创建该属性的对象
        private Person modle = new Person();
    4、在action中有一个方法:
        @Override
        public Person getModel() {
            // TODO Auto-generated method stub
            return this.modle;
        }
        该方法返回模型驱动对象

模型驱动的原理:
    模型驱动经过两个拦截器:
      1、ModelDrivenInterceptor
          1、得到action
          2、由action强制转化成ModelDriver
          3、由ModelDriver.getModel()获取模型对象
          4、把模型对象放入到栈顶
      2、ParameterInterceptor
            把form表单的数据封装到相应的对象栈中的属性中

threadlocal解析(重要)

在ActionContext类中
static ThreadLocal actionContext = new ThreadLocal();
//把context放入到当前线程中
public static void setContext(ActionContext context) {
actionContext.set(context);
}
//从threadlocal中把context提取出来
public static ActionContext getContext() {
return (ActionContext) actionContext.get();
}

这样做就不用参数的传递了,只要在同一个线程中就可以了

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值