对于struts框架而言,可以理解为空的容器,正是大量内建的拦截器完成了该框架的大部分操作。
若要使用某个拦截器,只需要在配置文件中配置即可,这种可拔插式的设计使得struts2框架具有较好的扩展性。
开发者也可以在开发过程中定义自己的拦截器,然后在配置文件中做相应的配置即可使用该拦截器。
sturts2的拦截器体系是一种AOP的设计思想,使得我们可以在执行action代码前后可以加入另外的执行代码。通过这种方式就可以把action中重复的代码提取出来,放入拦截器中达到代码复用的目的。
拦截器使得系统可以动态地选择使用某种功能或不使用某种功能,系统很大程度的解耦。
先看一些常见的拦截器:
conversionError:当类型转换错误时,提取错误并转换成action中的FiledError
createSession:创建一个HttpSession对象
exception:负责处理异常,将异常映射成结果
fileUpload:上传文件时设置action类的xxxFileName和xxxContentType,并且可以检验上传类型是否被允许,上传文件的大小限制
params:解析request中的请求参数并设置到action属性中。
servlet-config:将ServletAPI中的对象传递给Action
拦截器的实现原理
struts2中的拦截器是通过动态代理实现的,JDK直接支持动态代理,所以还是很方便的,有关动态代理更详细的说明可以看动态代理模式。
以下是一个简单的动态代理的示例:
public class DynamicProxy { public static void main(String[] args) { // TODO Auto-generated method stub Dog dog = new DogImpl(); RunHandler h = new RunHandler(dog); Dog proxyDog = (Dog)Proxy.newProxyInstance(dog.getClass().getClassLoader(), new Class[]{Dog.class}, h); proxyDog.run(); } } interface Dog{ public void run(); } class DogImpl implements Dog{ public void run(){ System.out.println("奔跑"); } } class DogIntercepter{ public void f(){ System.out.println("预备..."); } public void g(){ System.out.println("加速跑..."); } } class RunHandler implements InvocationHandler{ private Object target; private DogIntercepter di = new DogIntercepter(); public RunHandler(Object dog){ this.target = dog; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub Object result = null; if(method.getName().equals("run")){ di.f(); result = method.invoke(target, args); di.g(); } else{ result = method.invoke(target, args); } return result; } }
在RunHandler中,target用于保存被代理的对象,method.getName()则是判断是否是目标方法,DogIntercepter则是用于确定被插入的代码。
而在struts2的拦截器机制中,被拦截的肯定就是action类对象中的execute()或者配置文件中指定的method属性的值了,被插入的代码则放在拦截器中,通过拦截器调用中相应的方法。因为拦截器是动态配置的,所以execute()执行前后插入的代码也就是动态地了,如此便使得系统有较好的扩展性了。
接下来看一段拦截器的配置文件:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <bean type="ognl.PropertyAccessor" name="java.util.ArrayList" class="com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor" /> <bean type="ognl.PropertyAccessor" name="java.util.HashSet" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" /> <bean type="ognl.PropertyAccessor" name="java.util.HashMap" class="com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor" /> <package name="struts-default" abstract="true"> <result-types> <result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/> <result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/> <result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/> <result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/> <result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/> <result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/> <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/> <result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/> <result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/> <result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult" /> </result-types> <interceptors> <interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/> <interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/> <interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/> <interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/> <interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/> <interceptor name="cookieProvider" class="org.apache.struts2.interceptor.CookieProviderInterceptor"/> <interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" /> <interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" /> <interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" /> <interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/> <interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/> <interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/> <interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/> <interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/> <interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/> <interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/> <interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/> <interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/> <interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/> <interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/> <interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/> <interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/> <interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/> <interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/> <interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/> <interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/> <interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/> <interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" /> <interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" /> <interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" /> <interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" /> <interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" /> <interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" /> <!-- Basic stack --> <interceptor-stack name="basicStack"> <interceptor-ref name="exception"/> <interceptor-ref name="servletConfig"/> <interceptor-ref name="prepare"/> <interceptor-ref name="checkbox"/> <interceptor-ref name="multiselect"/> <interceptor-ref name="actionMappingParams"/> <interceptor-ref name="params"> <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param> </interceptor-ref> <interceptor-ref name="conversionError"/> </interceptor-stack> <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="multiselect"/> <interceptor-ref name="staticParams"/> <interceptor-ref name="actionMappingParams"/> <interceptor-ref name="params"> <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param> </interceptor-ref> <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-stack> </interceptors> <default-interceptor-ref name="defaultStack"/> <default-class-ref class="com.opensymphony.xwork2.ActionSupport" /> </package> </struts>
摘自struts-default.xml片段,上面的配置中,
<intercepters>:定义拦截器和拦截器栈(就是多个拦截器组合)
<intercepter>:定义拦截器
<intercepter-stack>:定义拦截器栈
<intercepter-ref>:使用拦截器或使用拦截器栈
<default-interceptor-ref>:在包内定义默认的拦截器,也就是该包内没有指定拦截器时使用该拦截器,但若指定了其他的拦截器则不使用(除非同时显示指明要使用该拦截器)
<param>:为拦截器设置参数,若在定义时使用这个元素是设定默认值,而在使用时则是覆盖默认值。
实现自己的拦截器
自定义的拦截器需要实现Interceptor接口,该接口有三个方法:init(),destroy(),interceptor(ActionInvacation)
如果不需要申请资源,可以继承AbstractInterceptor抽象类,它提供了init(),destroy()的空实现
如果要指定被拦截的方法,可以继承MethodFilterInterceptor,该类重写了Interceptor并回调抽象方法doInterceptor(ActionInvacation)
在使用拦截器时指定includeMethod和excludeMethod参数即可。
通过ActionInvacation类可以获得被代理的action实例,之后便可以进行各种操作了,给action属性设置值,传递HttpServletRequest实例等等。
关于说明到此为止,接下来看一个例子:
自定义拦截器:
package ch7.interceptor; import java.util.Date; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor; public class MyInterceptor extends MethodFilterInterceptor{ /** * */ private static final long serialVersionUID = -9188677556314894033L; private String name; public void setName(String name){ this.name = name; } public String getName(){ return name; } @Override protected String doIntercept(ActionInvocation action) throws Exception { // TODO Auto-generated method stub System.out.println(getName()+" 拦截"+action.getAction().getClass().getSimpleName()+"类在:"+new Date()); String o = action.invoke(); System.out.println(getName()+" 拦截"+action.getAction().getClass().getSimpleName()+"类在:"+new Date()); return o; } }
public class LoginAction { public String execute(){ return "success"; } }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="default" namespace="/" extends="struts-default"> <interceptors> <interceptor name="my" class="ch7.interceptor.MyInterceptor"></interceptor> </interceptors> <action name="interlogin" class="ch7.interceptor.LoginAction"> <interceptor-ref name="my"> <param name="name">我的拦截器</param> <param name="includeMethods">execute</param> </interceptor-ref> <interceptor-ref name="defaultStack"></interceptor-ref> <result name="success">/result.jsp</result> </action> </package> </struts>