Struts2攔截器(Interceptor)原理詳解

1.    理解攔截器
1.1.    什麼是攔截器
攔截器,在AOP(Aspect-Oriented Programming)中用於在某個方法或字段被訪問之前,進行攔截然後在之前或之後加入某些操作。攔截是AOP的一種實現策略。
在Webwork的中文文檔的解釋爲——攔截器是動態攔截Action調用的對象。它提供了一種機制可以使開發者可以定義在一個action執行的前後執行的代碼,也可以在一個action執行前阻止其執行。同時也是提供了一種可以提取action中可重用的部分的方式。
談到攔截器,還有一個詞大家應該知道——攔截器鏈(Interceptor Chain,在Struts 2中稱爲攔截器棧Interceptor Stack)。攔截器鏈就是將攔截器按一定的順序聯結成一條鏈。在訪問被攔截的方法或字段時,攔截器鏈中的攔截器就會按其之前定義的順序被調用。
1.2.    攔截器的實現原理
大部分時候,攔截器方法都是通過代理的方式來調用的。Struts 2的攔截器實現相對簡單。當請求到達Struts 2的ServletDispatcher時,Struts 2會查找配置文件,並根據其配置實例化相對的攔截器對象,然後串成一個列表(list),最後一個一個地調用列表中的攔截器。如下圖:

2.    攔截器的配置
Struts 2已經爲您提供豐富多樣的,功能齊全的攔截器實現。大家可以至struts2的jar包內的struts-default.xml查看關於默認的攔截器與攔截器鏈的配置。
 
       在struts.xml文件中定義攔截器,攔截器棧:
< package   name ="my"   extends ="struts-default"   namespace ="/manage" >  
                < interceptors >  
                <!--  定義攔截器  --> 
                < interceptor   name ="攔截器名"   class ="攔截器實現類" />  
                <!--  定義攔截器棧  --> 
                < interceptor-stack   name ="攔截器棧名" >  
                          < interceptor-ref   name ="攔截器一" />  
                          < interceptor-ref   name ="攔截器二" />  
                </ interceptor-stack >  
                </ interceptors >  
                ...... 
</ package >  
 
3.    使用攔截器
一旦定義了攔截器和攔截器棧後,就可以使用這個攔截器或攔截器棧來攔截Action了。攔截器的攔截行爲將會在Action的exceute方法執行之前被執行。
< action   name ="userOpt"   class ="org.qiujy.web.struts2.action.UserAction" >  
                        < result   name ="success" > /success.jsp</ result >  
                        < result   name ="error" > /error.jsp</ result >  
<!--  使用攔截器,一般配置在result之後,  --> 
<!--  引用系統默認的攔截器  --> 
< interceptor-ref   name ="defaultStack" />  
                        < interceptor-ref   name ="攔截器名或攔截器棧名" />  
                </ action >  
 
       此處需要注意的是,如果爲Action指定了一個攔截器,則系統默認的攔截器棧將會失去作用 。爲了繼續使用默認攔截器,所以上面配置文件中手動引入了默認攔截器。
4.    自定義攔截器
作爲“框架(framework)”,可擴展性是不可或缺的。雖然,Struts 2爲我們提供如此豐富的攔截器實現,但是這並不意味我們失去創建自定義攔截器的能力,恰恰相反,在Struts 2自定義攔截器是相當容易的一件事。
  
4.1.    實現攔截器類
所有的Struts 2的攔截器都直接或間接實現接口com.opensymphony.xwork2.interceptor.Interceptor。該接口提供了三個方法:
1)      void init(); 在該攔截器被初始化之後,在該攔截器執行攔截之前,系統回調該方法。對於每個攔截器而言,此方法只執行一次。
2)      void destroy();該方法跟init()方法對應。在攔截器實例被銷燬之前,系統將回調該方法。
3)      String intercept(ActionInvocation invocation) throws Exception; 該方法是用戶需要實現的攔截動作。該方法會返回一個字符串作爲邏輯視圖。
除此之外,繼承類com.opensymphony.xwork2.interceptor.AbstractInterceptor是更簡單的一種實現攔截器類的方式,因爲此類提供了init()和destroy()方法的空實現,這樣我們只需要實現intercept方法。
4.2.    使用自定義攔截器:兩個步驟
l  通過<interceptor …>元素來定義攔截器。
l  通過<interceptor-ref …>元素來使用攔截器。
5.    自定義攔截器示例
5.1.    問題描述
使用自定義攔截器來完成用戶權限的控制:當瀏覽者需要請求執行某個操作時,應用需要先檢查瀏覽者是否登錄,以及是否有足夠的權限來執行該操作。
5.2.    實現權限控制攔截器類
AuthorizationInterceptor.java
package   org.qiujy.common; 
    
