Struts2攔截器(Interceptor)
++YONG原創(chuàng),轉(zhuǎn)載請(qǐng)注明
1. 理解攔截器
1.1. 什么是攔截器:
攔截器,在AOP(Aspect-Oriented Programming)中用于在某個(gè)方法或字段被訪問之前,進(jìn)行攔截然后在之前或之后加入某些操作。攔截是AOP的一種實(shí)現(xiàn)策略。
在Webwork的中文文檔的解釋為——攔截器是動(dòng)態(tài)攔截Action調(diào)用的對(duì)象。它提供了一種機(jī)制可以使開發(fā)者可以定義在一個(gè)action執(zhí)行的前后執(zhí)行的代碼,也可以在一個(gè)action執(zhí)行前阻止其執(zhí)行。同時(shí)也是提供了一種可以提取action中可重用的部分的方式。
談到攔截器,還有一個(gè)詞大家應(yīng)該知道——攔截器鏈(Interceptor Chain,在Struts 2中稱為攔截器棧Interceptor Stack)。攔截器鏈就是將攔截器按一定的順序聯(lián)結(jié)成一條鏈。在訪問被攔截的方法或字段時(shí),攔截器鏈中的攔截器就會(huì)按其之前定義的順序被調(diào)用。
1.2. 攔截器的實(shí)現(xiàn)原理:
大部分時(shí)候,攔截器方法都是通過代理的方式來調(diào)用的。Struts 2的攔截器實(shí)現(xiàn)相對(duì)簡(jiǎn)單。當(dāng)請(qǐng)求到達(dá)Struts 2的ServletDispatcher時(shí),Struts 2會(huì)查找配置文件,并根據(jù)其配置實(shí)例化相對(duì)的攔截器對(duì)象,然后串成一個(gè)列表(list),最后一個(gè)一個(gè)地調(diào)用列表中的攔截器。如下圖:
2. 攔截器的配置
Struts 2已經(jīng)為您提供豐富多樣的,功能齊全的攔截器實(shí)現(xiàn)。大家可以至struts2的jar包內(nèi)的struts-default.xml查看關(guān)于默認(rèn)的攔截器與攔截器鏈的配置。
Struts2(XWork)提供的攔截器的功能說明:
攔截器 |
名字 |
說明 |
Alias Interceptor |
alias |
在不同請(qǐng)求之間將請(qǐng)求參數(shù)在不同名字件轉(zhuǎn)換,請(qǐng)求內(nèi)容不變 |
Chaining Interceptor |
chain |
讓前一個(gè)Action的屬性可以被后一個(gè)Action訪問,現(xiàn)在和chain類型的result(<result type=”chain”>)結(jié)合使用。 |
Checkbox Interceptor |
checkbox |
添加了checkbox自動(dòng)處理代碼,將沒有選中的checkbox的內(nèi)容設(shè)定為false,而html默認(rèn)情況下不提交沒有選中的checkbox。 |
Cookies Interceptor |
cookies |
使用配置的name,value來是指cookies |
Conversion Error Interceptor |
conversionError |
將錯(cuò)誤從ActionContext中添加到Action的屬性字段中。 |
Create Session Interceptor |
createSession |
自動(dòng)的創(chuàng)建HttpSession,用來為需要使用到HttpSession的攔截器服務(wù)。 |
Debugging Interceptor |
debugging |
提供不同的調(diào)試用的頁(yè)面來展現(xiàn)內(nèi)部的數(shù)據(jù)狀況。 |
Execute and Wait Interceptor |
execAndWait |
在后臺(tái)執(zhí)行Action,同時(shí)將用戶帶到一個(gè)中間的等待頁(yè)面。 |
Exception Interceptor |
exception |
將異常定位到一個(gè)畫面 |
File Upload Interceptor |
fileUpload |
提供文件上傳功能 |
I18n Interceptor |
i18n |
記錄用戶選擇的locale |
Logger Interceptor |
logger |
輸出Action的名字 |
Message Store Interceptor |
store |
存儲(chǔ)或者訪問實(shí)現(xiàn)ValidationAware接口的Action類出現(xiàn)的消息,錯(cuò)誤,字段錯(cuò)誤等。 |
Model Driven Interceptor |
model-driven |
如果一個(gè)類實(shí)現(xiàn)了ModelDriven,將getModel得到的結(jié)果放在Value Stack中。 |
Scoped Model Driven |
scoped-model-driven |
如果一個(gè)Action實(shí)現(xiàn)了ScopedModelDriven,則這個(gè)攔截器會(huì)從相應(yīng)的Scope中取出model調(diào)用Action的setModel方法將其放入Action內(nèi)部。 |
Parameters Interceptor |
params |
將請(qǐng)求中的參數(shù)設(shè)置到Action中去。 |
Prepare Interceptor |
prepare |
如果Acton實(shí)現(xiàn)了Preparable,則該攔截器調(diào)用Action類的prepare方法。 |
Scope Interceptor |
scope |
將Action狀態(tài)存入session和application的簡(jiǎn)單方法。 |
Servlet Config Interceptor |
servletConfig |
提供訪問HttpServletRequest和HttpServletResponse的方法,以Map的方式訪問。 |
Static Parameters Interceptor |
staticParams |
從struts.xml文件中將<action>中的<param>中的內(nèi)容設(shè)置到對(duì)應(yīng)的Action中。 |
Roles Interceptor |
roles |
確定用戶是否具有JAAS指定的Role,否則不予執(zhí)行。 |
Timer Interceptor |
timer |
輸出Action執(zhí)行的時(shí)間 |
Token Interceptor |
token |
通過Token來避免雙擊 |
Token Session Interceptor |
tokenSession |
和Token Interceptor一樣,不過雙擊的時(shí)候把請(qǐng)求的數(shù)據(jù)存儲(chǔ)在Session中 |
Validation Interceptor |
validation |
使用action-validation.xml文件中定義的內(nèi)容校驗(yàn)提交的數(shù)據(jù)。 |
Workflow Interceptor |
workflow |
調(diào)用Action的validate方法,一旦有錯(cuò)誤返回,重新定位到INPUT畫面 |
Parameter Filter Interceptor |
N/A |
從參數(shù)列表中刪除不必要的參數(shù) |
Profiling Interceptor |
profiling |
通過參數(shù)激活profile |
在struts.xml文件中定義攔截器,攔截器棧:
<package name="my" extends="struts-default" namespace="/manage">
<interceptors>
<!-- 定義攔截器 -->
<interceptor name="攔截器名" class="攔截器實(shí)現(xiàn)類"/>
<!-- 定義攔截器棧 -->
<interceptor-stack name="攔截器棧名">
<interceptor-ref name="攔截器一"/>
<interceptor-ref name="攔截器二"/>
</interceptor-stack>
</interceptors>
......
</package> |
3. 使用攔截器
一旦定義了攔截器和攔截器棧后,就可以使用這個(gè)攔截器或攔截器棧來攔截Action了。攔截器的攔截行為將會(huì)在Action的exceute方法執(zhí)行之前被執(zhí)行。
<action name="userOpt" class="org.qiujy.web.struts2.action.UserAction">
<result name="success">/success.jsp</result>
<result name="error">/error.jsp</result>
<!-- 使用攔截器,一般配置在result之后, -->
<!-- 引用系統(tǒng)默認(rèn)的攔截器 -->
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="攔截器名或攔截器棧名"/>
</action> |
此處需要注意的是,如果為Action指定了一個(gè)攔截器,則系統(tǒng)默認(rèn)的攔截器棧將會(huì)失去作用。為了繼續(xù)使用默認(rèn)攔截器,所以上面配置文件中手動(dòng)引入了默認(rèn)攔截器。
4. 自定義攔截器
作為“框架(framework)”,可擴(kuò)展性是不可或缺的。雖然,Struts 2為我們提供如此豐富的攔截器實(shí)現(xiàn),但是這并不意味我們失去創(chuàng)建自定義攔截器的能力,恰恰相反,在Struts 2自定義攔截器是相當(dāng)容易的一件事。
4.1. 實(shí)現(xiàn)攔截器類:
所有的Struts 2的攔截器都直接或間接實(shí)現(xiàn)接口com.opensymphony.xwork2.interceptor.Interceptor。該接口提供了三個(gè)方法:
1) void init(); 在該攔截器被初始化之后,在該攔截器執(zhí)行攔截之前,系統(tǒng)回調(diào)該方法。對(duì)于每個(gè)攔截器而言,此方法只執(zhí)行一次。
2) void destroy();該方法跟init()方法對(duì)應(yīng)。在攔截器實(shí)例被銷毀之前,系統(tǒng)將回調(diào)該方法。
3) String intercept(ActionInvocation invocation) throws Exception; 該方法是用戶需要實(shí)現(xiàn)的攔截動(dòng)作。該方法會(huì)返回一個(gè)字符串作為邏輯視圖。
除此之外,繼承類com.opensymphony.xwork2.interceptor.AbstractInterceptor是更簡(jiǎn)單的一種實(shí)現(xiàn)攔截器類的方式,因?yàn)榇祟愄峁┝?/span>init()和destroy()方法的空實(shí)現(xiàn),這樣我們只需要實(shí)現(xiàn)intercept方法。
4.2. 使用自定義攔截器:
兩個(gè)步驟:
l 通過<interceptor …>元素來定義攔截器。
l 通過<interceptor-ref …>元素來使用攔截器。
5. 自定義攔截器示例
5.1. 問題描述:
使用自定義攔截器來完成用戶權(quán)限的控制:當(dāng)瀏覽者需要請(qǐng)求執(zhí)行某個(gè)操作時(shí),應(yīng)用需要先檢查瀏覽者是否登錄,以及是否有足夠的權(quán)限來執(zhí)行該操作。
5.2. 實(shí)現(xiàn)權(quán)限控制攔截器類:
AuthorizationInterceptor.java
package org.qiujy.common;
import java.util.Map;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
/**
* 權(quán)限檢查攔截器
*
* @author qiujy
* @version 1.0
*/
public class AuthorizationInterceptor extends AbstractInterceptor {
/*
* 攔截Action處理的攔截方法
*
*/
public String intercept(ActionInvocation invocation) throws Exception {
Map session = invocation.getInvocationContext().getSession();
String userName = (String) session.get("userName");
if (null != userName && userName.equals("test")) {
System.out.println("攔截器:合法用戶登錄---");
return invocation.invoke();
} else {
System.out.println("攔截器:用戶未登錄---");
return Action.LOGIN;
}
}
} |
5.3. 配置權(quán)限控制攔截器:
struts.xml:
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="my" extends="struts-default">
<interceptors>
<!-- 定義權(quán)限控制攔截器 -->
<interceptor name="authority"class="org.qiujy.common.AuthorizationInterceptor"/>
</interceptors>
<!-- 定義全局處理結(jié)果 -->
<global-results>
<!-- 邏輯名為login的結(jié)果,映射到/login.jsp頁(yè)面 -->
<result name="login">/login.jsp</result>
</global-results>
<action name="listall"class="org.qiujy.web.struts2.action.UserAction" method="listAllUser">
<result name="success">/listall.jsp</result>
<!-- 使用攔截器 -->
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="authority"/>
</action>
<action name="userOpt"class="org.qiujy.web.struts2.action.UserAction">
<result name="success">/success.jsp</result>
</action>
</package>
</struts> |
其它頁(yè)面見源代碼。
5.4. 運(yùn)行調(diào)試:
在瀏覽器地址欄直接輸入http://localhost:8080/AuthorityInterceptorDemo/listall.action 來訪問,此動(dòng)作配置了權(quán)限攔截器,所有被轉(zhuǎn)到登錄頁(yè)面。
登錄后:
再訪問http://localhost:8080/AuthorityInterceptorDemo/listall.action 這個(gè)鏈接:



