struts2攔截器的使用

看到網上很多介紹關於攔截器的文章,感覺都不錯,但是都沒有很詳細全面的介紹,所以我就博衆家之長,呵呵,寫了篇關於struts攔截器的東西。


攔截器的工作原理如上圖,在工作的時候每一個Action請求都被包裝在一堆攔截器的內部。攔截器可以在Action執行直線做相似的操作也可以在Action執行直後做回收操作。

每一個Action既可以將操作轉交給下面的攔截器,Action也可以直接退出操作返回客戶既定的畫面。

下面我們來講講如何使用struts2攔截器,或者是自定義攔截器

先說說使用Struts自帶的攔截器:
在Struts2中已經在struts-default.xml中預定義了一些自帶的攔截器,如timer、params等。如果在<package>標籤中繼承struts-default,則當前package就會自動擁有struts-default.xml中的所有配置。代碼如下:

<package name="demo" extends="struts-default" > ... </package>

在struts-default.xml中有一個默認的引用,在默認情況下(也就是<action>中未引用攔截器時)會自動引用一些攔截器。這個默認的攔截器引用如下:

<interceptor-stack name="defaultStack">
    <interceptor-ref name="exception"/>
    <interceptor-ref name="alias"/>
    <interceptor-ref name="servletConfig"/>
    <interceptor-ref name="prepare"/>
    <interceptor-ref name="i18n"/>
    <interceptor-ref name="chain"/>
    <interceptor-ref name="debugging"/>
    <interceptor-ref name="profiling"/>
    <interceptor-ref name="scopedModelDriven"/>
    <interceptor-ref name="modelDriven"/>
    <interceptor-ref name="fileUpload"/>
    <interceptor-ref name="checkbox"/>
    <interceptor-ref name="staticParams"/>
    <interceptor-ref name="params">
      <param name="excludeParams">dojo\..*</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-stack>


上面在defaultStack中引用的攔截器都可以在<action>中不經過引用就可以使用(如果在<action>中引用了任何攔截器後,要使用在defaultStack中定義的攔截器,也需要在<action>中重新引用,在後面的“二、通過請求調用Action的setter方法(params)”將詳細講解)。
下面我們來看幾個簡單的攔截器的使用方法。

一、記錄攔截器和execute方法的執行時間(timer攔截器)

timer是Struts2中最簡單的攔截器,這個攔截器對應的類是com.opensymphony.xwork2.interceptor.TimerInterceptor。它的功能是記錄execute方法和其他攔截器(在timer後面定義的攔截器)的intercept方法執行的時間總和。如下面的配置代碼所示:

<action name="first" class="action.FirstAction">
    <interceptor-ref name="logger"/>
    <interceptor-ref name="timer" />
</action>


由於在timer後面沒有其他的攔截器定義,因此,timer只能記錄execute方法的執行時間,在訪問first動作時,會在控制檯輸出類似下面的一條信息:

信息: Executed action [/test/first!execute] took 16 ms.

在使用timer攔截器時,需要commons-logging.jar的支持。將logger引用放到timer的後面,就可以記錄logger攔截器的intercept方法和Action的execute方法的執行時間總和,代碼如下:

<action name="first" class="action.FirstAction">
    <interceptor-ref name="timer" />
    <interceptor-ref name="logger"/>
</action>


大家可以使用如下的Action類來測試一下timer攔截器:

package action;

import com.opensymphony.xwork2.ActionSupport;

public class FirstAction extends ActionSupport          

{
       public String execute() throws Exception

       {
           Thread.sleep(2000); // 延遲2秒
           return null;
       }

}


如果只記錄execute方法的執行時間,一般會輸出如下的信息:

信息: Executed action [/test/first!execute] took 2000 ms.

二、通過請求調用Action的setter方法(params)


    當客戶端的一個form向服務端提交請求時,如有一個textfield,代碼如下:

<s:form action="first" namespace="/test">
   <s:textfield name="name"/>
   <s:submit/>
</s:form>


