天天看点

重温struts2之拦截器

对于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;
	}

}
           

action:

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>
           

如此即可。

继续阅读