Struts2攔截器的運用

一、什麼是攔截器?

提到攔截器,使我不得不 想起武俠劇中劫匪們常說的一句話:“此山是我開,此樹是我栽,要打此路過,留下買路財!”。難不成程序中也有“打劫”的,說的沒錯,攔截器就是個打劫的。 在現實生活中,劫匪劫的大都是錢財,當然也有別的什麼,那麼程序中的“劫匪”劫的又是什麼呢?或者說程序中爲什麼需要它?在我們的日常編程中少不了寫一些 重複的代碼,例如在一個地方中寫了一段代碼,後來發現這段代碼在其它地方中同樣需要,在傳統的編程中我們一定會採取複製、粘貼的辦法。如果這段代碼只在這 一兩個處需要,我們採取這種辦法,還說的過去,但是如果系統對這段代碼過於依賴,也就是這段代碼在系統中出現的過多,如果那一天我們發現這段代碼中在某些 地方還需要完善,我們是不是要着個修改它們呢?我估計沒有人會這麼做,它嚴重違反了軟件開發中一條非常重要的DRY規則,不寫重複代碼。說了這麼多你一定知道我們爲什麼需要在程序中弄一個“劫匪”了吧。這個“劫匪”就是並不是劫取什麼東西,只是爲了在某個程序執行前後,動態的增加一些功能(以前所寫通用代碼塊)或進行一些檢查工作。那麼這個攔截器到底是怎麼實現的呢?實際上它是用Java中的動態代理來實現的。

二、攔截器在Struts2中的應用

對於Struts2框架而言,正是大量的內置攔截器完成了大部分操作。像params攔截器將http請求中參數解析出來賦值給Action中對應的屬性。Servlet-config攔截器負責把請求中HttpServletRequest實例和HttpServletResponse實例傳遞給Action……struts2內置的攔截器有很多,在此我就不一一列舉了

那麼怎麼在struts2中定義自己的攔截器呢?

    很簡單Struts2爲我們提供了一個Interceptor接口,該接口源代碼如下:

publicinterfaceInterceptorextends Serializable {

    void destroy();

    void init();

    String intercept(ActionInvocation invocation)throws Exception;

}

1)   init():在攔截器執行之前調用,主要用於初始化系統資源。

2)   destroty():與init()對應,用於攔截器執行之後銷燬資源。

3)   intercept():攔截器的核心方法,實現具體的攔截操作。與action一樣,該方法也返回一個字符串作爲邏輯視圖。如果攔截器成功調用了action,則返回一個真正的,也就是該action中execute()方法返回的邏輯視圖,反之,則返回一個自定義的邏輯視圖。

通常我們使用攔截器並不需要申請資源,爲此Struts2還爲我們提供了一個AbstractInterceptor類,該類的init()和destroy()都是空實現。我們開發自己的攔截器只需要繼承這個類就行了。

    下面創建一個判斷用戶是否登錄的攔截器。代碼如下:

@SuppressWarnings("serial")
public class AuthInterceptor extends AbstractInterceptor {
        public String intercept(ActionInvocation actionInvocation) throws Exception {
                 System.out.println("-------AuthInterceptor-------");
               //檢查Session中是否存在user
               Map map = actionInvocation.getInvocationContext().getSession();
              if(map.get("user")==null){
              // 否則終止後續操作,返回LOGIN
                        return Action.INPUT;
               }else{
              //存在的情況下進行後續操作
                       return actionInvocation.invoke();
           }
      }
}

 

    創建好攔截器後,還不能使用,還需要我們在struts.xml中配置一下。

  下面看一下怎麼配置攔截器。

<interceptors>

           <interceptor name="auth" class="com.cyd.interceptor.AuthInterceptor"></interceptor>

</interceptors>

   這個定義好的攔截器在Action中怎麼使用呢?使用方法很簡單,如下:

<action name="userManager" class="com.cyd.action.UserManagerAction" method="del">

                 <result name="success">..</result>
                 <result name="input">/index.jsp</result>

                <interceptor-ref name="defaultStack"></interceptor-ref>

 </action> 

  一旦我們爲某個action引用了自定義的攔截器,struts2默認的攔截器就不會再起作用,因此還需要引用默認攔截器。

