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,如需转载请自行联系原作者