首页 > 技术文章 > 信步漫谈之Struts2—拦截器

alfredinchange 2016-04-13 21:35 原文

主要介绍Struts2的拦截器,结合实例说明。

代码结构:

image

关键代码:

LoginCheckInterceptor.java
MapParametersInterceptor.java
TimeInterceptor.java
LoginAction.java
RegistAction.java
UserAction.java
User.java
main.jsp
login.jsp
regist.jsp
struts.xml

实例程序中定义了三个拦截器:TimeInterceptor、MapParametersInterceptor、LoginCheckInterceptor,分别是时间捕捉、Map传值、登陆验证功能。

TimeInterceptor实现了Interceptor接口,该接口是Struts2中拦截器的祖先,所有拦截器的最终实现。该接口有三个方法,分别是init、destory、intercept,分别是初始化时执行、销毁时执行、以及具体的拦截操作。同时,Struts2中还定义了一个抽象类AbstractInterceptor,该类实现了Interceptor接口,并空实现了init和destory方法,所以我们也可以直接通过继承AbstractInterceptor类来自定义拦截器(好处是不用实现init和destory方法,和实现Interceptor接口的区别也就在此,实际上这两个方法一般不会去使用)

LoginCheckInterceptor继承自抽象类MethodFilterInterceptor,MethodFilterInterceptor类在AbstractInterceptor的基础上添加了方法过滤,所谓的方法过滤就是允许我们指定哪些action方法要进行拦截处理,哪些action方法不进行action拦截处理,分别定义在excludeMethods(不拦截)和includeMethods(要拦截)中。以下是相关的源码,可以看到MethodFilterInterceptor在intercept实现里添加了一层判断applyInterceptor,用于判断是否执行拦截。也因此继承自MethodFilterInterceptor的子类一般不去实现intercept方法,而是实现MethodFilterInterceptor提供的doIntercept方法(应为如果不实现doIntercept而直接实现intercept,那就等于没继承MethodFilterInterceptor)

MethodFilterInterceptor.java
MethodFilterInterceptorUtil.java

MapParametersInterceptor继承自ParametersInterceptor类,ParametersInterceptor主要功能是实现参数过滤处理,他继承自MethodFilterInterceptor类,可以定义拦截判断参数名长度,参数格式。。。,我们通过继承ParametersInterceptor实现对参数的操作,MapParametersInterceptor重载了setParameters方法,实现的功能是将不是对象的参数(例如:user.username)存放至map中(例如:username->map.username),从而在传递非对象参数时不用在Action中定义大量的属性,而是只需要定义一个map,所有的传递参数都可以从map中获取。

拦截器最关键的方法就是intercept或doIntercept,这是实现具体拦截操作的位置,该方法一个类型为ActionInvocation的参数,通过这个参数我们可以获取到ActionContext对象、调用的Action类名、调用的Action方法等等,方便我们在拦截器中对被拦截Action的判断以及操作。

//获取拦截Action类名
Class<?> cls = invocation.getAction().getClass();
//获取拦截Action方法名
String method = invocation.getProxy().getMethod();
//获取ActionContext
ActionContext actionContext = invocation.getInvocationContext();

拦截器在struts.xml中的定义

拦截器定义在interceptors标签中,定义拦截器名称和拦截器类:

<interceptor name="TimeInterceptor" class="com.alfred.interceptor.TimeInterceptor" />

拦截器栈定义在interceptors标签中,栈内包含有一系列的拦截器引用,之后加载拦截器栈就可以一次性加载该栈内的所有拦截器:

<interceptor-stack name="myDefaultStack">
    <interceptor-ref name="TimeInterceptor"></interceptor-ref>
    <interceptor-ref name="MapParametersInterceptor"></interceptor-ref>
    <!-- 判断是否已登录 -->
    <interceptor-ref name="LoginCheckInterceptor">
        <!-- 允许执行的方法 如下只有execute这个方法允许调用该拦截器
        <param name="includeMethods">execute</param> -->
        <!-- 不允许执行的方法 如果有和includeMethods相同的,以includeMethods为主
        <param name="excludeMethods">loginAction,registAction</param> -->
    </interceptor-ref>
</interceptor-stack>

默认拦截器定义在package下,所谓默认拦截器,就是action在没有加载拦截器的情况下,默认加载的拦截器,通过查看struts-default.xml配置,我们可以看到struts为我们定义的默认拦截器是defaultStack,默认拦截器栈。

<interceptor-stack name="defaultStack">
    <interceptor-ref name="exception"/>
    <interceptor-ref name="alias"/>
    <interceptor-ref name="servletConfig"/>
    <interceptor-ref name="i18n"/>
    <interceptor-ref name="prepare"/>
    <interceptor-ref name="chain"/>
    <interceptor-ref name="scopedModelDriven"/>
    <interceptor-ref name="modelDriven"/>
    <interceptor-ref name="fileUpload"/>
    <interceptor-ref name="checkbox"/>
    <interceptor-ref name="datetime"/>
    <interceptor-ref name="multiselect"/>
    <interceptor-ref name="staticParams"/>
    <interceptor-ref name="actionMappingParams"/>
    <interceptor-ref name="params"/>
    <interceptor-ref name="conversionError"/>
    <interceptor-ref name="validation">
        <param name="excludeMethods">input,back,cancel,browse</param>
    </interceptor-ref>
    <interceptor-ref name="workflow">
        <param name="excludeMethods">input,back,cancel,browse</param>
    </interceptor-ref>
    <interceptor-ref name="debugging"/>
    <interceptor-ref name="deprecation"/>
</interceptor-stack>

<default-interceptor-ref name="defaultStack"/>

可以看到defaultStack中引用了大量的拦截器,需要提到的一点就是,如果我们action中引用了一个拦截器,那么就不会再加载默认拦截器了,所以如果想要在action中引用拦截器后仍旧可以使用默认拦截器中的拦截,需在手动加上默认拦截器的引用。

另外,无论是拦截器的引用还是拦截器中都可以加入配置参数,例如:includeMethods、excludeMethods等等,具体参数可以查看API或者看对应拦截器类的属性参数。

推荐阅读