转自http://www.cnblogs.com/kay/archive/2009/09/15/1566805.html
拦截器(interceptor)是Struts2最强大的特性之一,拦截器可以让你在Action和result被执行之前或之后进行一些处理。同时,拦截器也可以让你将通用的代码模块化并作为可重用的类。Struts2中的很多特性都是由拦截器来完成的。例如params拦截器将HTTP请求中的参数解析出来,并设置为Action的属性。servlet-config拦截器直接将HTTP请求中的HttpServletRequest对象化HttpServletResponse对象传给Action。
Struts2中内置类许多的拦截器,它们提供了许多Struts2的核心功能和可选的高级特性。这些内置的拦截器在struts-default.xml中配置。只有配置了拦截器,拦截器才可以正常的工作和运行。在struts-default.xml中拦截器的配置片段为:
<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拦截器栈的存在。
<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添加拦截器,则可以这样来做:
<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拦截器的效果。
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;
}
}
在配置文件struts.xml中配置拦截器:
<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中的过滤器是不是很相像呢?其实它们只有一个重要的区别,就是拦截器的工作是不依赖容器的,这会在进行单元测试时变得简单。