Struts2的攔截器總結

Struts2的攔截器總結

攔截器的作用主要就是攔截東西,攔截什麼呢?當然是'action'了,在執行'action'之前 攔截器會起作用,執行一些預先處理的代碼,
接着區執行action中相關的方法,之後,流程又會回到攔截器裏面,接着去執行後續的一些操作。

先看配置,這些配置都是在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()方法之後也要執行。給出如下兩個攔截器說明:

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

2

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這兩個方法 可是又加入又排除到底執行嗎?答案是執行的,必定結果是最能說明問題的!呵呵!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章