SSH:Struts2框架(攔截器)

      攔截器的作用主要就是攔截東西,攔截什麼呢?當然是'action'了,在執行'action'之前 攔截器會起作用,執行一些預先處理的代碼, 
接着區執行action中相關的方法,之後,流程又會回到攔截器裏面,接着去執行後續的一些操作。
 如果你對MVC框架模式不是很瞭解,在看下面的講解之前我建議你先在這裏查看進行學習:  http://blog.csdn.net/qq_27550755/article/details/49924617




先看配置,這些配置都是在struts.xml裏面的。配置相當簡單,不過底層都是很複雜的。在這章之前,我專門看了下動態代理,感覺真的是開發者花了不少的心血, 

首先先建一個包,放我們的interceptor。 
過濾器和攔截器是非常相似的,public interface Filter類裏面有三個方法: 
init(FilterConfig filterConfig),destroy(),doFilter(ServletRequest request,ServletResponse response,FilterChain chain), 
這裏面的doFilter()方法是最重要的,在struts2中就相當於攔截的那個方法。 

先寫一個攔截器,在struts2中要實現一個接口 這個接口是什麼呢?在哪呢?是webwork是我們以前聽的最多的關於攔截器的框架, 
struts2用了其中一個核心的東西,這個東西在是什麼呢?是xwork恩,有了它纔可以攔截,好了我們在哪找呢? 
在com.opensymphony.xwork2.interceptor中找,裏面有個Interceptor 這是個接口,裏面也有三個方法, 
有init,destroy和intercept三個方法,而在struts2裏面的所有的攔截器都繼承這個接口! 

就依照這個接口寫一個攔截器類,呵呵! 
package com.interceptor; 
import com.opensymphony.xwork2.ActionInvocation; 
import com.opensymphony.xwork2.interceptor.Interceptor; 

public class MyInterceptor implements Interceptor{ 
    private String hello;//一定要寫 
    get和set方法 
    public void destroy() { 
       System.out.println("destory"); 
    } 
    public void init() { 
       System.out.println("init"); 
    } 
    public String intercept(ActionInvocation invoker) throws Exception { 
       System.out.println("intercept"); 
       String result=invoker.invoke(); 
    //  System.out.println("finish1"); 
       return result; 
    } 


爲了看這些是怎麼實現的,加入了一些打印! 
Intercept方法返回一個字符串,這個裏面最重要的是ActionInvocation 也是個抽象的接口,裏面有個invoke() 方法 
          作用:Invokes the next step in processing this ActionInvocation. 即調用下一個攔截器,如果有的話! 
爲了,讓struts2知道我們寫了個攔截器,就在struts。Xml中配置一下。 
<package name="struts2" extends="struts-default"> 
<interceptors> 
   <interceptor name="myinterceptor" class="com.interceptor.MyInterceptor"> 
              <param name="hello">world</param> 
           </interceptor> 
</interceptors> 

註釋:action是寫的一個註冊頁面,也可以隨便用個action 在這個點上是不影響需要檢驗結果的 

<action name="register" class="com.test.action.RegisterAction" > 
           <result name="input">/register.jsp</result> 
           <result name="success">/success.jsp</result> 
</package> 

好了到了這裏 攔截器也配置好了,但是攔截器是攔截action的,怎麼才能讓action被攔截呢? 
一般的情況下,放在result後面 怎麼寫呢?好了,如下: 
<interceptor-ref name="myinterceptor"> 
</interceptor-ref> 

這樣就可以讓aciton被攔截了,到此,好了,可以運行程序了: 
輸出結果是:啓動服務器init被打出 
運行後提交action 輸出intercept 
這個就是初步的一個攔截器。 



=======在此可能出現一個問題,是什麼呢?如果就我們做的登陸而言,當然登陸大家都做的很多了,可以想一下,有數據轉換,有驗證數據是否符合我們的要求==== 

Ok 如果按照上述運行的話,當數據轉換,驗證出錯的時候,就不會有提示,爲什麼呢? 這裏就和struts2的默認攔截器有關係! 

這裏可以打開一個文件看一下,看了就會明白,是什麼文件呢?struts-default。Xml 
這裏定義的很多的東西,和我們的程序相關的非常緊密 
首先這裏有個 
<package name="struts-default" abstract="true">和struts.Xml裏面的 
<package name="struts2" extends="struts-default">有什麼一樣呢?很明顯可以猜到struts.Xml中繼承的就是default。Xml中的struts-default。 
這個裏面還有個<interceptors>和</interceptors>這個是定義攔截器的,仔細看可以發現裏面有個validation 如此可以猜想, 
validation 也是定義的一個攔截器,可是最後當登陸出錯後沒有提示信息呢?肯定是相關的東西沒有執行,以前的執行了,現在沒執行, 
在新加了個攔截器後,這樣說明了,是現有的攔截器取代了原有的攔截器,這個是我僅能想到的!結果就是這個樣子的。那麼我們手工吧把原來的默認攔截器加入,這樣可以嗎? 
答案是可以的!添加如下! 

接着上面result後面添加一個把! 
<interceptor-ref name="defaultStack"></interceptor-ref> 

這樣還可以說明:如果我們沒有添加攔截器的話,默認的攔截器會自動添加到裏面。 


攔截器棧 
過濾器可以組成過濾器鏈,就是可以有多個過濾器來去過濾一個組件,攔截器也是,只不過是叫攔截器棧(相當於串攔截器)。 
攔截器棧先把攔截器逐個執行,接着執行action方法,之後又按照相反的順序回到最後的一個攔截器,再回到視圖。 

攔截器棧是怎麼構成的呢?繼續看struts-default.Xml這個文件!裏面有這些東西: 
            <interceptor-stack name="defaultStack"> 
                <interceptor-ref name="static-params"/> 
                <interceptor-ref name="params"/> 
                <interceptor-ref name="conversionError"/> 
            </interceptor-stack> 

