1. 程式人生 > >過濾器(Filter)和攔截器(Interceptor)

過濾器(Filter)和攔截器(Interceptor)

Filter介紹
Filter可以認為是Servlet的一種“加強版”,它主要用於對使用者請求進行預處理,也可以對HttpServletResponse進行後處理,是個典型的處理鏈。Filter也可以對使用者請求生成響應,這一點與Servlet相同,但實際上很少會使用Filter向用戶請求生成響應。使用Filter完整的流程是:Filter對使用者請求進行預處理,接著將請求交給Servlet進行預處理並生成響應,最後Filter再對伺服器響應進行後處理。

Filter有如下幾個用處。

在HttpServletRequest到達Servlet之前,攔截客戶的HttpServletRequest。
根據需要檢查HttpServletRequest,也可以修改HttpServletRequest頭和資料。
在HttpServletResponse到達客戶端之前,攔截HttpServletResponse。
根據需要檢查HttpServletResponse,也可以修改HttpServletResponse頭和資料。
Filter有如下幾個種類。

使用者授權的Filter:Filter負責檢查使用者請求,根據請求過濾使用者非法請求。
日誌Filter:詳細記錄某些特殊的使用者請求。
負責解碼的Filter:包括對非標準編碼的請求解碼。
能改變XML內容的XSLT Filter等。
Filter可以負責攔截多個請求或響應;一個請求或響應也可以被多個Filter攔截。
建立一個Filter只需兩個步驟

建立Filter處理類
web.xml檔案中配置Filter
建立Filter必須實現javax.servlet.Filter介面,在該介面中定義瞭如下三個方法。

void init(FilterConfig config):用於完成Filter的初始化。
void destory():用於Filter銷燬前,完成某些資源的回收。
void doFilter(ServletRequest request,ServletResponse response,FilterChain chain):實現過濾功能,該方法就是對每個請求及響應增加的額外處理。該方法可以實現對使用者請求進行預處理(ServletRequest request),也可實現對伺服器響應進行後處理(ServletResponse response)—它們的分界線為是否呼叫了chain.doFilter(),執行該方法之前,即對使用者請求進行預處理;執行該方法之後,即對伺服器響應進行後處理。

Interceptor介紹
攔截器,在AOP(Aspect-Oriented Programming)中用於在某個方法或欄位被訪問之前,進行攔截,然後在之前或之後加入某些操作。攔截是AOP的一種實現策略。

 在WebWork的中文文件的解釋為—攔截器是動態攔截Action呼叫的物件。它提供了一種機制可以使開發者可以定義在一個Action執行的前後執行的程式碼,也可以在一個Action執行前阻止其執行。同時也提供了一種可以提取Action中可重用的部分的方式。

 攔截器將Action共用的行為獨立出來,在Action執行前後執行。這也就是我們所說的AOP,它是分散關注的程式設計方法,它將通用需求功能從不相關類之中分離出來;同時,能夠共享一個行為,一旦行為發生變化,不必修改很多類,只要修改這個行為就可以。

 攔截器將很多功能從我們的Action中獨立出來,大量減少了我們Action的程式碼,獨立出來的行為就有很好的重用性。

 當你提交對Action(預設是.action結尾的url)的請求時,ServletDispatcher會根據你的請求,去排程並執行相應的Action。在Action執行之前,呼叫被Interceptor擷取,Interceptor在Action執行前後執行。

 建立Interceptor必須實現com.opensymphony.xwork2.interceptor.Interceptor介面,該介面定義瞭如下三個方法。

void init():在該攔截器被例項化之後,在該攔截器執行攔截之前,系統將回調該方法。對於每個攔截器而言,其init()方法只執行一次。因此,該方法的方法體主要用於初始化資源。
void destory():該方法與init()方法對應。在攔截器例項被銷燬之前,系統將回調該攔截器的destory方法,該方法用於銷燬在init方法裡開啟的資源。
String intercept(ActionInvocation invocation):該方法是使用者需要實現的攔截動作。就像Action的execute方法一樣。intercept方法會返回一個字串作為邏輯檢視。如果該方法直接返回了一個字串,系統會將跳轉到該邏輯檢視對應的實際檢視資源,不會呼叫被攔截的Action。該方法的ActionInvocation引數包含了被攔截的Action的引用,可以通過呼叫該引數的invoke方法,將控制權轉給下一個攔截器,或者轉給Action的execute方法(如果該攔截器後沒有其他攔截器,則直接執行Action的execute方法)。

Filter和Interceptor的區別
Filter是基於函式回撥(doFilter()方法)的,而Interceptor則是基於Java反射的(AOP思想)。
Filter依賴於Servlet容器,而Interceptor不依賴於Servlet容器。
Filter對幾乎所有的請求起作用,而Interceptor只能對action請求起作用。
Interceptor可以訪問Action的上下文,值棧裡的物件,而Filter不能。
在action的生命週期裡,Interceptor可以被多次呼叫,而Filter只能在容器初始化時呼叫一次。
Filter和Interceptor的執行順序
過濾前-攔截前-action執行-攔截後-過濾後

一些理解:

但凡跟servlet有關——引數url-pattern指定的目標,都可以用filter。
至於interceptor,通常的場景是利用反射來管理某個類的方法。比如但凡Service的save.*和delete.*的方法都必須開啟事務處理,所有Dao方法丟擲異常時統一處理等。
但是Action/controller比較特殊,因為它既是類的方法,又是對映到某個url上,容易讓人困惑。

比如登陸校驗,沒有登陸的全部跳轉到一個錯誤頁面
比如後臺安全校驗,安全校驗不通過的跳轉到一個錯誤頁面

其實兩種都可以,

用filter過濾url。拿原始的web資源比較方便。
用interceptor過濾方法。拿request和response不一定方便,但訪問spring的資源方便。