詳解Struts2攔截器機(jī)制

?????Struts2的核心在于它復(fù)雜的攔截器,幾乎70%的工作都是由攔截器完成的枝誊。比如我們之前用于將上傳的文件對(duì)應(yīng)于action實(shí)例中的三個(gè)屬性的fileUpload攔截器宝恶,還有用于將表單頁(yè)面的http請(qǐng)求參數(shù)設(shè)置成action中對(duì)應(yīng)的屬性的param攔截器等烙丛〖拦。總之,在整個(gè)Struts框架中攔截器的作用是相當(dāng)大的,本篇將從以下幾點(diǎn)詳細(xì)介紹下有關(guān)Struts攔截器的內(nèi)容:

  • 攔截器在Struts中的作用
  • 自定義攔截器實(shí)現(xiàn)類
  • 配置攔截器(包含配置默認(rèn)攔截器)
  • 引用攔截器
  • 配置攔截指定方法的攔截器
  • 攔截器的攔截順序

一蛆橡、攔截器在Struts中的作用
?????在我們的web.xml中舌界,我們配置了一個(gè)過(guò)濾器,實(shí)現(xiàn)將所有請(qǐng)求交付StrutsPrepareAndExecuteFilter類泰演。一旦接受到任意action的請(qǐng)求呻拌,該類會(huì)創(chuàng)建和初始化一個(gè)ActionProxy實(shí)例,它代理了具體的action睦焕,在其中我們可以添加任意攔截器在execute方法執(zhí)行之前和之后做一些額外的操作藐握,最終會(huì)調(diào)用該action實(shí)例的execute方法,為用戶返回視圖結(jié)果字符串垃喊,然后系統(tǒng)會(huì)根據(jù)該視圖結(jié)果字符串調(diào)取相應(yīng)的視圖頁(yè)面猾普。下圖是攔截器和action之間的關(guān)系:

這里寫(xiě)圖片描述

這是一種典型的AOP思想,當(dāng)我們?cè)赟truts.xml中定義一個(gè)包的時(shí)候本谜,大部分情況下我們會(huì)繼承struts-default文件初家,所以雖然我們?cè)谧约旱呐渲梦募胁](méi)有手動(dòng)配置任何的攔截器,但是我們創(chuàng)建的action卻被很多攔截器攔截處理乌助,就是因?yàn)閟truts-default中配置的攔截器生效了溜在。Struts中內(nèi)建了很多的攔截器,他們大多被配置在struts-default文件中他托,詳細(xì)的內(nèi)建攔截器的介紹可以參考官方API掖肋,接下來(lái)我們看如何自定義一個(gè)攔截器。

二赏参、自定義攔截器實(shí)現(xiàn)類
?????想要實(shí)現(xiàn)自己的攔截器類只需要實(shí)現(xiàn) com.opensymphony.xwork2.interceptor.Interceptor.Interceptor 接口即可志笼,該接口中有如下幾個(gè)方法:

  public abstract void destroy();
  
  public abstract void init();
  
  public abstract String intercept(ActionInvocation paramActionInvocation)
    throws Exception;

init 方法在執(zhí)行攔截方法之前回調(diào),主要用于初始化一些資源登刺,destroy 與init 方法對(duì)應(yīng)籽腕,在攔截器實(shí)例被銷毀之前回調(diào),主要用于釋放在init 方法中打開(kāi)的資源纸俭。intercept 方法是我們的攔截方法皇耗,我們可以重寫(xiě)該方法來(lái)完成對(duì)action實(shí)例的攔截,該方法具有一個(gè)ActionInvocation 類型的參數(shù)揍很,該參數(shù)內(nèi)部引用了具體的action實(shí)例對(duì)象(如果該action還有其他攔截器的話)郎楼,我們可以調(diào)用該參數(shù)的invoke方法調(diào)用具體action實(shí)例的execute方法或者調(diào)用下一個(gè)攔截器,intercept方法返回一個(gè)String 類型的字符串代表了具體視圖頁(yè)面窒悔。下面看個(gè)具體的例子:

public class TestAction extends ActionSupport {

    public String execute(){
        System.out.println("執(zhí)行execute方法......");
        return SUCCESS;
    }
}
public class MyIntercept implements Interceptor {

    public void init() {}
    public void destroy() {}