  <interceptor-stack name="validationWorkflowStack"> 
                <interceptor-ref name="defaultStack"/> 
                <interceptor-ref name="validation"/> 
                <interceptor-ref name="workflow"/> 
           </interceptor-stack> 

這裏面看見了 棧是什麼樣的結構,是由很多個預先定義好的攔截器構成,而且也可以再加上攔截器棧組成,就如此就組成了! 



還有這行代碼: 
<default-class-ref class="com.opensymphony.xwork2.ActionSupport" /> 
這個是定義默認的攔截器,竟然是默認的當然只可能有一個!是把! 

好了,到了這裏,就來有進一步學習struts2的攔截器把!讓我們自己配置自己的攔截器棧! 
在開始 的時候我們添加的第一個myinterceptor攔截器的時候我添加了一個參數 

<param name="hello">world</param> 這裏我們可以通過配置文件,給攔截器添加一個參數,那這個在攔截器中怎麼取得的呢? 
瞭解過濾器的朋友都知道,裏面有個init(FilterConfig filterConfig)方法這樣可以取值,而在struts2中沒有這麼麻煩,做法嗎, 
上面其實已經給出來了! 
private String hello; 
    get和set方法 

寫個變量,然後加上get和set方法,當然變量的名字必須和設定的參數是相同的,這個是賦值成功的前提條件 

此時,運行,成功輸出:world   這裏的參數使用是在定義攔截器的時候,還有一種是在使用攔截器的時候添加參數。怎麼做呢? 

定義攔截器的情況: 

<interceptor name="myinterceptor" class="com.interceptor.MyInterceptor"> 
              <param name="hello">world</param> 
</interceptor> 

使用攔截器的時候的情況: 
<interceptor-ref name="myinterceptor"> 
              <param name="hello">zhuxinyu</param> 
</interceptor-ref> 

這下知道了嗎,還有,當出現如上引用的時候給同樣的參數設置了不同的值,會顯示那一個呢,在運行的時候? 
結果是:zhuxinyu  很明顯 覆蓋了第一個  結論是:使用的時候比定義的時候更加厲害,這叫撒,縣官不如現管! 
好了,把這些零散的東西搞完了,真的開始解決更多的知識! 

攔截器棧,在struts2裏面,其實是把攔截器和攔截器棧一樣的對待。可以把攔截器棧當作一個攔截器看待,同樣的引用。 
現在定義一個攔截器棧把! 

同樣在<interceptors> </interceptors>裏面定義 

<interceptor-stack name="mystack"> 
           <interceptor-ref name="myinterceptor"></interceptor-ref> 
           <interceptor-ref name="defaultStack"></interceptor-ref> 
</interceptor-stack> 

看見了沒,一個引用第一次定義的myinterceptor攔截器,一個引用默認的攔截器,怎麼引用呢,和開始的一個樣,呵呵! 

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

呵呵 ,這樣看是不是比剛纔簡單呢?把兩次引用換成一次!運行結果呢?和上次一樣,而且都成功! 

當然我們也可以自己定義一個默認的攔截器,這樣在程序中怎麼做呢?呵呵,定義如下 
<default-interceptor-ref name="mystack"></default-interceptor-ref> 
這裏引用的就是上面的mystack攔截器,這樣在程序中如果不在action中加入攔截器,它同樣可以執行相應的工作, 
前面已經說過了,如果不加入任何攔截器的引用,它將把默認的攔截器加入。 


我們在做攔截器的時候,剛纔實現了Interceptor接口,裏面有三個方法,但是一般的情況下init()和destroy()方法我們用不上, 
最關心的就是intercept(ActionInvocation invoker){}方法,所以怎麼辦呢?其實,struts2給我們提供了一個簡化的攔截器類,這個是什麼呢? 

MethodFilterInterceptor  這是一個抽象的類,裏面實現了init()和destroy()方法,所以只要我們繼承這個類,就不用再多寫這兩個方法! 

爲了驗證是對的,就寫了個方法,實現如下: 

public class MyInterceptor2 extends AbstractInterceptor{ 
  protected String doIntercept(ActionInvocation invocation) throws Exception { 
       System.out.println("my interceptor2"); 
       String result=invocation.invoke(); 
       return result; 
    } 


就是這樣一個簡單的東西,呵呵,把它和其他的攔截器一樣的配置,運行,呵呵就可以出來結果了! 
當然在這裏還需要指出一點,你安放的攔截器的順序,其實也就是攔截器執行的順序!但是攔截器,不只是在執行execute()方法之前要執行, 
而且在execute()方法之後也要執行。給出如下兩個攔截器說明: 


public String intercept(ActionInvocation invoker) throws Exception { 
       System.out.println("intercept1"); 
       String result=invoker.invoke(); 
       System.out.println("finish1"); 
       return result; 
    } 



public String intercept(ActionInvocation invoker) throws Exception { 
       System.out.println("intercept2"); 
       String result=invoker.invoke(); 
       System.out.println("finish2"); 
       return result; 
    } 

在配置順序也是一二,結果會輸出什麼呢? 

intercept1  intercept2 finish2  finish1  這裏執行攔截器的過程是正着來的,回來的時候是反着的。就像你要進一個很多門的房間一樣。 
進去一個,開一個門,爲了讓自己能回來的方便一些,這個打開的門就不要關着了,當你把所有的門進去了後,然後回來,再逐個關門。 
這樣的過程就像是這個攔截器執行的過程。 

最後講一個方法過濾攔截器,顧名思義,過濾的是方法。其實在struts2中可以在一個action類中寫很多個與aciton的execute方法類似的方法。 
只要在struts。Xml中的action添加一個屬性就可以了這個屬性是method比如: 

<action name="register"class="com.test.action.RegisterAction" method="test">當然在action類中也有個test()方法 

這個攔截器可以細化到攔截到具體的哪一個方法。如果不是方法過濾攔截器 哪麼它可能將與execute()方法類似的方法都執行。 
比如說上面的test()方法。如此這樣照成很多的不必要。於是這種攔截器就顯的格外的重要。 
在這個類繼承後實現的不是inteceptor()方法而是doIntercept(),可是做好這個類後如何配置繼承MethodFilterInterceptor這個類呢? 
如下(爲了實現過濾方法加入了幾個參數,其他的都相同): 

<interceptor-ref name="myinterceptor2"> 
              <param name="includeMethods">execute,test</param> 
</interceptor-ref> 

includeMethods  包含execute,test這兩個方法,結果執行了這個攔截器,如果改成excludeMethods ,就不會執行了,也可以再加下面的一個參數 
<param name="excludeMethods">execute,test</param> 
不排除execute,test這兩個方法 可是又加入又排除到底執行嗎?答案是執行的,必定結果是最能說明問題的!呵呵! 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章