struts2的工作流程

用户请求 
       ——>    StrutsPrepareAndExecuteFilter 
       ——>    Interceptor
       ——>    Action
       ——>    Result
       ——> Jsp/html
       ——> 响应

Struts2拦截器

拦截器(interceptor)是Struts2最强大的特性之一,拦截器可以让你在Action和result被执行之前或之后进行一些处理。同时,拦截器也可以让你将通用的代码模块化并作为可重用的类。Struts2中的很多特性都是由拦截器来完成的。例如params拦截器将HTTP请求中的参数解析出来,并设置为Action的属性。servlet-config拦截器直接将HTTP请求中的HttpServletRequest对象化HttpServletResponse对象传给Action。

image

Struts2中内置类许多的拦截器,它们提供了许多Struts2的核心功能和可选的高级特性。这些内置的拦截器在struts-default.xml中配置。只有配置了拦截器,拦截器才可以正常的工作和运行。在struts-default.xml中拦截器的配置片段为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<package name="struts-default" abstract="true">  ①
    <interceptors>
        <interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>  ②
        <interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
        //…其他拦截器配置
        <interceptor-stack name="defaultStack">  ③
              <interceptor-ref name="exception"/>
              <interceptor-ref name="alias"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="i18n"/>
                //…其他拦截器的引用
          </interceptor-stack>  
    </interceptors>
    <default-interceptor-ref name="defaultStack"/>  ④
</package>
① package将属性abstract设置为true,代表此package为一个抽象的package。抽象package和非抽象package的区别在于抽象的package中不能配置action。
② name属性指定拦截器的名字,class属性指定拦截器的完全限定名。
③ 多个拦截器可以组成拦截器栈。name属性为拦截器栈的名字。
④ 指定当前package的默认拦截器(栈)。当前指定的默认拦截器栈为defaultStack,该拦截器栈是Struts2运行的一个基本拦截器栈,一般我们不用在自己配置它,因为在大多数情况下,我们自定义的package是继承自struts-default这个package的。


我们以Struts2内置的timer拦截器为例,来学习如何在我们的应用中添加其他的拦截器。timer拦截器可以统计action执行的时间。我们可以修改package中默认的拦截器,那么将替换掉struts-default中配置的defaultStack拦截器栈,导致Struts2无法正常运行,比如无法获取表单的值等等。那么该如何正确的配置呢?可以在添加新的拦截器的基础上加入defaultStack拦截器栈,这样就可以保证defaultStack拦截器栈的存在。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<package name="myStruts" extends="struts-default">
    <interceptors>
        <interceptor-stack name="myInterceptor">  ①
            <interceptor-ref name="timer"/>
            <interceptor-ref name="defaultStack"/>
        </interceptor-stack>
    </interceptors>
    <default-interceptor-ref name="myInterceptor"/>  ②
    <action name="userAction"
        class="com.kay.action.UserAction">
        <result name="success">suc.jsp</result>
        <result name="input">index.jsp</result>
        <result name="error">err.jsp</result>
    </action>
</package>
① 添加一个自定义的拦截器栈,并在其中包含time拦截器和defaultStack拦截器栈。
② 设置当前的package的默认拦截器栈为自定义的拦截器栈。

修改package的默认拦截器会应用的package中的所有Action中,如果只想给其中一个Action添加拦截器,则可以这样来做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<package name="myStruts" extends="struts-default">
    <interceptors>
        <interceptor-stack name="myInterceptor">
            <interceptor-ref name="timer"/>
            <interceptor-ref name="defaultStack"/>
        </interceptor-stack>
    </interceptors>
    <action name="userAction"
        class="com.kay.action.UserAction">
        <interceptor-ref name="myInterceptor"/>  ①
        <result name="success">suc.jsp</result>
        <result name="input">index.jsp</result>
        <result name="error">err.jsp</result>
    </action>
</package>
                                                                
① 给UserAction添加拦截器。

如果要创建自己的拦截器,只需要实现Interceptor接口,该接口中定义了以下三个方法:

void init():

在拦截器初始化之后,在执行拦截之前,系统调用该方法。对于一个拦截器而言,init方法只会被调用一次。

String intercept(ActionInvocation invocation) throws Exception:

该方法是拦截器的拦截方法,返回一个字符串,系统将会跳转到该字符串对应的视图资源。该方法的ActionInvocation参数包含了被拦截的Action的引用,可以通过该对象的invoke方法,将控制权转给下一个拦截器或者转给Action的execute方法。

void destroy():

该方法与init方法对应,在拦截器示例被销毁之前,系统将会调用该方法。

