在上一篇中介绍了 Struts2 拦截器的原理,在这一篇中我们将学习一下如何编写自己的拦截器。 实现一个拦截器非常简单。实际上,一个拦截器就是一个普通的类,只是这个类必须实现 com.opensymphony.xwork2.interceptor.Interceptor 接口。 Interceptor 接口有如下三个方法:
public interface Interceptor extends Serializable { void destroy(); void init(); String intercept(ActionInvocation invocation) throws Exception; }
其中init
和destroy
方法只在拦截器加载和释放(都由Struts2
自身处理)时执行一次。而intercept
方法在每次访问动作时都会被调用。Struts2
在调用拦截器时,每个拦截器类只有一个对象实例,而所有引用这个拦截器的动作都共享这一个拦截器类的对象实例,因此,在实现Interceptor
接口的类中如果使用类变量,要注意同步问题。 下面我们来实现一个简单的拦截器,这个拦截器通过请求参数action
指定一个拦截器类中的方法,并调用这个方法(我们可以使用这个拦截器对某一特定的动作进行预处理)。如果方法不存在,或是action
参数不存在,则继续执行下面的代码。如下面的URL
: http://localhost:8080/struts2/test/interceptor.action?action=test
访问上面的url
后,拦截器会就会调用拦截器中的test
方法,如果这个方法不存在,则调用invocation.invoke
方法,invoke
方法和Servlet
过滤器中调用FilterChain.doFilter
方法类似,如果在当前拦截器后面还有其他的拦截器,则invoke
方法就是调用后面拦截器的intercept
方法,否则,invoke
会调用Action
类的execute
方法(或其他的执行方法)。 下面我们先来实现一个拦截器的父类ActionInterceptor
。这个类主要实现了根据action
参数值来调用方法的功能,代码如下: package interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; import javax.servlet.http. * ; import org.apache.struts2. * ; public class ActionInterceptor implements Interceptor { protected final String INVOKE = " ##invoke " ; public void destroy() { System.out.println( " destroy " ); } public void init() { System.out.println( " init " ); } public String intercept(ActionInvocation invocation) throws Exception { HttpServletRequest request = ServletActionContext.getRequest(); String action = request.getParameter( " action " ); System.out.println( this .hashCode()); if (action != null ) { try { java.lang.reflect.Method method = this .getClass().getMethod(action); String result = (String)method.invoke( this ); if (result != null ) { if ( ! result.equals(INVOKE)) return result; } else return null ; } catch (Exception e) { } } return invocation.invoke(); } }
从上面代码中的intercept
方法可以看出,在调用action
所指定的方法后,来判断返回值。可能发生的情况有三种: 1.
返回值为null
,执行return null
。 2.
返回值为INVOKE
,执行 return invockation.invoke()
。 3.
其他情况,执行return result
。 result
表示指定方法的返回值,如上面代码所示。 在实现完上面的拦截器父类后,任何继承于 ActionInterceptor 类的拦截器都可以自动根据 action 的参数值调用自身的相应方法。下面我们来实现一个拥有两个动作方法 test 和 print 的拦截器类。代码如下:
package interceptor; import javax.servlet.http.HttpServletResponse; import org.apache.struts2.ServletActionContext; public class MultiMethodInterceptor extends ActionInterceptor { public String test() throws Exception { HttpServletResponse response = ServletActionContext.getResponse(); response.getWriter().println( " invoke test " ); return this .INVOKE; } public String print() throws Exception { HttpServletResponse response = ServletActionContext.getResponse(); response.getWriter().println( " invoke print " ); return null ; } }
test
方法返回了INVOKE
,因此,在执行完这个方法后,Struts2
会接着调用其他拦截器的intercept
方法或Action
类的execute
方法。而print
方法在执行完后,只是返回了null
,而不再调用其他的方法了,也就是访问如下的url
时,动作的execute
方法将不会执行: http://localhost:8080/struts2/test/ddd.action?action=print
下面我们来实现一个 Action 类,代码如下:
package action; import org.apache.struts2. * ; import com.opensymphony.xwork2.ActionSupport; public class InterceptorAction extends ActionSupport { public String abcd() throws Exception { ServletActionContext.getResponse().getWriter() .println( " invoke abcd " ); return null ; } } 在这个Action
类中,只有一个abcd
方法,实际上,这个方法相当于execute
方法,在下面会设置动作的method
属性为abcd
。下面我们来在struts.xml
中定义拦截器类和动作,代码如下: <? xml version="1.0" encoding="UTF-8" ?> <! DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd" > < struts > < package name ="demo" extends ="struts-default" namespace ="/test" > < interceptors > < interceptor name ="method" class ="interceptor.MultiMethodInterceptor" /> < interceptor-stack name ="methodStack" > < interceptor-ref name ="method" /> < interceptor-ref name ="defaultStack" /> </ interceptor-stack > </ interceptors > < action name ="interceptor" class ="action.InterceptorAction" method ="abcd" > < interceptor-ref name ="methodStack" /> </ action > </ package > </ struts > 在配置上面的methodStack
拦截器时要注意,最好在后面引用defaultStack
,否则很多通过拦截器提供的功能将失去。 OK
,现在访问如下的URL
: http://localhost:8080/struts2/test/ddd.action?action=test
在浏览器中将会出现如下的字符串: invoke test
而如果访问http://localhost:8080/struts2/test/ddd.action?action=print
,将会只出现如下的字符串: invoke print
大家可以看出,访问这个url
时并没有调用abcd
方法。如果随便指定的action
值的话,则只调用abcd
方法,如访问http://localhost:8080/struts2/test/ddd.action?action=aaa
,就只会输出invoke abcd
。 二、拦截器的参数 我们在使用很多Struts2
内置的拦截器时会发现有很多拦截器都带参数,当然。我们自己做的拦截器也可以加上同样的参数。有两个参数比较常用,这两个参数是includeMethods
和excludeMethods
,其中includeMethods
指定了拦截器要调用的Action
类的执行方法(默认是execute
),也就是说,只有在includeMethods
中指定的方法才会被Struts2
调用,而excludeMethods
恰恰相反,在这个参数中指定的执行方法不会被Struts2
调用。如果有多个方法,中间用逗号(,)
分隔。在Struts2
中提供了一个抽象类来处理这两个参数。这个类如下: com.opensymphony.xwork2.interceptor.MethodFilterInterceptor
如有继承于这个类的拦截器类都会自动处理 includeMethods 和 excludeMethods 参数,如下面的拦截器类所示:
package interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor. * ; public class MyFilterInterceptor extends MethodFilterInterceptor { private String name; public String getName() { return name; } public void setName(String name) { this .name = name; } @Override protected String doIntercept(ActionInvocation invocation) throws Exception { System.out.println( " doIntercept " ); System.out.println(name); return invocation.invoke(); } } MethodFilterInterceptor 的子类需要实现 doIntercept 方法(相当于 Interceptor 的 intercept 方法),如上面代码所示。在上面的代码中还有一个 name 属性,是为了读取拦截器的 name 属性而设置的,如下面的配置代码所示:
<? xml version="1.0" encoding="UTF-8" ?> <! DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd" > < struts > < package name ="demo" extends ="struts-default" namespace ="/test" > < interceptors > < interceptor name ="method" class ="interceptor.MultiMethodInterceptor" /> < interceptor name ="filter" class ="interceptor.MyFilterInterceptor" > < param name ="includeMethods" > abcd </ param > < param name ="name" > 中国 </ param > </ interceptor > < interceptor-stack name ="methodStack" > < interceptor-ref name ="method" /> < interceptor-ref name ="filter" /> < interceptor-ref name ="defaultStack" /> </ interceptor-stack > </ interceptors > < action name ="interceptor" class ="action.InterceptorAction" method ="abcd" > < interceptor-ref name ="methodStack" /> </ action > </ package > </ struts >
再次访问 http://localhost:8080/struts2/test/ddd.action?action=test, Struts2
就会调用MyFilterInterceptor
的doIntercept
方法来输出name
属性值。如果将上面的includeMethods
参数值中的abcd
去掉,则Action
类的abcd
方法不会被执行。
本文转自 androidguy 51CTO博客,原文链接:http://blog.51cto.com/androidguy/216451,如需转载请自行联系原作者