轉:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<struts>
<package name="struts2" extends="struts-default"> <interceptors> <interceptor name="myInterceptor" class="edu.hust.interceptor.MyInterceptor"></interceptor> </interceptors> <action name="register" class="edu.hust.action.RegisterAction"> <result name="input">/register.jsp</result> <result>/result.jsp</result> <!-- 在自定義interceptor並將其ref時, 系統會覆蓋掉默認的interceptor-stack(defaultStack), 為了保證系統默認的defaultStack不受印象, 我們需要顯式的將其引入 --> <!-- 注意兩個interceptor-ref的順序, 順序不同, 執行效果也不同: 先配置的先執行/后配置的先退出(先進后出) --> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="myInterceptor"></interceptor-ref> </action> </package> </struts> |
方法2. 配置攔截器棧(即將多個interceptor串聯的一種元素)。然后在ion>中引入該攔截器棧就可以了。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<struts>
<package name="struts2" extends="struts-default"> <interceptors> <interceptor name="myInterceptor" class="edu.hust.interceptor.MyInterceptor"></interceptor> <interceptor-stack name="myInterceptorStack"> <interceptor-ref name="myInterceptor"></interceptor-ref> <interceptor-ref name="defaultStack"></interceptor-ref> </interceptor-stack> </interceptors> <action name="register" class="edu.hust.action.RegisterAction"> <result name="input">/register.jsp</result> <result>/result.jsp</result> <interceptor-ref name="myInterceptorStack"></interceptor-ref> </action> </package> </struts> |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<struts>
<package name="struts2" extends="struts-default"> <interceptors> <interceptor name="myInterceptor" class="edu.hust.interceptor.MyInterceptor"></interceptor> <interceptor-stack name="myInterceptorStack"> <interceptor-ref name="myInterceptor"></interceptor-ref> <interceptor-ref name="defaultStack"></interceptor-ref> </interceptor-stack> </interceptors> <!-- 此默認interceptor是針對所有action的 --> <!-- 如果某個action中引入了interceptor, 則在這個action中此默認interceptor就會失效 --> <default-interceptor-ref name="myInterceptorStack"></default-interceptor-ref> <action name="register" class="edu.hust.action.RegisterAction"> <result name="input">/register.jsp</result> <result>/result.jsp</result> </action> </package> </struts> |
看到網上很多介紹關於攔截器的文章,感覺都不錯,但是都沒有很詳細全面的介紹,所以我就博眾家之長,呵呵,寫了篇關於struts攔截器的東西。
攔截器的工作原理如上圖,在工作的時候每一個Action請求都被包裝在一堆攔截器的內部。攔截器可以在Action執行直線做相似的操作也可以在Action執行直后做回收操作。
每一個Action既可以將操作轉交給下面的攔截器,Action也可以直接退出操作返回客戶既定的畫面。
下面我們來講講如何使用struts2攔截器,或者是自定義攔截器。
先說說使用Struts自帶的攔截器:
在Struts2中已經在struts-default.xml中預定義了一些自帶的攔截器,如timer、params等。如果在標簽中繼承struts-default,則當前package就會自動擁有struts-default.xml中的所有配置。代碼如下:
...
在struts-default.xml中有一個默認的引用,在默認情況下(也就是中未引用攔截器時)會自動引用一些攔截器。這個默認的攔截器引用如下:
- <</span>interceptor-stack name="defaultStack">
- <</span>interceptor-ref name="exception"/>
- <</span>interceptor-ref name="alias"/>
- <</span>interceptor-ref name="servletConfig"/>
- <</span>interceptor-ref name="prepare"/>
- <</span>interceptor-ref name="i18n"/>
- <</span>interceptor-ref name="chain"/>
- <</span>interceptor-ref name="debugging"/>
- <</span>interceptor-ref name="profiling"/>
- <</span>interceptor-ref name="scopedModelDriven"/>
- <</span>interceptor-ref name="modelDriven"/>
- <</span>interceptor-ref name="fileUpload"/>
- <</span>interceptor-ref name="checkbox"/>
- <</span>interceptor-ref name="staticParams"/>
- <</span>interceptor-ref name="params">
- <</span>param name="excludeParams">dojo\..*</</span>param>
- </</span>interceptor-ref>
- <</span>interceptor-ref name="conversionError"/>
- <</span>interceptor-ref name="validation">
- <</span>param name="excludeMethods">input,back,cancel,browse</</span>param>
- </</span>interceptor-ref>
- <</span>interceptor-ref name="workflow">
- <</span>param name="excludeMethods">input,back,cancel,browse</</span>param>
- </</span>interceptor-ref>
- </</span>interceptor-stack>
上面在defaultStack中引用的攔截器都可以在中不經過引用就可以使用(如果在中引用了任何攔截器后,要使用在defaultStack中定義的攔截器,也需要在中重新引用,在后面的“二、通過請求調用Action的setter方法(params)”將詳細講解)。
下面我們來看幾個簡單的攔截器的使用方法。
一、記錄攔截器和execute方法的執行時間(timer攔截器)
timer是Struts2中最簡單的攔截器,這個攔截器對應的類是com.opensymphony.xwork2.interceptor.TimerInterceptor。它的功能是記錄execute方法和其他攔截器(在timer后面定義的攔截器)的intercept方法執行的時間總和。如下面的配置代碼所示:
- <</span>action name="first" class="action.FirstAction">
- <</span>interceptor-ref name="logger"/>
- <</span>interceptor-ref name="timer" />
- </</span>action>
由於在timer后面沒有其他的攔截器定義,因此,timer只能記錄execute方法的執行時間,在訪問first動作時,會在控制台輸出類似下面的一條信息:
信息: Executed action [/test/first!execute] took 16 ms.
在使用timer攔截器時,需要commons-logging.jar的支持。將logger引用放到timer的后面,就可以記錄logger攔截器的intercept方法和Action的execute方法的執行時間總和,代碼如下:
- <</span>action name="first" class="action.FirstAction">
- <</span>interceptor-ref name="timer" />
- <</span>interceptor-ref name="logger"/>
- </</span>action>
大家可以使用如下的Action類來測試一下timer攔截器:
- package action;
- import com.opensymphony.xwork2.ActionSupport;
- public class FirstAction extends ActionSupport
- {
- public String execute() throws Exception
- {
- 2000); // 延遲2秒
- return null;
- }
如果只記錄execute方法的執行時間,一般會輸出如下的信息:
信息: Executed action [/test/first!execute] took 2000 ms.
二、通過請求調用Action的setter方法(params)
當客戶端的一個form向服務端提交請求時,如有一個textfield,代碼如下:
- "/test">
- "name"/>
在提交后,Struts2將會自動調用first動作類中的setName方法,並將name文本框中的值通過setName方法的參數傳入。實際上,這個操作是由params攔截器完成的,params對應的類是com.opensymphony.xwork2.interceptor.ParametersInterceptor。由於params已經在defaultStack中定義,因此,在未引用攔截器的中是會自動引用params的,如下面的配置代碼,在訪問first動作時,Struts2是會自動執行相應的setter方法的。
... ...
但如果在中引用了其他的攔截器,就必須再次引用params攔截器,Struts2才能調用相應的setter方法。如下面的配置代碼所示:
- <</span>action name="first" class="action.FirstAction">
- <</span>interceptor-ref name="timer" />
- <</span>interceptor-ref name="params"/>
- </</span>action>
三、通過配置參數調用Action的setter方法(static-params)
static-params攔截器可以通過配置標簽來調用Action類的相應的setter方法,static-params攔截器對應的類是com.opensymphony.xwork2.interceptor.StaticParametersInterceptor。
下面配置代碼演示了如何使用static-params攔截器:
- <</span>action name="first" class="action.FirstAction">
- <</span>interceptor-ref name="timer" />
- <</span>param name="who">比爾</</span>param>
- <</span>interceptor-ref name="params"/>
- <</span>interceptor-ref name="static-params"/>
- </</span>action>
如果first動作使用上面的配置,在訪問first動作時,Struts2會自動調用setWho方法將“比爾”作為參數值傳入setWho方法。
四、使用攔截器棧
為了能在多個動作中方便地引用同一個或幾個攔截器,可以使用攔截器棧將這些攔截器作為一個整體來引用。攔截器棧要在標簽中使用和子標簽來定義。代碼如下:
- <</span>package name="demo" extends="struts-default" >
- <</span>interceptors>
- <</span>interceptor-stack name="mystack">
- <</span>interceptor-ref name="timer" />
- <</span>interceptor-ref name="logger" />
- <</span>interceptor-ref name="params" />
- <</span>interceptor-ref name="static-params" />
- </</span>interceptor-stack>
- </</span>interceptors>
- <</span>action name="first" class="action.FirstAction">
- <</span>param name="who">比爾</</span>param>
- <</span>interceptor-ref name="mystack"/>
- </</span>action>
- </</span>package>
這樣以來,我們就可以象使用攔截器一樣使用攔截器棧。
如何自定義一個攔截器?
自定義一個攔截器,我們需要三步就可以完成了:
1 自定義一個實現Interceptor接口(或者繼承自AbstractInterceptor)的類。
2 在strutx.xml中注冊上一步中定義的攔截器。
3 在需要使用的Action中引用上述定義的攔截器,為了方便也可將攔截器定義為默認的攔截器,這樣在不加特殊聲明的情況下所有的Action都被這個攔截器攔截。
Interceptor接口聲明了三個方法:
- public interface Interceptor extends Serializable {
- void destroy();
- void init();
- String intercept(ActionInvocation invocation) throws Exception;
- }
Init方法在攔截器類被創建之后,在對Action鏡像攔截之前調用,相當於一個post-constructor方法,使用這個方法可以給攔截器類做必要的初始話操作。
Destroy方法在攔截器被垃圾回收之前調用,用來回收init方法初始化的資源。
Intercept是攔截器的主要攔截方法,如果需要調用后續的Action或者攔截器,只需要在該方法中調用invocation.invoke()方法即可,在該方法調用的前后可以插入Action調用前后攔截器需要做的方法。如果不需要調用后續的方法,則返回一個String類型的對象即可,例如Action.SUCCESS。
另外AbstractInterceptor提供了一個簡單的Interceptor的實現,這個實現為:
- public abstract class AbstractInterceptor implements Interceptor {
- public void init() {
- public void destroy() {
- public abstract String intercept(ActionInvocation invocation) throws Exception;
- }
在不需要編寫init和destroy方法的時候,只需要從AbstractInterceptor繼承而來,實現intercept方法即可。
我們嘗試編寫一個Session過濾用的攔截器,該攔截器查看用戶Session中是否存在特定的屬性(LOGIN屬性)如果不存在,中止后續操作定位到LOGIN,否則執行原定操作,代碼為:
- public class CheckLoginInterceptor extends AbstractInterceptor {
- public static final String LOGIN_KEY = "LOGIN";
- public static final String LOGIN_PAGE = "global.login";
- public String intercept(ActionInvocation actionInvocation) throws Exception {
- System.out.println("begin check login interceptor!");
- // 對LoginAction不做該項攔截
- if (action instanceof LoginAction) {
- "exit check login, because this is login action.");
- return actionInvocation.invoke();
- // 確認Session中是否存在LOGIN
- String login = (String) session.get(LOGIN_KEY);
- if (login != null && login.length() > 0) {
- // 存在的情況下進行后續操作。
- "already login!");
- return actionInvocation.invoke();
- else {
- // 否則終止后續操作,返回LOGIN
- "no login, forward login page!");
- return LOGIN_PAGE;
- }
- }
注冊攔截器
- <</span>interceptors>
- <</span>interceptor
- class="com.jpleasure.teamware.util.CheckLoginInterceptor"/>
- <</span>interceptor-stack name="teamwareStack">
- <</span>interceptor-ref name="login"/>
- <</span>interceptor-ref name="defaultStack"/>
- </</span>interceptor-stack>
- </</span>interceptors>
將上述攔截器設定為默認攔截器:
- -interceptor-ref name="teamwareStack"/>
這樣在后續同一個package內部的所有Action執行之前都會被login攔截。
注冊並引用Interceptor
- <</span>package name="default" extends="struts-default">
- <</span>interceptors>
- <</span>interceptor name="timer" class=".."/>
- <</span>interceptor name="logger" class=".."/>
- </</span>interceptors>
- <</span>action name="login" class="tutorial.Login">
- <</span>interceptor-ref name="timer"/>
- <</span>interceptor-ref name="logger"/>
- <</span>result name="input">login.jsp</</span>result>
- <</span>result name="success"
- type="redirect-action">/secure/home</</span>result>
- </</span>action>
- </</span>package>
可以將多個攔截器合並在一起作為一個堆棧調用,當一個攔截器堆棧被附加到一個Action的時候,要想Action執行,必須執行攔截器堆棧中的每一個攔截器。
- <</span>package name="default" extends="struts-default">
- <</span>interceptors>
- <</span>interceptor name="timer" class=".."/>
- <</span>interceptor name="logger" class=".."/>
- <</span>interceptor-stack name="myStack">
- <</span>interceptor-ref name="timer"/>
- <</span>interceptor-ref name="logger"/>
- </</span>interceptor-stack>
- </</span>interceptors>
- <</span>action name="login" class="tutuorial.Login">
- <</span>interceptor-ref name="myStack"/>
- <</span>result name="input">login.jsp</</span>result>
- <</span>result name="success"
- type="redirect-action">/secure/home</</span>result>
- </</span>action>
- </</span>package>
每一個攔截器都可以配置參數,有兩種方式配置參數,一是針對每一個攔截器定義參數,二是針對一個攔截器堆棧統一定義所有的參數,例如:
- <</span>interceptor-ref name="validation">
- <</span>param name="excludeMethods">myValidationExcudeMethod</</span>param>
- </</span>interceptor-ref>
- <</span>interceptor-ref name="workflow">
- <</span>param name="excludeMethods">myWorkflowExcludeMethod</</span>param>
- </</span>interceptor-ref>
或者
- <</span>interceptor-ref name="defaultStack">
- <</span>param name="validation.excludeMethods">myValidationExcludeMethod</</span>param>
- <</span>param name="workflow.excludeMethods">myWorkflowExcludeMethod</</span>param>
- </</span>interceptor-ref>
每一個攔截器都有兩個默認的參數:
excludeMethods - 過濾掉不使用攔截器的方法和
includeMethods – 使用攔截器的方法。
需要說明的幾點:
1 攔截器執行的順序按照定義的順序執行,例如:
- <</span>interceptor-stack name="xaStack">
- <</span>interceptor-ref name="thisWillRunFirstInterceptor"/>
- <</span>interceptor-ref name="thisWillRunNextInterceptor"/>
- <</span>interceptor-ref name="followedByThisInterceptor"/>
- <</span>interceptor-ref name="thisWillRunLastInterceptor"/>
- </</span>interceptor-stack>
的執行順序為:
- thisWillRunNextInterceptor
- thisWillRunLastInterceptor
- MyAction2 (chain)
- MyResult (result)
- followedByThisInterceptor
- thisWillRunFirstInterceptor
2 使用默認攔截器配置每個Action都需要的攔截器堆棧,例如:
- <</span>action name="login" class="tutorial.Login">
- <</span>interceptor-ref name="timer"/>
- <</span>interceptor-ref name="logger"/>
- <</span>interceptor-ref name="default-stack"/>
- <</span>result name="input">login.jsp</</span>result>
- <</span>result type="redirect-action">/secure/home</</span>result>
- </</span>action>
可以按照如下的方式定義:
- <</span>interceptors>
- <</span>interceptor-stack name="myStack">
- <</span>interceptor-ref name="timer"/>
- <</span>interceptor-ref name="logger"/>
- <</span>interceptor-ref name="default-stack"/>
- </</span>interceptor-stack>
- </</span>interceptors>
- <</span>default-interceptor-ref name="myStack"/>
- <</span>action name="login" class="tutorial.Login">
- <</span>result name="input">login.jsp</</span>result>
- <</span>result type="redirect-action">/secure/home</</span>result>
- </</span>action>
3 如何訪問HttpServletRequest,HttpServletResponse或者HttpSession
有兩種方法可以達到效果,使用ActionContext:
- Map attibutes = ActionContext.getContext().getSession();
或者實現相應的接口:
- HttpServletRequest ServletRequestAware
- HttpServletResponse ServletResponseAware
Struts2(XWork)提供的攔截器的功能說明:
- Alias Interceptor——alias——在不同請求之間將請求參數在不同名字件轉換,請求內容不變
- Chaining Interceptor——chain——讓前一個Action的屬性可以被后一個Action訪問,現在和chain類型的result()結合使用。
- Checkbox Interceptor——checkbox——添加了checkbox自動處理代碼,將沒有選中的checkbox的內容設定為false,而html默認情況下不提交沒有選中的checkbox。
- Cookies Interceptor—— Cookies—— 使用配置的name,value來是指cookies
- Conversion Error Interceptor—— conversionError—— 將錯誤從ActionContext中添加到Action的屬性字段中。
- Create Session Interceptor—— createSession—— 自動的創建HttpSession,用來為需要使用到HttpSession的攔截器服務。
- Debugging Interceptor—— Debugging—— 提供不同的調試用的頁面來展現內部的數據狀況。
- Execute and Wait Interceptor—— execAndWait—— 在后台執行Action,同時將用戶帶到一個中間的等待頁面。
- Exception Interceptor—— exception—— 將異常定位到一個畫面
- File Upload Interceptor—— fileUpload—— 提供文件上傳功能
- I18n Interceptor—— i18n—— 記錄用戶選擇的locale
- Logger Interceptor—— logger—— 輸出Action的名字
- Message Store Interceptor—— store—— 存儲或者訪問實現ValidationAware接口的Action類出現的消息,錯誤,字段錯誤等。
- Model Driven Interceptor—— model-driven—— 如果一個類實現了ModelDriven,將getModel得到的結果放在Value Stack中。
- Scoped Model Driven—— scoped-model-driven—— 如果一個Action實現了ScopedModelDriven,則這個攔截器會從相應的Scope中取出model調用Action的setModel方法將其放入Action內部。
- Parameters Interceptor—— params—— 將請求中的參數設置到Action中去。
- Prepare Interceptor—— Prepare—— 如果Acton實現了Preparable,則該攔截器調用Action類的prepare方法。
- Scope Interceptor—— Scope—— 將Action狀態存入session和application的簡單方法。
- Servlet Config Interceptor—— servletConfig—— 提供訪問HttpServletRequest和HttpServletResponse的方法,以Map的方式訪問。
- Static Parameters Interceptor—— staticParams—— 從struts.xml文件中將中的中的內容設置到對應的Action中。
- Roles Interceptor—— roles—— 確定用戶是否具有JAAS指定的Role,否則不予執行。
- Timer Interceptor—— timer—— 輸出Action執行的時間
- Token Interceptor—— token—— 通過Token來避免雙擊
- Token Session Interceptor—— tokenSession—— 和Token Interceptor一樣,不過雙擊的時候把請求的數據存儲在Session中
- Validation Interceptor—— validation—— 使用action-validation.xml文件中定義的內容校驗提交的數據。
- Workflow Interceptor—— workflow—— 調用Action的validate方法,一旦有錯誤返回,重新定位到INPUT畫面
- Parameter Filter Interceptor—— N/A—— 從參數列表中刪除不必要的參數
- Profiling Interceptor—— profiling—— 通過參數激活profile
-
攔截器 名字 說明