    public String intercept(ActionInvocation action) throws Exception{
        System.out.println("攔截action開(kāi)始.......");
        String result = action.invoke();
        System.out.println("攔截action結(jié)束.......");
        return result;
    }
}

省略了配置攔截器和TestAction 的代碼呜袁,下圖是上述程序運(yùn)行的結(jié)果截圖:

這里寫(xiě)圖片描述

三、配置和引用攔截器
?????上述的示例定義了一個(gè)簡(jiǎn)單的攔截器實(shí)現(xiàn)類简珠,我們省略了在struts.xml中配置和引用該攔截器的代碼阶界,本小節(jié)將詳細(xì)的介紹如何在struts.xml中定義和引用我們自定義實(shí)現(xiàn)的攔截器類虹钮。

從struts-default.xml中我們可以看出來(lái),我們使用<interceptors>元素定義攔截器name和物理位置的配對(duì)膘融,例如:

<interceptors>
    <interceptor name="test" class="MyPackage.TestAction"/>
    ......
    ......
</interceptors>

上述代碼定義了一個(gè)攔截器test芙粱,它對(duì)應(yīng)于具體的一個(gè)class。需要注意的是氧映,定義攔截器的元素 interceptors 及其子元素必須被配置在某個(gè)package包下春畔。

以上只是定義了一個(gè)攔截器和具體攔截器實(shí)現(xiàn)類之間的映射關(guān)系,但是想要實(shí)現(xiàn)對(duì)某個(gè)具體的action的攔截需要使用元素<interceptor-ref>根據(jù)name屬性值引用一個(gè)上述已經(jīng)定義了的攔截器岛都。例如:

<action name="test" class="MyPackage.TestAction">
    <interceptor-ref name="test"/>
    <result name="success">/index.jsp</result>
    ......
    ......
</action>

正如上述代碼展示的一樣律姨,該元素用于引用一個(gè)已經(jīng)定義好了的攔截器,并且該元素出現(xiàn)在具體的action內(nèi)部臼疫,表明了該action具有一個(gè)test攔截器择份。以上代碼實(shí)現(xiàn)了對(duì)單個(gè)攔截器的定義和引用,其實(shí)對(duì)于攔截器棧(一堆攔截器的組合)來(lái)說(shuō)配置也是類似的多矮。定義一個(gè)攔截器棧的代碼是如下的:

<interceptor-stack name="攔截器棧名">
    interceptor-ref name="攔截器一"/>
    interceptor-ref name="攔截器二"/>
    interceptor-ref name="攔截器三"/>
    .....
</interceptor-stack>

引用一個(gè)攔截器棧就沒(méi)什么區(qū)別了:

interceptor-ref name="攔截器棧名"/>

當(dāng)然我們也可以通過(guò)

<default-interceptor-ref name="攔截器名"/>

配置默認(rèn)攔截器或者攔截器棧缓淹,如果該包下某個(gè)action沒(méi)有顯式指定攔截器,那么就會(huì)調(diào)用該默認(rèn)攔截器塔逃,否則如果顯式配置了攔截器讯壶,那么默認(rèn)攔截器將會(huì)失效。

四湾盗、為Action中指定方法配置攔截器
?????在默認(rèn)情況下伏蚊,我們?yōu)閍ction配置了攔截器之后,該攔截器將會(huì)攔截該action中所有的方法格粪,這有時(shí)候會(huì)給我們帶來(lái)麻煩躏吊,當(dāng)然struts為我們提供API用來(lái)針對(duì)具體的某個(gè)方法配置攔截器。這里涉及到一個(gè)抽象類:MethodFilterInterceptor帐萎。該類實(shí)際上實(shí)現(xiàn)了Interceptor并完成了一些默認(rèn)實(shí)現(xiàn)比伏,我們簡(jiǎn)單看看其中的代碼:

