Struts2拦截器

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

image

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; 
	}
}

① 获得Action执行的开始时间。

② 将控制权交给下一个拦截器,如果该拦截器是最后一个拦截器,则调用Action的execute方法。

③ 获得Action执行的结束时间。

 

在配置文件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中的过滤器是不是很相像呢?其实它们只有一个重要的区别,就是拦截器的工作是不依赖容器的,这会在进行单元测试时变得简单。

posted @ 2009-09-15 10:42  樊凯  阅读(8511)  评论(0编辑  收藏  举报