import   java.util.Map; 
    
import   com.opensymphony.xwork2.Action; 
import   com.opensymphony.xwork2.ActionInvocation; 
import   com.opensymphony.xwork2.interceptor.AbstractInterceptor; 
    
/** 
* 權限檢查攔截器 
*    
* @author qiujy 
* @version 1.0 
*/
 
public   class   AuthorizationInterceptor  extends   AbstractInterceptor { 
    
        /* 
         * 攔截Action處理的攔截方法 
         *    
         */
 
        public   String intercept(ActionInvocation invocation)  throws   Exception { 
                 
                Map session = invocation.getInvocationContext().getSession(); 
                String userName = (String) session.get("userName" ); 
                 
                if   (null   != userName && userName.equals("test" )) { 
                        System.out.println("攔截器:合法用戶登錄---" ); 
                        return   invocation.invoke(); 
                }  else   { 
                        System.out.println("攔截器:用戶未登錄---" ); 
                        return   Action.LOGIN; 
                } 
        } 
} 
 
 
5.3.    配置權限控制攔截器
struts.xml:
<!DOCTYPE struts PUBLIC 
                "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" 
                "http://struts.apache.org/dtds/struts-2.0.dtd"> 
< struts >  
        < package   name ="my"   extends ="struts-default" >  
                 
                < interceptors >  
                <!--  定義權限控制攔截器  --> 
                < interceptor   name ="authority"   class ="org.qiujy.common.AuthorizationInterceptor" />  
                </ interceptors >  
                 
                <!--  定義全局處理結果  --> 
                < global-results >  
                <!--  邏輯名爲login的結果,映射到/login.jsp頁面  --> 
                < result   name ="login" > /login.jsp</ result >  
                </ global-results >  
                 
                < action   name ="listall"   class ="org.qiujy.web.struts2.action.UserAction"   method ="listAllUser" >  
                        < result   name ="success" > /listall.jsp</ result >  
                        <!--  使用攔截器  --> 
                        < interceptor-ref   name ="defaultStack" />  
                        < interceptor-ref   name ="authority" />  
                </ action >  
                 
                < action   name ="userOpt"   class ="org.qiujy.web.struts2.action.UserAction" >  
                        < result   name ="success" > /success.jsp</ result >  
                </ action >  
        </ package >  
</ struts >  
 
    5.4.    運行調試
在瀏覽器地址欄直接輸入 http://localhost:8080/AuthorityInterceptorDemo/listall.action   來訪問,此動作配置了權限攔截器,所有被轉到登錄頁面。

登錄後:
 

如果爲了簡化struts.xml文件的配置,避免在每個Action重複配置該攔截器,可以將攔截器配置成了一個默認攔截器棧。如下:
<!DOCTYPE struts PUBLIC 
                "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" 
                "http://struts.apache.org/dtds/struts-2.0.dtd"> 
< struts >  
        < package   name ="my"   extends ="struts-default" >  
    
                < interceptors >  
                        <!--  定義權限控制攔截器  --> 
                        < interceptor   name ="authority"  
                                class ="org.qiujy.common.AuthorizationInterceptor"   />  
                        <!--  定義一個包含權限控制的攔截器棧  --> 
                        < interceptor-stack   name ="mydefault" >  
                                < interceptor-ref   name ="defaultStack"   />  
                                < interceptor-ref   name ="authority"   />  
                        </ interceptor-stack >  
                </ interceptors >  
                 
                <!--  定義默認攔截器  --> 
                < default-interceptor-ref   name ="mydefault"   />  
    
                <!--  定義全局處理結果  --> 
                < global-results >  
                        <!--  邏輯名爲login的結果,映射到/login.jsp頁面  --> 
                        < result   name ="login" > /login.jsp</ result >  
                </ global-results >  
    
                < action   name ="listall"  
                        class ="org.qiujy.web.struts2.action.UserAction"  
                        method ="listAllUser" >  
                        < result   name ="success" > /listall.jsp</ result >  
                </ action >  
        </ package >  
         
        < package   name ="font"   extends ="struts-default" >  
                < action   name ="userOpt"   class ="org.qiujy.web.struts2.action.UserAction" >  
                        < result   name ="success" > /success.jsp</ result >  
                </ action >  
        </ package >  
</ struts >  
 
一旦在某個包下定義了默認攔截器棧,在該包下的所有action都會使用此攔截器棧。對於那些不想使用些攔截器棧的action,則應該將它放置在其它的包下。

本文來自CSDN博客,轉載請標明出處: http://blog.csdn.net/qjyong/archive/2007/10/14/1824607.aspx
發佈了15 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章