第一節(jié):Struts2的攔截器
1.1 攔截器的概述:
攔截器,在AOP(Aspect - Oriented Programming)中用于在某個方法或字段被訪問之前,進行攔截然后在之前或之后加入某些操作。攔截是AOP的一種實現(xiàn)策略。
在WebWork的中文文檔的解釋為——攔截器是動態(tài)攔截Action調(diào)用的對象。它提供了一些機制可以使開發(fā)者可以定義在一個action執(zhí)行的前后執(zhí)行的代碼,也可以在一個Action執(zhí)行前阻止其執(zhí)行。同時也是提供了一種可以提取action中可重用的部分的方式。
談到攔截器,還有一個詞——攔截器鏈(Interceptor Chain,在Struts2中稱為攔截棧Interceptor Stack)。攔截器鏈就是將攔截器按一定的順序聯(lián)結(jié)成一條鏈。在訪問被攔截的方法或字段時,攔截器鏈中的攔截器就會按其之前定義的順序被調(diào)用。
1.2 攔截器的實現(xiàn)原理:
攔截器方法都是通過代理的方式來調(diào)用的。當請求送達Struts2的ServletDispatcher時,Struts2會查找配置文件,并根據(jù)其配置實例化相對的攔截器對象,然后串成一個列表,最后一個一個地調(diào)用列表中的攔截器。
Struts2攔截器是可插拔的,攔截器是AOP的一種實現(xiàn)。Struts2攔截器棧就是將攔截器按一定的順序聯(lián)結(jié)成一條鏈。在訪問被攔截的方法或字段時,Struts2攔截器鏈中的攔截器就會按其之前定義的順序被調(diào)用。
1.3 攔截器的執(zhí)行流程

1.4 自定義攔截器
若需要實現(xiàn)攔截器類,就需要直接或間接的實現(xiàn)com.opensymphony.xwork2.interceptor接口,其接口定義代碼如下:
import com.opensymphony.xwork2.ActionInvocation;
import java.io.Serializable;
public interface Interceptor extends Serializable {
void destroy();
void init();
String intercept(ActionInvocation var1) throws Exception;
}
該接口提供了三個方法,其具體介紹如下:
- void init():該方法在攔截器被創(chuàng)建后會立即被調(diào)用,它在攔截器的生命周期內(nèi)只被調(diào)用一次,可以在該方法中對相關(guān)資源進行必要的初始。
- void destroy():該方法與init方法相對應(yīng),在攔截器被銷毀之前,將調(diào)用該方法來釋放和攔截器相關(guān)的資源。它在攔截器的生命周期內(nèi),也只被調(diào)用一次。
- String intercept(ActionInvocation invocation)throws Exception:該方法是攔截器的核心方法,用來添加真正執(zhí)行攔截工作的代碼,實現(xiàn)具體的攔截操作。它返回一個字符串作為邏輯視圖,系統(tǒng)根據(jù)返回的字符串跳轉(zhuǎn)到對應(yīng)的視圖資源。每攔截一個動作請求,該方法都會被調(diào)用一次。該方法的ActionInvocation參數(shù)包含了被攔截Action的引用,可以通過該參數(shù)的invoke()方法,將控制權(quán)給下一個攔截器或者轉(zhuǎn)給Action的execute()方法。
如果需要自定義攔截器,只需要實現(xiàn)Interceptor接口的三個方法即可。然而在實際的開發(fā)中,除了實現(xiàn)Interceptor接口可以自定義攔截器外,更常用的一種方式是繼承抽象攔截器類AbstracIntercepter。該類實現(xiàn)了Interceptor接口,并且提供了init()方法和destory()方法的空實現(xiàn)。使用時,可以繼承該抽象類,而不用實現(xiàn)那些不必要的方法。攔截器類AbstractInterceptor中定義的方法如下所示:
public abstract class AbstractInterceptor implements Interceptor {
public AbstractInterceptor() {
}
public void init() {
}
public void destroy() {
}
public abstract String intercept(ActionInvocation var1) throws Exception;
}
從上述代碼中可以看出,AbstractInterceptor類已經(jīng)實現(xiàn)了Interceptor接口的所有方法,一般情況下,只需繼承AbstractInterceptor類,實現(xiàn)interceptor()方法就可以創(chuàng)建自定義攔截器。
只有當自定義的攔截器需要打開系統(tǒng)資源時,才需要覆蓋AbstracInterceptor類的init()方法和destroy()方法。與實現(xiàn)Interceptor接口相比,繼承AbstractInterceptor類的方法更為簡單。
1.5 攔截器的配置
- 攔截器
要想讓攔截器起作用,首先要對它進行配置。攔截器的配置是在struts.xml文件中完成的,它通常以<interceptor>標簽開頭,以</interceptor>標簽結(jié)束。定義攔截器的語法格式如下:
<interceptors>
<interceptor name="interceptorDemo01" class="com.seapp.struts2.interceptor.MyInterceptor02">
<param name="paramName">paramValue</param>
</interceptor>
</interceptors>
上述語法格式中,name屬性用來指定攔截器的名稱,class屬性用于指定攔截器的實現(xiàn)類。有時,在定義攔截器時需要傳入?yún)?shù),這時需要使用<param>標簽,其中name屬性用來指定參數(shù)的名稱,paramValue表示參數(shù)的值。
- 在實際開發(fā)中,經(jīng)常需要在Action執(zhí)行前同時執(zhí)行多個攔截動作,如:用戶登錄檢查、登錄日志記錄以及權(quán)限檢查等。這時,可以把多個攔截器組成一個攔截器棧。在使用時,可以將棧內(nèi)多個攔截器當成一個整體來引用。當攔截器棧被附加到一個Action上時,在執(zhí)行Action之前必須先執(zhí)行攔截器棧中的每一個攔截器。
-攔截器:
<interceptors>
<interceptor-stack name="interceptorStackName">
<interceptor-ref name="interceptorName"/>
...
</interceptor-stack>
</interceptors>
在上述的語法中,interceptorStackName值表示配置的攔截器的名稱;interceptorName值表示攔截器的名稱。除此之外,在一個攔截器棧中還可以包含另一個攔截器棧,示例代碼如下:
<interceptors>
<!--聲明攔截器-->
<interceptor name="interceptor" class="com.seapp.struts2.interceptor.MyInterceptor">
</interceptor>
<interceptor name="interceptorDemo01" class="com.seapp.struts2.interceptor.MyInterceptor02">
<param name="paramName">paramValue</param>
</interceptor>
<!--定義一個攔截器棧myStack,該攔截器棧中包含兩個攔截器和一個攔截器棧-->
<interceptor-stack name="myStack">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="interceptor"/>
<interceptor-ref name="interceptorDemo01"/>
</interceptor-stack>
</interceptors>
在上述代碼中,定義的攔截器棧是myStack,在myStack棧中,除了引用了兩個自定義的攔截器interceptor和interceptorDemo01外,還引用了一個內(nèi)置攔截器棧defaultStack,這個攔截器是必須要引入的。