在提交後,Struts2將會自動調用first動作類中的setName方法,並將name文本框中的值通過setName方法的參數傳入。實際上,這個操作是由params攔截器完成的,params對應的類是com.opensymphony.xwork2.interceptor.ParametersInterceptor。由於params已經在defaultStack中定義,因此,在未引用攔截器的<action>中是會自動引用params的,如下面的配置代碼,在訪問first動作時,Struts2是會自動執行相應的setter方法的。

<action name="first" class="action.FirstAction">

    ... ...

</action>

但如果在<action>中引用了其他的攔截器,就必須再次引用params攔截器,Struts2才能調用相應的setter方法。如下面的配置代碼所示:

<action name="first" class="action.FirstAction">
    <interceptor-ref name="timer" />
    <interceptor-ref name="params"/>
</action>


三、通過配置參數調用Action的setter方法(static-params)

    static-params攔截器可以通過配置<params>標籤來調用Action類的相應的setter方法,static-params攔截器對應的類是com.opensymphony.xwork2.interceptor.StaticParametersInterceptor。
    下面配置代碼演示瞭如何使用static-params攔截器:

<action name="first" class="action.FirstAction">
    <interceptor-ref name="timer" />
    <param name="who">比爾</param>
    <interceptor-ref name="params"/>
    <interceptor-ref name="static-params"/>
</action>


如果first動作使用上面的配置,在訪問first動作時,Struts2會自動調用setWho方法將“比爾”作爲參數值傳入setWho方法。

四、使用攔截器棧

爲了能在多個動作中方便地引用同一個或幾個攔截器,可以使用攔截器棧將這些攔截器作爲一個整體來引用。攔截器棧要在<package>標籤中使用<interceptors>和子標籤<interceptor-stack>來定義。代碼如下:

<package name="demo" extends="struts-default" >
    <interceptors>
        <interceptor-stack name="mystack">
            <interceptor-ref name="timer" />
            <interceptor-ref name="logger" />
            <interceptor-ref name="params" />
            <interceptor-ref name="static-params" />
        </interceptor-stack>
    </interceptors>

    <action name="first" class="action.FirstAction">
        <param name="who">比爾</param>
        <interceptor-ref name="mystack"/>            
    </action>
</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,否則執行原定操作,代碼爲:

 
<interceptors>
            <interceptor
name="login" 
class="com.jpleasure.teamware.util.CheckLoginInterceptor"/>
            <interceptor-stack name="teamwareStack">
                <interceptor-ref name="login"/>
                <interceptor-ref name="defaultStack"/>
            </interceptor-stack>
</interceptors>


將上述攔截器設定爲默認攔截器:

<default-interceptor-ref name="teamwareStack"/>


這樣在後續同一個package內部的所有Action執行之前都會被login攔截。

註冊並引用Interceptor

<package name="default" extends="struts-default">
   <interceptors>
       <interceptor name="timer" class=".."/>
       <interceptor name="logger" class=".."/>
   </interceptors>
 
   <action name="login" class="tutorial.Login">
        <interceptor-ref name="timer"/>
        <interceptor-ref name="logger"/>
        <result name="input">login.jsp</result>
        <result name="success"
            type="redirect-action">/secure/home</result>
   </action>
</package>
 


可以將多個攔截器合併在一起作爲一個堆棧調用,當一個攔截器堆棧被附加到一個Action的時候,要想Action執行,必須執行攔截器堆棧中的每一個攔截器。

Xml代碼 複製代碼
  1. <package name="default" extends="struts-default">  
  2.    <interceptors>  
  3.         <interceptor name="timer" class=".."/>  
  4.         <interceptor name="logger" class=".."/>  
  5.         <interceptor-stack name="myStack">  
  6.            <interceptor-ref name="timer"/>  
  7.            <interceptor-ref name="logger"/>  
  8.         </interceptor-stack>  
  9.     </interceptors>  
  10.     
  11.     <action name="login" class="tutuorial.Login">  
  12.          
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章