如果為了簡(jiǎn)化struts.xml文件的配置,避免在每個(gè)Action重復(fù)配置該攔截器,可以將攔截器配置成了一個(gè)默認(rèn)攔截器棧。如下:
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="my" extends="struts-default">
<interceptors>
<!-- 定義權(quán)限控制攔截器 -->
<interceptor name="authority"
class="org.qiujy.common.AuthorizationInterceptor" />
<!-- 定義一個(gè)包含權(quán)限控制的攔截器棧 -->
<interceptor-stack name="mydefault">
<interceptor-ref name="defaultStack" />
<interceptor-ref name="authority" />
</interceptor-stack>
</interceptors>
<!-- 定義默認(rèn)攔截器 -->
<default-interceptor-ref name="mydefault" />
<!-- 定義全局處理結(jié)果 -->
<global-results>
<!-- 邏輯名為login的結(jié)果,映射到/login.jsp頁(yè)面 -->
<result name="login">/login.jsp</result>
</global-results>
<action name="listall"
class="org.qiujy.web.struts2.action.UserAction"
method="listAllUser">
<result name="success">/listall.jsp</result>
</action>
</package>
<package name="font" extends="struts-default">
<action name="userOpt"class="org.qiujy.web.struts2.action.UserAction">
<result name="success">/success.jsp</result>
</action>
</package>
</struts> |
一旦在某個(gè)包下定義了默認(rèn)攔截器棧,在該包下的所有action都會(huì)使用此攔截器棧。對(duì)于那些不想使用些攔截器棧的action,則應(yīng)該將它放置在其它的包下。