Struts 2的拦截器
1. 拦截器的意义
- 避免重复代码调用
DRY规则即Don’t Reapeat Yourself,即不重复 编写你的代码,Struts 2中的拦截器符合DRY规则。从代码角度来看,拦截器本质就是一个JAVA类,这个类的某些方法较特殊,框架执行目标方法调用之前首先执行拦截器中的这些特殊方法。使用了拦截器可避免在代码中手工调用这些方法。
- 实现高层次的代码解耦
目标代码无需手动调用目标方法,而是由框架完成,从而将这种调用代码层次上升到更高层次,提供更高层次的解耦。
2. Struts 2内建拦截器
Strus2框架内建了大量的拦截器完成了框架几乎70%的工作,比如,params拦截器将HTTP请求中的参数解析出来,设置成Action的属性;servlet-config拦截器直接将HTTP请求中的HttpServletRequest实例和HttpServletResponse实例传给Action;fileUpload拦截器负责解析请求参数中的文件域,并将一个文件域设置成Action的3个属性...
由于默认的struts拦截器栈中定义了许多框架的常用操作,且若Action中使用了自定义拦截器,struts-default包中定义的defaultStack将不起作用,从而无法完成HTTP参数映射到Action各属性的过程,因此大部分情况下,为某个Action指定了相应的拦截器后,组合使用多个拦截器/拦截器栈,或者自定义一个拦截器栈,其中包含对defaultStack的引用。
3.拦截器的实现原理
定义接口
public interface Dog { public void info(); public void run(); }
定义接口实现类
public class DogImpl implements Dog { public void info() { ... } public void run() { ... } }
系统拦截器类
public class DogIntercepter { public void method1(){} public void method2(){} }
上面只是些普通的JAVA类,实现拦截器功能关键是下面的代理类
public class ProxyHandler implemts InvocationHandler { private Object target;//需被代理的目标对象 //创建拦截器实例 DogIntercepter di = new DogIntercepter(); //执行代理的目标方法时,该Invoke方法会被自动调用 public Object invoke(Object proxy, Method method, Object[] args) { Object result = null; if(method.getName().equals("info"){ di.methord1(); result = method.invoke(tart,args); di.method2(); } else { result = methos.invoke(target,args); } return result; } public void setTarget(Object o){ this.target=o; } }
代理工厂类
public class MYProxyFactory{ public static Object getProxy(Object object){ ProxyHandler handler = new ProxyHandler(); handler.setTarget(object); return Proxy.newProxyInstance(Dogimpl.class.getClassLoader(), object.getClass().getInterfaces(),handler); } }
主程序
public class Test{ public static void main(String[] args){ Dog targetObject = new DogImpl(); Dog dog = null; //以目标对象创建代理 Object proxy = MyProxyFactory.getProxy(targetObject); if(proxy instance of Dog) { dog=(Dog)proxy; } dog.info(); dog.run(); } }
上例通过JDK动态代理,在执行目标方法之前调用拦截器方法一,在执行目标方法之后调用拦截器方法二。
4. 拦截器及拦截器栈的配置
- 在Struts.xml中配置拦截器
<interceptor name="name" class="class"/>
还可以指定拦截器参数
<interceptor name="name" class="class">
<param name="param name">…</param>
</interceptor>
- 在Struts.xml中配置拦截器栈
拦截器栈是由多个拦截器组成的,即一个拦截器栈包含了多个拦截器。
<interceptor-stack name="stack name">
<interceptor-ref name="interceptor 1"/>
<interceptor-ref name="interceptor 2"/>
<interceptor-ref name="interceptor stack 1"/>
</interceptor>
提示:一个包中所有的拦截器都应定义在<interceptors…/>元素中
5. 拦截器及拦截器栈的使用
通过<interceptor-ref…/>元素来使用拦截器和拦截器栈。下面是在Action中定义拦截器的配置示例:
<action name="..." ...> ...... <!-- interceptor 1 --> <interceptor-ref name="int1"/> <!-- interceptor 2 --> <interceptor-ref name="int2"> <param name="...">...</param> </nterceptor-ref> </action
注:系统为拦截器指定参数有2个时机:
-
定义拦截器时:即在<interceptor>和<interceptor-stack>中增加<param>子元素
-
使用拦截器时:即在<interceptor-ref>中增加<param>子元素
6. 默认拦截器
配置每一个包时,可以为其指定默认拦截器。如果该包的某个Action未指定拦截器,系统会使用默认拦截器,但是一旦这个Action指定了拦截器则该包的默认拦截器将不起作用
配置默认拦截器使用<default-interceptor-ref …/>元素,该元素作为<packag…/>的子元素。
-
注:每个包只能有一个<default-interceptor-ref …/>子元素,即每个包至多只能有一个默认拦截器。
<package name="Test" extends="struts-default">
<default-interceptor-ref name="defaultStack" />
<interceptors>
<interceptor…/>
</interceptors>
<action name="showAction">
<result>/list.jsp</result>
</action>
</package>
提示:一个包中所有的拦截器都应定义在<interceptors…/>元素中
7.使用自定义拦截器
实现拦截器类
如果用户要开发自己的拦截器类,有如下两种方式:
- 实现com.opensymphony.xwork2.interceptor.Interceptor接口
- 继承AbstractInterceptor类
Interceptor定义如下:
public interface Interceptor extends Serializable {
/**
* Called to let an interceptor clean up any resources it has allocated.
*/
void destroy();/**
* Called after an interceptor is created, but before any requests are processed using
* {@link #intercept(com.opensymphony.xwork2.ActionInvocation) intercept} , giving
* the Interceptor a chance to initialize any needed resources.
*/
void init();/**
* Allows the Interceptor to do some processing on the request before and/or after the rest of the processing of the
* request by the {@link ActionInvocation} or to short-circuit the processing and just return a String return code.
*
* @param invocation the action invocation
* @return the return code, either returned from {@link ActionInvocation#invoke()}, or from the interceptor itself.
* @throws Exception any system-level error, as defined in {@link com.opensymphony.xwork2.Action#execute()}.
*/
String intercept(ActionInvocation invocation) throws Exception;}
我们的拦截器必须重写Interceptor接口中的intercept方法,该方法有一个ActionInvocation的参数,该参数实例可以用于获得被拦截的Action实例。
MyAction action = (MyAction)invocation.getAction();
一旦获得了Action实例,几乎获得了Action的全部控制权:
- 可以实现将HTTP请求参数解析出来,设置成Action的属性(这是系统拦截器干的事情)
- 可以直接将HTTP请求中的HttpServletRequest实例和HttpServletResponse实例传给Action(这是servlet-config拦截器干的事情)
- …..
下面是个自定义拦截器类的例子
拦截器类
import com.jj.test.redirect.RedirectTest; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; public class MyInterceptor extends AbstractInterceptor{ @Override public String intercept(ActionInvocation invocation) throws Exception { RedirectTest action = (RedirectTest)invocation.getAction(); System.out.println(action.getTarget()); System.out.println("Start------"); long start = System.currentTimeMillis(); //执行Action的exceute方法 String result = invocation.invoke(); long end = System.currentTimeMillis(); System.out.println("End------"+(end-start)); return result; } }
ActionInvocation 类常用方法
- getAction方法 -获取Action实例
- getInvocationContext方法 - 获取ActionContext实例
- invoke方法 - 执行该拦截器的后一个拦截器,或者直接执行Action的execute方法
在intercept方法中获取Session
ActionContext ctx = invocation.getInvocationContext();
Map session = ctx.getSession();
struts.xml中的配置
<package name="redir" namespace="/redir" extends="struts-default"> <interceptors> <interceptor name="MyInterceptor" class="com.jj.test.interceptor.MyInterceptor"></interceptor> </interceptors> <default-interceptor-ref name="MyInterceptor"/> <action name="RedirTest" class="com.jj.test.redirect.RedirectTest"> <result name="SUCCESS" type="dispatcher">/${target}.jsp</result> </action> </package>
8. 方法过滤拦截器
在默认情况下,如果为某个Action定义了拦截器,则这个拦截器会拦截该Action的所有方法,有些情况下我们只需要拦截某个Action的某些方法,着就要使用到方法过滤器。
为了实现方法过滤的特性,struts2提供了一个MethodFilterInterceptor类,该类是AbstractInterceptor类的子类,用户可以继承该类来实现自己的方法过滤器类。
MethodFilterInterceptor类重写了AbstractInterceptor类的intercept方法,但提供了一个doIntercept的抽象方法。如果用户需要实现自己的拉涅逻辑,则应该重写doIntercept方法。
MethodFilterInterceptor类中还有两个额外的方法
-
setExcludeMethods:排除需要过滤的方法,这些方法不会被拦截
-
setIncludeMethods:要拦截的方法
提示:如果一个方法同时在excludeMethods和includeMethods中列出,则该方法会被拦截。
方法过滤拦截器与普通拦截器使用类似,该拦截器配置举例:
<interceptors><interceptor name="MethodFilterTest" class="…" /></interceptors><action …><interceptor-ref name="MethodFilterTest"><param name = "excludeMethods">execute,run</param></intercepter-ref>……</action
其他Struts 2中提供的方法过滤拦截器
-
TokenInterceptor
-
TokenSessionStorInterceptor
-
DefaultWorkflowInterceptor
-
ValidationInterceptor
9. 拦截器的执行顺序
如果一个Action使用了多个拦截器,则这些拦截器的使用顺序如下:
在执行目标Action的execute方法之前执行第一个拦截器的代码执行第二个拦截器的代码……执行第n个拦截器的代码在执行目标Action的execute方法之后执行第n个拦截器的代码……执行第二个拦截器的代码执行第一个拦截器的代码
10. 拦截结果的监听器
为了精确定义在execute方法执行结束后,再处理Result执行的动作,Struts2提供了用于拦截结果的监听器,这个监听器必须手动在其他拦截器内注册。
实现拦截结果的监听器首先必须现实com.opensymphony.xwork2.interceptor.PreResultListener类并重写里面的方法beforeResult :
public class MyListener implements PreResultListener {
public void beforeResult(ActionInvocation invocation, String resultCode) {
System.out.println(resultCode);
}
}
结果监听器的注册(必须手动在其他拦截器内注册)
如在某个拦截器的intercept方法中添加撰写如下代码:
public String intercept(ActionInvocation invocation) throws Exception { //将一个拦截器结果的监听器注册给该拦截器 invocation.addPreResultListener(new MyPreResultListener()); System.out.println("execute()方法执行之前的拦截..."); //调用下一个拦截器,或者Action的执行方法 String result = invocation.invoke(); System.out.println("execute()方法执行后的拦截..."); return result; }
拦截器结果监听器是在系统处理Result之前,在execute之后执行的。
虽然beforeResult方法中也可以获得AcionInvocation实例,但千万不可通过该实例再次调用invoke方法,如果再次调用,将会再次执行Action处理,紧跟着在调用beforeResult方法,造成死循环。
注意:不要在PreResultListener监听器的beforeResult方法中通过ActionInvocation参数调用invoke方法。否则容易造成死循环。
11. 拦截器栈中特定拦截器参数的覆盖
若想覆盖某拦截器栈中特定拦截器的某些参数,可以在配置Action的拦截器引用时使用如下形式
<interceptor-ref name="interceptor-stack">
<param name="要覆盖的拦截器名.参数名">参数的值</param>
</interceptor>
posted on 2011-02-12 17:55 Eason Jiang 阅读(1071) 评论(0) 编辑 收藏 举报