JAVA & XML & JAVASCRIPT & AJAX & CSS

          Web 2.0 技術(shù)儲備............

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            77 隨筆 :: 17 文章 :: 116 評論 :: 0 Trackbacks

          轉(zhuǎn)自(http://samyulong.javaeye.com/blog/217092)

          一、什么是攔截器?

          提到攔截器,使我不得不 想起武俠劇中劫匪們常說的一句話:“此山是我開,此樹是我栽,要打此路過,留下買路財!”。難不成程序中也有“打劫”的,說的沒錯,攔截器就是個打劫的。 在現(xiàn)實生活中,劫匪劫的大都是錢財,當(dāng)然也有別的什么,那么程序中的“劫匪”劫的又是什么呢?或者說程序中為什么需要它?在我們的日常編程中少不了寫一些 重復(fù)的代碼,例如在一個地方中寫了一段代碼,后來發(fā)現(xiàn)這段代碼在其它地方中同樣需要,在傳統(tǒng)的編程中我們一定會采取復(fù)制、粘貼的辦法。如果這段代碼只在這 一兩個處需要,我們采取這種辦法,還說的過去,但是如果系統(tǒng)對這段代碼過于依賴,也就是這段代碼在系統(tǒng)中出現(xiàn)的過多,如果那一天我們發(fā)現(xiàn)這段代碼中在某些 地方還需要完善,我們是不是要著個修改它們呢?我估計沒有人會這么做,它嚴(yán)重違反了軟件開發(fā)中一條非常重要的DRY規(guī)則,不寫重復(fù)代碼。說了這么多你一定知道我們?yōu)槭裁葱枰诔绦蛑信粋€“劫匪”了吧。這個“劫匪”就是并不是劫取什么東西,只是為了在某個程序執(zhí)行前后,動態(tài)的增加一些功能(以前所寫通用代碼塊)或進行一些檢查工作。那么這個攔截器到底是怎么實現(xiàn)的呢?實際上它是用Java中的動態(tài)代理來實現(xiàn)的。

          二、攔截器在Struts2中的應(yīng)用

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

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

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

          publicinterface Interceptor extends Serializable {

              void destroy();

              void init();

              String intercept(ActionInvocation invocation) throws Exception;

          }

          1)    init():在攔截器執(zhí)行之前調(diào)用,主要用于初始化系統(tǒng)資源。

          2)    destroty():init()對應(yīng),用于攔截器執(zhí)行之后銷毀資源。

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

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

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

          import java.util.Map;
          import com.opensymphony.xwork2.Action;
          import com.opensymphony.xwork2.ActionInvocation;
          import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

          @SuppressWarnings(
          "serial")
          public class CheckLoginInterceptor extends AbstractInterceptor {

              @SuppressWarnings(
          "unchecked")
              
          public String intercept(ActionInvocation actionInvocation) throws Exception {
                   System.out.println(
          "begin check login interceptor!");

                      
          // 檢查Session中是否存在user

                      Map session 
          = actionInvocation.getInvocationContext().getSession();

                      String username 
          = (String) session.get("user");

                      
          if (username != null && username.length() > 0) {

                          
          // 存在的情況下進行后續(xù)操作。

                          System.out.println(
          "already login!");

                          
          return actionInvocation.invoke();

                      } 
          else {

                          
          // 否則終止后續(xù)操作,返回LOGIN

                          System.out.println(
          "no login, forward login page!");

                          
          return Action.LOGIN;

                      }

                  }

              }
              創(chuàng)建好攔截器后,還不能使用,還需要我們在struts.xml中配置一下。

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

          <interceptors>

                     <interceptor name="checkLogin" class="com.myblog.interceptor.CheckLoginInterceptor" />

          </interceptors>

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

          <action name=" " class=" " >

                     <result> </result>

                     <interceptor-ref name="checkLogin" />

          </action>

             一旦我們?yōu)槟硞€action引用了自定義的攔截器,struts2默認(rèn)的攔截器就不會再起作用,因此還需要引用默認(rèn)攔截器。

          <action name=" " class=" " >

                     <result> </result>

                     <interceptor-ref name="checkLogin" />

                               <interceptor-ref name="defaultStack" />

          </action>

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

          <interceptors>

                     <interceptor name="checkLogin" class="com.myblog.interceptor.CheckLoginInterceptor" />

                     <!—-定義一個攔截器棧-->

                     <interceptor-stack name="mydefault">

                        <interceptor-ref name="defaultStack" />

                        <interceptor-ref name="checkLogin" />

                     </interceptor-stack>

          </interceptors>

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

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

          <interceptor-ref name="  ">

                 <param name="exculdeMethods"></param>

                 <param name="includeMethods"></param>    

          </interceptor-ref>

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

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

           



              下面我來實驗下。我們寫個攔截器棧
             

          <interceptors>
             
          <interceptor name="authorize" class="com.struts2.interceptor.AuthorizeInterceptor" />
             
          <interceptor-stack name="appStack">
                
          <!-- 你自定義的 -->
                
          <interceptor-ref name="authorize"/>
                
          <!-- 系統(tǒng)內(nèi)置的攔截器棧 -->
                
          <interceptor-ref name="defaultStack"/>
             
          </interceptor-stack>
          </interceptors>
          <action name="forward" class="com.struts2.RequestForward">
             
          <interceptor-ref name="appStack"/>
             
          <result name="index">index.jsp</result>
             
          <result name="NOT_FOUND">not_found.jsp</result>
          </action>
              恩,還是有點很迷茫的位置,比說的攔截器的調(diào)用順序是根據(jù)xml里面的順序來的嗎?還有可以指定只在action之前或者只在action之后調(diào)用嗎?說實話我也搞不清楚,在運用的過程中,大家慢慢在來體會


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

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

          另一方面,因為Struts2的插件機制,Struts2提供了無限擴展的可能性,你可以把自己想要的任何
          東西做成插件,然后填入Struts2——這樣的結(jié)果是:一個企業(yè),一個團隊,可以把自己業(yè)務(wù)相關(guān)的東西
          做成插件,隨時隨地地復(fù)用。
          也就是說:如果你想要,你可以把Struts2改造成屬于自己的框架。

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

          當(dāng)然,Struts2的攔截器機制并不是來自于Struts1,而是來自于WebWork。


          posted on 2009-03-02 11:31 Web 2.0 技術(shù)資源 閱讀(1054) 評論(0)  編輯  收藏 所屬分類: Struts2

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 上林县| 桓仁| 泊头市| 湟源县| 项城市| 噶尔县| 彰武县| 合水县| 莫力| 额济纳旗| 青海省| 永修县| 稻城县| 阳泉市| 新余市| 景德镇市| 沾化县| 光山县| 芜湖县| 柳江县| 南昌市| 赣榆县| 揭阳市| 北碚区| 宜阳县| 平阴县| 特克斯县| 吉隆县| 溆浦县| 克什克腾旗| 万全县| 建水县| 汤原县| 陇南市| 高阳县| 罗田县| 会同县| 澜沧| 海城市| 南投市| 诸城市|