在开始讲解之前,先分享一篇不错的关于Struts2拦截器的讲解博客:Struts2拦截器详解
一、拦截器的概述
拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问前,进行拦截,然后在之前或在之后加入某些操作。拦截是AOP的一种实现策略。现实开发中有很多的应用场景,比如:用户登录检查、登录日志记录以及权限检查等等。
Struts2的执行流程如下图:
拦截器是一种可以在让用户在Action执行之前和Result执行之后进行一些功能处理的机制。 而且拦截器在action执行之前和result执行之后的顺序是相反的,即:Interceptor1—Interceptor2—Interceptor3—Action—Result–Interceptor3—-Interceptor2—-Interceptor1。
struts2里面封装的功能都是在拦截器里面。有很多拦截器,但不是每次这些拦截器都执行,每次执行默认的拦截器。
Struts2里面默认的拦截器位置:struts2-core-2.xxxx.jar—->struts-default.xml,在这里面配置了很多的拦截器,但是只执行默认配置的那些拦截器。
拦截器链,又叫拦截器栈,就是将拦截器按照一定的顺序联
二、拦截器的原理
大部分时候,拦截器方法都是通过代理的方式来调用的。当请求到达Struts2的ServletDiapatcher时,Struts2会查找配置文件,并根据其配置实例化相应的拦截器对象,然后串成一个列表,最后一个一个地调用列表中的拦截器。另外,Struts2中的拦截器都是可插拔的。
三、自定义拦截器
方法一:实现Interceptor接口
com.opensymphony.xwork2.interceptor.Interceptor接口的代码如下:
public interface Interceptor extends Serializable{
void init();
void destroy();
String intercept(ActionInvocation invocation)throws Exception;
}
可以看出来,该接口提供了三个方法,具体介绍如下:
(1):void init():该方法在拦截器被创建后立即被调用,它在拦截器的生命周期内只被调用一次,可以在该方法中对相关的资源进行必要的初始化;
(2):void destroy():该方法与init()方法相对应,在拦截器实例被销毁之前,将调用该方法来释放和拦截器有关的资源。它在拦截器的生命周期内,也只被调用了一次。
(3):String intercept(ActionInvocation invocation)throws Exception: 该方法是拦截器的核心方法,用来添加真正执行拦截工作的代码,实现具体的拦截操作。它返回一个字符串作为逻辑视图,系统根据返回的字符串跳转到对应的视图资源。每拦截一个动作请求,该方法就会被调用一次。该方法的ActionInvocation参数包含了被拦截的Action的引用,可以通过该参数的invoke()方法,将控制权转给下一个拦截器或者转给Action的execute()方法。
方法二:继承AbstractInterceptor类(常用,更简单一点)
除了实现Interceptor接口外,实际开发中更常用的是继承抽象拦截器类:AbstractInterceptor。该类实现了Interceptor接口,并且提供了init()和destroy()方法的空实现。使用时可以直接继承该抽象类,而不用实现那些不必要的方法。
public abstract class AbstractInterceptor implements Interceptor{
public void init(){}
public void destroy(){}
public abstract String intercept(ActionInvocation invocation) throws Exception;
}
四、拦截器的配置
拦截器的配置是在struts.xml文件中完成的,它通过<interceptor>标签开头。
1、拦截器的配置
<interceptor name="interceptorName" class="interceptorClass">
<param name="paramName">paramValue</param>
</interceptor>
name属性用来指定拦截器的名称,class属性用来指定拦截器的实现类。有时定义拦截器需要传入参数,这时需要使用<param>标签,其中name属性用来指定参数的名称,paramValue表示参数的值。
2、拦截器栈的配置
在实际开发中,经常需要在Action执行前同时执行多个拦截器动作,如:用户登录检查、登录日志记录以及权限检查等,这时,可以把多个拦截器组成一个拦截器栈。在使用时,可以将栈内的多个拦截器当成一个整体来引用。当拦截器栈被附加到一个Action上时,在执行Action之前必须先执行拦截器栈中的每一个拦截器。
定义拦截器栈使用<interceptors>元素和<interceptor-stack>子元素,当配置多个拦截器时,需要使用<interceptor-ref>元素来指定多个拦截器,配置语法如下:
<interceptors>
<interceptor-stack name="interceptorStackName">
<interceptor-ref name="interceptorName1"/>
<interceptor-ref name="interceptorName1"/>
...
</interceptor-stack>
</interceptors>
在上述语法中,interceptorStackName值表示配置的拦截器栈的名称,interceptorName表示拦截器的名称。另外,在一个拦截器栈中还可以包含其他拦截器栈,配置语法如下:
<package name="default" extends="struts-default" namespace="/">
<!-- 声明拦截器 -->
<interceptors>
<interceptor name="interceptor1" class="interceptorClass">
<interceptor name="interceptor2" class="interceptorClass">
<!-- 定义一个拦截器栈myStack,该拦截器栈中包含两个拦截器和一个拦截器栈 -->
<interceptor-stack name="myStack">
<!-- defaultStack这个内置的拦截器栈是必须要引入的 -->
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="interceptor1"/>
<interceptor-ref name="interceptor2"/>
</interceptor-stack>
</interceptors>
</package>