<action name="userManager" class="com.cyd.action.UserManagerAction" method="del">

                 <result name="success">..</result>
                 <result name="input">/index.jsp</result>

                <interceptor-ref name="defaultStack"></interceptor-ref>

                <interceptor-ref name="defaultStack" />

</action>

   但是我們這麼做似乎也不太方便,因爲如果攔截器auth需要被多個action引用的話,每一個都要配置一遍太麻煩了。我們可以把它定義成默認的攔截器。

 <interceptors>
            <!-- 定義攔截器 -->
           <interceptor name="auth" class="com.cyd.interceptor.AuthInterceptor"></interceptor>

            <!-- 定義一個攔截器棧,包含多個攔截器 -->
          <interceptor-stack name="myDefault"> 
                 <interceptor-ref name="auth"></interceptor-ref>
                <interceptor-ref name="defaultStack"></interceptor-ref>
         </interceptor-stack>

 </interceptors>

<default-interceptor-refname="mydefault"/>

   另外,struts2還爲我們提供了一個方法過濾的攔截器MethodFilterInterceptor類,該類繼承AbstractInterceptor類,重寫了intercept(ActionInvocation invocation)並提供了一個新的方法doInterceptor(ActionInvocation invocation)抽象方法。該類的使用方法很簡單,就不舉例了。這個攔截器與以往的攔截器配置有所不同。那就是可以指定哪些方法需要被攔截,那些不需要。通常在引用該攔截器時指定。

<interceptor-refname="  ">

       <paramname="exculdeMethods"></param>

       <paramname="includeMethods"></param>    

</interceptor-ref>

   exculdeMethods:是不被攔截的方法,如果有多個以逗號分隔。

   includeMethods:需要被攔截的方法,如果有多個以逗號分隔。

 

     下面我來實驗下。我們寫個攔截器棧
    <struts>
    <package name="default" extends="struts-default">
    
        <interceptors>
            <!-- 定義攔截器 -->
      <interceptor name="auth" class="com.cyd.interceptor.AuthInterceptor"></interceptor>
      <interceptor-stack name="myDefault"> 
    <interceptor-ref name="auth"></interceptor-ref>
          <interceptor-ref name="defaultStack"></interceptor-ref>
   </interceptor-stack>
  </interceptors>
  
  <default-interceptor-ref name="myDefault"></default-interceptor-ref>
  <!-- 攔截器必須要定義在action的上面 -->
  
        <action name="login" class="com.cyd.action.LoginAction" method="login">
            <result name="success">/view/menu/index.jsp</result>
            <result name="input">/index.jsp</result>
            <interceptor-ref name="defaultStack"></interceptor-ref>
        </action>
       
        <action name="userManager" class="com.cyd.action.UserManagerAction" method="del">
        </action>
       
   </package>
   
</struts>
  

上面的配置只有當用戶登錄的時候,不用攔截,除了登錄以外的所有的action都需要攔截。(因爲登錄的時候session一定是沒有user的,所以就沒有必要攔截,

如果攔截的話,永遠也不會登錄成功)

 

攔截器幾乎完成了Struts2框架70%的工作,包括解析請求參數、將請求參數賦值給Action屬性、執行數據校驗、文件上傳……,Struts2設計的靈巧性,更大程度地得益於攔截器設計,當需要擴展Struts2功能時,只需要提供對應攔截器,並將它配置在Struts2容器中即可;如果不需要該功能時,也只需要取消該攔截器的配置即可。這種可插拔式的設計,正是軟件設計領域一直孜孜以求的目標。

實際上,Struts2的精髓就在於攔截器,掌握了Struts2的攔截器機制,你就可以說精通了Struts2。
從某個角度來看,我們可以把Struts2框架理解成一個空殼,而這些攔截器像一個一個抽屜,隨時可以
插進入,也可以拔出來——這是軟件產品一直追求的目標。
如果你喜歡,你可以把Struts2的全部插件拔出,那麼Struts2就成了一個空容器——
而這種空,正是 Struts2的魅力,你可以把任何自己想要的東西填入進去,甚至包括自己完全實現這個框架。