除了Interceptor接口外,Struts2中还提供了一个AbStractInterceptor类,该类提供了一个init和destroy方法的空实现。如果不需要就不用重写这两个方法,可见继承自AbstractInterceptor类可以让我们构建拦截器时变得简单。

下面我们构建自己的拦截器,实现timer拦截器的效果。

1
2
3
4
5
6
7
8
9
10
11
12
public class MyInterceptor extends AbstractInterceptor {
    public String intercept(ActionInvocation invocation) throws Exception {
        long startTime = System.currentTimeMillis();  ①
        String result = invocation.invoke();  ②
        long endTime = System.currentTimeMillis();  ③
        System.out.println("Action执行共需要" + (endTime - startTime) + "毫秒");
        return result;
    }
}
① 获得Action执行的开始时间。
② 将控制权交给下一个拦截器,如果该拦截器是最后一个拦截器,则调用Action的execute方法。
③ 获得Action执行的结束时间。

在配置文件struts.xml中配置拦截器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<package name="myStruts" extends="struts-default">
    <interceptors>
        <interceptor name="myTimer" class="com.kay.interceptor.MyInterceptor"></interceptor>  ①
        <interceptor-stack name="myInterceptor">
            <interceptor-ref name="myTimer"/>  ②
            <interceptor-ref name="defaultStack"/>
        </interceptor-stack>
    </interceptors>
    <action name="userAction"
        class="com.kay.action.UserAction">
        <interceptor-ref name="myInterceptor"/>
        <result name="success">suc.jsp</result>
        <result name="input">index.jsp</result>
        <result name="error">err.jsp</result>
    </action>
</package>
                                                     
① 定义一个新的拦截器,name属性为拦截器的名字,class属性为拦截器的完全限定名。
② 在拦截器栈中加入新的拦截器。

从拦截器的运行原理上和我们以前学习的Servlet中的过滤器是不是很相像呢?其实它们只有一个重要的区别,就是拦截器的工作是不依赖容器的,这会在进行单元测试时变得简单。



struts2.0中struts.xml配置文件详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd" >
<struts>
    <!-- include节点是struts2中组件化的方式 可以将每个功能模块独立到一个xml配置文件中 然后用include节点引用 -->
    <include file="struts-default.xml"></include>
                                              
                                              
    <!-- package提供了将多个Action组织为一个模块的方式
        package的名字必须是唯一的 package可以扩展 当一个package扩展自
        另一个package时该package会在本身配置的基础上加入扩展的package
        的配置 父package必须在子package前配置
        name:package名称
        extends:继承的父package名称
        abstract:设置package的属性为抽象的 抽象的package不能定义action 值true:false
        namespace:定义package命名空间 该命名空间影响到url的地址,例如此命名空间为/test那么访问是的地址为http://localhost:8080/struts2/test/XX.action
     -->
    <package name="com.kay.struts2" extends="struts-default" namespace="/test">
        <interceptors>
            <!-- 定义拦截器
                name:拦截器名称
                class:拦截器类路径
             -->
            <interceptor name="timer" class="com.kay.timer"></interceptor>
            <interceptor name="logger" class="com.kay.logger"></interceptor>
            <!-- 定义拦截器栈 -->
            <interceptor-stack name="mystack">
                <interceptor-ref name="timer"></interceptor-ref>
                <interceptor-ref name="logger"></interceptor-ref>
            </interceptor-stack>
        </interceptors>
                                                  
        <!-- 定义默认的拦截器 每个Action都会自动引用
         如果Action中引用了其它的拦截器 默认的拦截器将无效 -->
        <default-interceptor-ref name="mystack"></default-interceptor-ref>
                                                  
                                                  
        <!-- 全局results配置 -->
        <global-results>
            <result name="input">/error.jsp</result>
        </global-results>
                                                  
        <!-- Action配置 一个Action可以被多次映射(只要action配置中的name不同)
             name:action名称
             class: 对应的类的路径
             method: 调用Action中的方法名
        -->
        <action name="hello" class="com.kay.struts2.Action.LoginAction">
            <!-- 引用拦截器
                name:拦截器名称或拦截器栈名称
             -->
            <interceptor-ref name="timer"></interceptor-ref>
                                                  
            <!-- 节点配置
                name : result名称 和Action中返回的值相同
                type : result类型 不写则选用superpackage的type struts-default.xml中的默认为dispatcher
             -->
         <result name="success" type="dispatcher">/talk.jsp</result>
         <!-- 参数设置
             name:对应Action中的get/set方法
         -->
         <param name="url">http://www.sina.com</param>
        </action>
    </package>
</struts>

本文转自lixiyu 51CTO博客,原文链接:http://blog.51cto.com/lixiyu/1355147,如需转载请自行联系原作者