攔截器(interceptor)是Struts2最強大的特性之一,攔截器可讓你在Action和result被執行以前或以後進行一些處理。同時,攔截器也可讓你將通用的代碼模塊化並做爲可重用的類。Struts2中的不少特性都是由攔截器來完成的。例如params攔截器將HTTP請求中的參數解析出來,並設置爲Action的屬性。servlet-config攔截器直接將HTTP請求中的HttpServletRequest對象化HttpServletResponse對象傳給Action。html
Struts2中內置類許多的攔截器,它們提供了許多Struts2的核心功能和可選的高級特性。這些內置的攔截器在struts-default.xml中配置。只有配置了攔截器,攔截器才能夠正常的工做和運行。在struts-default.xml中攔截器的配置片斷爲:java
<package name="struts-default" abstract="true"> ① <interceptors> <interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/> ② <interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/> //…其餘攔截器配置 <interceptor-stack name="defaultStack"> ③ <interceptor-ref name="exception"/> <interceptor-ref name="alias"/> <interceptor-ref name="servletConfig"/> <interceptor-ref name="i18n"/> //…其餘攔截器的引用 </interceptor-stack> </interceptors> <default-interceptor-ref name="defaultStack"/> ④ </package> ① package將屬性abstract設置爲true,表明此package爲一個抽象的package。抽象package和非抽象package的區別在於抽象的package中不能配置action。 ② name屬性指定攔截器的名字,class屬性指定攔截器的徹底限定名。 ③ 多個攔截器能夠組成攔截器棧。name屬性爲攔截器棧的名字。 ④ 指定當前package的默認攔截器(棧)。當前指定的默認攔截器棧爲defaultStack,該攔截器棧是Struts2運行的一個基本攔截器棧,通常咱們不用在本身配置它,由於在大多數狀況下,咱們自定義的package是繼承自struts-default這個package的。
咱們以Struts2內置的timer攔截器爲例,來學習如何在咱們的應用中添加其餘的攔截器。timer攔截器能夠統計action執行的時間。咱們能夠修改package中默認的攔截器,那麼將替換掉struts-default中配置的defaultStack攔截器棧,致使Struts2沒法正常運行,好比沒法獲取表單的值等等。那麼該如何正確的配置呢?能夠在添加新的攔截器的基礎上加入defaultStack攔截器棧,這樣就能夠保證defaultStack攔截器棧的存在。spring
<package name="myStruts" extends="struts-default"> <interceptors> <interceptor-stack name="myInterceptor"> ① <interceptor-ref name="timer"/> <interceptor-ref name="defaultStack"/> </interceptor-stack> </interceptors> <default-interceptor-ref name="myInterceptor"/> ② <action name="userAction" class="com.kay.action.UserAction"> <result name="success">suc.jsp</result> <result name="input">index.jsp</result> <result name="error">err.jsp</result> </action> </package> ① 添加一個自定義的攔截器棧,並在其中包含time攔截器和defaultStack攔截器棧。 ② 設置當前的package的默認攔截器棧爲自定義的攔截器棧。
修改package的默認攔截器會應用的package中的全部Action中,若是隻想給其中一個Action添加攔截器,則能夠這樣來作:apache
<package name="myStruts" extends="struts-default"> <interceptors> <interceptor-stack name="myInterceptor"> <interceptor-ref name="timer"/> <interceptor-ref name="defaultStack"/> </interceptor-stack> </interceptors> <action name="userAction" class="com.kay.action.UserAction"> <interceptor-ref name="myInterceptor"/> ① <result name="success">suc.jsp</result> <result name="input">index.jsp</result> <result name="error">err.jsp</result> </action> </package> ① 給UserAction添加攔截器。
若是要建立本身的攔截器,只須要實現Interceptor接口,該接口中定義瞭如下三個方法:jsp
void init():ide
在攔截器初始化以後,在執行攔截以前,系統調用該方法。對於一個攔截器而言,init方法只會被調用一次。模塊化
String intercept(ActionInvocation invocation) throws Exception:組件化
該方法是攔截器的攔截方法,返回一個字符串,系統將會跳轉到該字符串對應的視圖資源。該方法的ActionInvocation參數包含了被攔截的Action的引用,能夠經過該對象的invoke方法,將控制權轉給下一個攔截器或者轉給Action的execute方法。post
void destroy():單元測試
該方法與init方法對應,在攔截器示例被銷燬以前,系統將會調用該方法。
除了Interceptor接口外,Struts2中還提供了一個AbStractInterceptor類,該類提供了一個init和destroy方法的空實現。若是不須要就不用重寫這兩個方法,可見繼承自AbstractInterceptor類可讓咱們構建攔截器時變得簡單。
下面咱們構建本身的攔截器,實現timer攔截器的效果。
public class MyInterceptor extends AbstractInterceptor { public String intercept(ActionInvocation invocation) throws Exception { long startTime = System.currentTimeMillis(); ① String result = invocation.invoke(); ② long endTime = System.currentTimeMillis(); ③ System.out.println("Action執行共須要" + (endTime - startTime) + "毫秒"); return result; } } ① 得到Action執行的開始時間。 ② 將控制權交給下一個攔截器,若是該攔截器是最後一個攔截器,則調用Action的execute方法。 ③ 得到Action執行的結束時間。
在配置文件struts.xml中配置攔截器:
<package name="myStruts" extends="struts-default"> <interceptors> <interceptor name="myTimer" class="com.kay.interceptor.MyInterceptor"></interceptor> ① <interceptor-stack name="myInterceptor"> <interceptor-ref name="myTimer"/> ② <interceptor-ref name="defaultStack"/> </interceptor-stack> </interceptors> <action name="userAction" class="com.kay.action.UserAction"> <interceptor-ref name="myInterceptor"/> <result name="success">suc.jsp</result> <result name="input">index.jsp</result> <result name="error">err.jsp</result> </action> </package> ① 定義一個新的攔截器,name屬性爲攔截器的名字,class屬性爲攔截器的徹底限定名。 ② 在攔截器棧中加入新的攔截器。
從攔截器的運行原理上和咱們之前學習的Servlet中的過濾器是否是很相像呢?其實它們只有一個重要的區別,就是攔截器的工做是不依賴容器的,這會在進行單元測試時變得簡單。
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd" > <struts> <!-- include節點是struts2中組件化的方式 能夠將每一個功能模塊獨立到一個xml配置文件中 而後用include節點引用 --> <include file="struts-default.xml"></include> <!-- package提供了將多個Action組織爲一個模塊的方式 package的名字必須是惟一的 package能夠擴展 當一個package擴展自 另外一個package時該package會在自己配置的基礎上加入擴展的package 的配置 父package必須在子package前配置 name:package名稱 extends:繼承的父package名稱 abstract:設置package的屬性爲抽象的 抽象的package不能定義action 值true:false namespace:定義package命名空間 該命名空間影響到url的地址,例如此命名空間爲/test那麼訪問是的地址爲http://localhost:8080/struts2/test/XX.action --> <package name="com.kay.struts2" extends="struts-default" namespace="/test"> <interceptors> <!-- 定義攔截器 name:攔截器名稱 class:攔截器類路徑 --> <interceptor name="timer" class="com.kay.timer"></interceptor> <interceptor name="logger" class="com.kay.logger"></interceptor> <!-- 定義攔截器棧 --> <interceptor-stack name="mystack"> <interceptor-ref name="timer"></interceptor-ref> <interceptor-ref name="logger"></interceptor-ref> </interceptor-stack> </interceptors> <!-- 定義默認的攔截器 每一個Action都會自動引用 若是Action中引用了其它的攔截器 默認的攔截器將無效 --> <default-interceptor-ref name="mystack"></default-interceptor-ref> <!-- 全局results配置 --> <global-results> <result name="input">/error.jsp</result> </global-results> <!-- Action配置 一個Action能夠被屢次映射(只要action配置中的name不一樣) name:action名稱 class: 對應的類的路徑 method: 調用Action中的方法名 --> <action name="hello" class="com.kay.struts2.Action.LoginAction"> <!-- 引用攔截器 name:攔截器名稱或攔截器棧名稱 --> <interceptor-ref name="timer"></interceptor-ref> <!-- 節點配置 name : result名稱 和Action中返回的值相同 type : result類型 不寫則選用superpackage的type struts-default.xml中的默認爲dispatcher --> <result name="success" type="dispatcher">/talk.jsp</result> <!-- 參數設置 name:對應Action中的get/set方法 --> <param name="url">http://www.sina.com</param> </action> </package> </struts>