public abstract class MethodFilterInterceptor
  extends AbstractInterceptor
{
//該set集合保存了該攔截器不需要攔截的所有方法
  protected Set<String> excludeMethods = Collections.emptySet();
  //該set集合保存了所有該攔截器需要攔截的方法
  protected Set<String> includeMethods = Collections.emptySet();
  //省略getter,setter方法
  
  //用于攔截action的入口
  public String intercept(ActionInvocation invocation)
    throws Exception
  {
    if (applyInterceptor(invocation)) {
      return doIntercept(invocation);
    }
    return invocation.invoke();
  }
  
  //判斷當(dāng)前需要調(diào)用的action處理邏輯方法是否需要被此攔截器攔截
  protected boolean applyInterceptor(ActionInvocation invocation)
  {
    String method = invocation.getProxy().getMethod();
    
    boolean applyMethod = MethodFilterInterceptorUtil.applyMethod(this.excludeMethods, this.includeMethods, method);
    if ((this.log.isDebugEnabled()) && 
      (!applyMethod)) {
      this.log.debug("Skipping Interceptor... Method [" + method + "] found in exclude list.", new String[0]);
    }
    return applyMethod;
  }
  
  //這是需要我們重寫(xiě)的方法疆导,具體作用下文介紹
  protected abstract String doIntercept(ActionInvocation paramActionInvocation)
    throws Exception;
}

從上述代碼中可以看出赁项,該抽象類實(shí)現(xiàn)了Interceptor接口并完成了基本的實(shí)現(xiàn)。除此之外澈段,該類提供了兩個(gè)集合用于保存該攔截器需要攔截的所有方法和不需要攔截的所有方法悠菜,攔截器入口intercept中會(huì)首先判斷此次請(qǐng)求action實(shí)例中的邏輯處理方法是否需要被該攔截器攔截,如果需要被攔截败富,那么將會(huì)調(diào)用doIntercept我們自己實(shí)現(xiàn)的攔截器邏輯悔醋。否則直接調(diào)用invoke方法執(zhí)行處理邏輯。所以一般來(lái)說(shuō)兽叮,我們只需要重寫(xiě)doIntercept方法完成攔截器的核心處理即可芬骄。

當(dāng)然此處需要注意一點(diǎn)的是猾愿,用于判斷當(dāng)前請(qǐng)求的處理邏輯方法是否需要被該攔截器攔截的方法applyInterceptor是在intercept中進(jìn)行校驗(yàn)的,也就是說(shuō)在執(zhí)行doIntercept方法之前excludeMethods和includeMethods的值應(yīng)當(dāng)是已經(jīng)初始化完畢了的德玫。所以我們?cè)赿oIntercept中再次為這兩個(gè)屬性賦值是沒(méi)用的匪蟀,因?yàn)橐呀?jīng)完成了校驗(yàn)椎麦。一般我們?cè)趕truts.xml中為這兩個(gè)屬性賦值宰僧,因?yàn)樵撆渲梦募窍缺患虞d的。下面我們看個(gè)實(shí)例:

//自定義一個(gè)攔截器
public class MyIntercept extends MethodFilterInterceptor {

    protected  String doIntercept(ActionInvocation action)
            throws Exception{
        System.out.println("攔截開(kāi)始......");
        String result = action.invoke();
        System.out.println("攔截結(jié)束......");
        return result;
    }
}
//引用該攔截器并指定不需要攔截的方法
<action name="test" class="MyPackage.TestAction">
    <interceptor-ref name="test">
                <param name="excludeMethods">execute</param>
    </interceptor-ref>
    <result name="success">/index.jsp</result>
</action>

下面我們看運(yùn)行的結(jié)果截圖:

這里寫(xiě)圖片描述

顯然我們指明了該攔截器不用攔截方法execute观挎,當(dāng)然結(jié)果顯示的也是如我們所愿琴儿。如果我們修改上述struts.xml中內(nèi)容:

<action name="test" class="MyPackage.TestAction">
    <interceptor-ref name="test">
        <param name="includeMethods">execute</param>
    </interceptor-ref>
    <result name="success">/index.jsp</result>
</action>

我們指定該execute方法是需要被攔截器攔截的,下面運(yùn)行的結(jié)果截圖:

這里寫(xiě)圖片描述

當(dāng)然如果需要指定多個(gè)方法需要被攔截或者不用被攔截嘁捷,可以使用英文逗號(hào)隔開(kāi)這些方法造成,例如:

<param name="includeMethods">方法一,方法二,方法三</param>

最后還有一點(diǎn)是:如果一個(gè)方法既被放在了includeMethods中也被放在了excludeMethods中,那么框架將會(huì)選擇攔截該方法雄嚣。

