小解拦截器
可以说,“拦截器”是Struts2的重点内容。见名知义,拦截器的作用主要就是拦截东西,拦截什么呢?当然是‘action‘了,在执行‘action‘之前 拦截器会起作用,执行一些预先处理的代码,接着去执行action中相关的方法,之后,流程又会回到拦截器里面,接着去执行后续的一些操作。
在这里还要提两点:
1. Struts2拦截器是可插拔的,拦截器是AOP的一种实现.
2. 拦截器栈(Interceptor Stack)。Struts2拦截器栈就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,Struts2拦截器链中的拦截器就会按其之前定义的顺序被调用。
实现Struts2拦截器原理
Struts 2的拦截器实现相对简单。当请求到达Struts2的ServletDispatcher时,Struts 2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表(list),最后一个一个地调用列表中的拦截器。事实上,我们之所以能够如此灵活地使用拦截器,完全归功于“动态代理”的使用。动态代理是代理对象根据客户的需求做出不同的处理。对于客户来说,只要知道一个代理对象就行了。
那Struts2中,拦截器是如何通过动态代理被调用的呢?当Action请求到来的时候,会由系统的代理生成一个Action的代理对象,由这个代理对象调用Action的execute()或指定的方法,并在struts.xml中查找与该Action对应的拦截器。如果有对应的拦截器,就在Action的方法执行前(后)调用这些拦截器;如果没有对应的拦截器则执行Action的方法。其中系统对于拦截器的调用,是通过ActionInvocation来实现的。
看一张简要的图
拦截器的工作原理如上图,每一个Action请求都包装在一系列的拦截器的内部。拦截器可以在Action执行直线做相似的操作也可以在Action执行直后做回收操作。每一个Action既可以将操作转交给下面的拦截器,Action也可以直接退出操作返回客户既定的画面。
代码举例
1. 编写拦截器
(1) 实现接口com.opensymphony.xwork2.Intercepter(或继承com.opensymphony.xwork2.AbstractInterceptor)
(2) 在interceptor方法中加入如下代码:
public String intercept(ActionInvocation arg0) throws Exception { System.out.println("Before"); //在Action之前调用 String result = arg0.invoke(); //如果此拦截器之后还有拦截器,则调用下个拦截器的intercept方法 //如果之后没有了拦截器,则调用Action的execute方法 System.out.println("After"); return result; }
2.在Struts.xml中配置拦截器
(1) 在struts.xml中声明拦截器和拦截器Stack,拦截器Stack可以包括多个拦截器和其他Stack。
<interceptors> <!-- 拦截器 --> <interceptor name="MyInterceptor" class="com.test.interceptor.MyInterceptor"></interceptor> <!-- 拦截器Stack --> <interceptor-stack name="validationWorkflowStack"> <interceptor-ref name="basicStack"/> <interceptor-ref name="validation"/> <interceptor-ref name="workflow"/> </interceptor-stack> </interceptors>
(2) 将拦截器配置到单个Action中,只拦截此Action中的execute方法。
<action name="register" class="com.test.action.RegisterAction" method="test"> <result name="success">/success.jsp</result> <result name="input">/register2.jsp</result> <interceptor-ref name="MyInterceptor"></interceptor-ref> </action>
(3) 将拦截器配置到所有Action中,拦截所有Action中的execute方法。
<default-interceptor-ref name="MyInterceptor"></default-interceptor-ref>
对已经单独配置了拦截器的Action不起作用
3.拦截Action中指定的方法
(1) 继承com.opensymphony.xwork2.interceptor.MethodFilterInterceptor。
(2) 因为是针对某个Action的方法,所以只能配置在Action内部
<action name="register" class="com.test.action.RegisterAction" method="test"> <result name="success">/success.jsp</result> <result name="input">/register2.jsp</result> <interceptor-ref name="MyInterceptor"> <param name="includeMethod">test,execute</param> <!-- 拦截text和execute方法,方法间用逗号分隔 --> <param name="excludeMethod">myfun</param> <!-- 不拦截myfun方法 --> </interceptor-ref> </action>
4. struts2拦截器的interceptor方法中,参数ActionInvocation可用来获取页面用户输入的信息。
public String intercept(ActionInvocation arg0) throws Exception { Map map = arg0.getInvocationContext().getSession(); if(map.get("user") == null) { return Action.LOGIN; } else { return arg0.invoke(); } }
总之
Struts2拦截器跟Servlet过滤器或JDK代理类是一样的。拦截器允许横切功能分开实现的动作,以及框架。