天天看點

重溫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>
           

如此即可。

繼續閱讀