五晒屎、有關(guān)攔截器機(jī)制的其他一些細(xì)節(jié)
?????攔截器的執(zhí)行順序是按照引用攔截器的順序決定的,例如我們定義兩個(gè)攔截器:

<action name="test" class="MyPackage.TestAction">
    <interceptor-ref name="test"/>
    <interceptor-ref name="test2"/>
    <result name="success">/index.jsp</result>
</action>
這里寫(xiě)圖片描述

也就是說(shuō)第一個(gè)攔截器攔截action之后缓升,會(huì)調(diào)用invoke方法鼓鲁,如果還有其他攔截器則會(huì)調(diào)用下一個(gè)攔截器,一層層嵌套港谊,最后結(jié)束最外層的攔截器骇吭。

上述實(shí)例中我們使用param參數(shù)為攔截器類中的includeMethods屬性賦值,但是如果是一個(gè)攔截器棧中我們有該如何為其中某個(gè)具體的攔截器屬性賦值呢歧寺?

<interceptor-ref name="攔截器棧">
    <param name="攔截器一.屬性名">屬性值</param>
</interceptor-ref>

至此燥狰,我們簡(jiǎn)單了解了有關(guān)struts2中攔截器器的相關(guān)知識(shí),如需深刻理解還要在具體項(xiàng)目中體會(huì)斜筐,總結(jié)不到之處龙致,望海涵!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末顷链,一起剝皮案震驚了整個(gè)濱河市目代,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蕴潦,老刑警劉巖像啼,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異潭苞,居然都是意外死亡忽冻,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門此疹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)僧诚,“玉大人遮婶,你說(shuō)我怎么就攤上這事『浚” “怎么了旗扑?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)慈省。 經(jīng)常有香客問(wèn)我臀防,道長(zhǎng),這世上最難降的妖魔是什么边败? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任袱衷,我火速辦了婚禮,結(jié)果婚禮上笑窜,老公的妹妹穿的比我還像新娘致燥。我一直安慰自己,他們只是感情好排截,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布嫌蚤。 她就那樣靜靜地躺著,像睡著了一般断傲。 火紅的嫁衣襯著肌膚如雪脱吱。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,071評(píng)論 1 285
  • 那天艳悔,我揣著相機(jī)與錄音急凰,去河邊找鬼。 笑死猜年,一個(gè)胖子當(dāng)著我的面吹牛抡锈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播乔外,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼床三,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了杨幼?” 一聲冷哼從身側(cè)響起撇簿,我...
    開(kāi)封第一講書(shū)人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎差购,沒(méi)想到半個(gè)月后四瘫,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡欲逃,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年找蜜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片稳析。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡洗做,死狀恐怖弓叛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情诚纸,我是刑警寧澤撰筷,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站畦徘,受9級(jí)特大地震影響毕籽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜旧烧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一影钉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧掘剪,春花似錦、人聲如沸奈虾。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)肉微。三九已至匾鸥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間碉纳,已是汗流浹背勿负。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留劳曹,地道東北人奴愉。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓壳快,卻偏偏與公主長(zhǎng)得像井濒,于是被迫代替她去往敵國(guó)和親俺抽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子肯腕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 攔截器是Struts2框架的核心祟偷,它主要完成解析請(qǐng)求參數(shù)剥扣、將請(qǐng)求參數(shù)賦值給Action屬性宜鸯、執(zhí)行數(shù)據(jù)校驗(yàn)坎怪、文件上傳...
    重山楊閱讀 3,925評(píng)論 2 13
  • 概述 什么是Struts2的框架Struts2是Struts1的下一代產(chǎn)品岖沛,是在 struts1和WebWork的...
    inke閱讀 2,242評(píng)論 0 50
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理暑始,服務(wù)發(fā)現(xiàn),斷路器婴削,智...
    卡卡羅2017閱讀 134,600評(píng)論 18 139
  • 本文包括: 1廊镜、Struts 2 概述2、Struts 2 快速入門3馆蠕、Struts 2 的執(zhí)行流程4期升、配置 st...
    廖少少閱讀 2,949評(píng)論 3 13
  • (一)Struts乓序、Spring、Hibernate坎背、Mybatis框技術(shù) 1.Struts2.0有幾種標(biāo)簽庫(kù) 【...
    獨(dú)云閱讀 3,226評(píng)論 0 62