另一方面,因爲Struts2的插件機制,Struts2提供了無限擴展的可能性,你可以把自己想要的任何
東西做成插件,然後填入Struts2——這樣的結果是:一個企業,一個團隊,可以把自己業務相關的東西
做成插件,隨時隨地地複用。
也就是說:如果你想要,你可以把Struts2改造成屬於自己的框架。

當然,Struts2也內建了大量的攔截器,這些攔截器以name-class對的形式配置在struts-default. xml文件中,其中name是攔截器的名字,就是以後使用該攔截器的唯一標識;class則指定了該攔截器的實現類,如果我們定義的package繼承了Struts2的默認struts-default包,則可以自由使用下面定義的攔截器,否則必須自己定義這些攔截器。
下面是Struts2內建攔截器的簡要介紹:
alias:實現在不同請求中相似參數別名的轉換。
autowiring:這是個自動裝配的攔截器,主要用於當Struts2和Spring整合時,Struts2可以使用自動裝配的方式來訪問Spring容器中的Bean。
chain:構建一個Action鏈,使當前Action可以訪問前一個Action的屬性,一般和<result type="chain" .../>一起使用。
conversionError:這是一個負責處理類型轉換錯誤的攔截器,它負責將類型轉換錯誤從ActionContext中取出,並轉換成Action的FieldError錯誤。
createSession:該攔截器負責創建一個HttpSession對象,主要用於那些需要有HttpSession對象才能正常工作的攔截器中。
debugging:當使用Struts2的開發模式時,這個攔截器會提供更多的調試信息。
execAndWait:後臺執行Action,負責將等待畫面發送給用戶。
exception:這個攔截器負責處理異常,它將異常映射爲結果。
fileUpload:這個攔截器主要用於文件上傳,它負責解析表單中文件域的內容。 
i18n:這是支持國際化的攔截器,它負責把所選的語言、區域放入用戶Session中。
logger:這是一個負責日誌記錄的攔截器,主要是輸出Action的名字。
model-driven:這是一個用於模型驅動的攔截器,當某個Action類實現了ModelDriven接口時,它負責把getModel()方法的結果堆入ValueStack中。
scoped-model-driven:如果一個Action實現了一個ScopedModelDriven接口,該攔截器負責從指定生存範圍中找出指定的Modol,並將通過setModel方法將該Model傳給Action實例。
params:這是最基本的一個攔截器,它負責解析HTTP請求中的參數,並將參數值設置成Action對應的屬性值。
prepare:如果action實現了Preparable接口,將會調用該攔截器的prepare()方法。
static-params:這個攔截器負責將xml中<action>標籤下<param>標籤中的參數傳入action。
scope:這是範圍轉換攔截器,它可以將Action狀態信息保存到HttpSession範圍,或者保存到ServletContext範圍內。
servlet-config:如果某個Action需要直接訪問Servlet API,就是通過這個攔截器實現的。
注意:儘量避免在Action中直接訪問Servlet API,這樣會導致Action與Servlet的高耦合。
roles:這是一個JAAS(Java Authentication and Authorization Service,Java授權和認證服務)攔截器,只有當瀏覽者取得合適的授權後,纔可以調用被該攔截器攔截的Action。
timer:這個攔截器負責輸出Action的執行時間,這個攔截器在分析該Action的性能瓶頸時比較有用。
token:這個攔截器主要用於阻止重複提交,它檢查傳到Action中的token,從而防止多次提交。
token-session:這個攔截器的作用與前一個基本類似,只是它把token保存在HttpSession中。
validation:通過執行在xxxAction-validation.xml中定義的校驗器,從而完成數據校驗。
workflow:這個攔截器負責調用Action類中的validate方法,如果校驗失敗,則返回input的邏輯視圖。
大部分時候,開發者無需手動控制這些攔截器,因爲struts-default.xml文件中已經配置了這些攔截器,只要我們定義的包繼承了系統的struts-default包,就可以直接使用這些攔截器。

當然,Struts2的攔截器機制並不是來自於Struts1,而是來自於WebWork。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章