過濾器(Filter)和 攔截器(Interceptor ) 的區別

過濾器(Filter)

Servlet中的過濾器Filter是實現了javax.servlet.Filter接口的服務器端程序,主要的用途是設置字符集、控制權限、控制轉向、做一些業務邏輯判斷等。其工作原理是,只要你在web.xml文件配置好要攔截的客戶端請求,它都會幫你攔截到請求,此時你就可以對請求或響應(Request、Response)統一設置編碼,簡化操作;同時還可進行邏輯判斷,如用戶是否已經登陸、有沒有權限訪問該頁面等等工作。它是隨你的web應用啓動而啓動的,只初始化一次,以後就可以攔截相關請求,只有當你的web應用停止或重新部署的時候才銷燬。

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

Filter有如下幾個用處:
  1. 在HttpServletRequest到達Servlet之前,攔截客戶的HttpServletRequest。
  2. 根據需要檢查HttpServletRequest,也可以修改HttpServletRequest頭和數據。
  3. 在HttpServletResponse到達客戶端之前,攔截HttpServletResponse。
  4. 根據需要檢查HttpServletResponse,也可以修改HttpServletResponse頭和數據。

·

Filter有如下幾個種類:
  1. 用戶授權的Filter:Filter負責檢查用戶請求,根據請求過濾用戶非法請求。
  2. 日誌Filter:詳細記錄某些特殊的用戶請求。
  3. 負責解碼的Filter:包括對非標準編碼的請求解碼。
  4. 能改變XML內容的XSLT Filter等。
  5. Filter可以負責攔截多個請求或響應;一個請求或響應也可以被多個Filter攔截。

·

創建一個Filter只需兩個步驟
  1. 創建Filter處理類
  2. web.xml文件中配置Filter

創建Filter必須實現javax.servlet.Filter接口,在該接口中定義瞭如下三個方法。

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

攔截器(Interceptor)

攔截器是在面向切面編程中應用的,就是在你的service或者一個方法前調用一個方法,或者在方法後調用一個方法。是基於JAVA的反射機制。攔截器不是在web.xml,比如struts在struts.xml中配置。

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

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

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

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

當你提交對Action(默認是.action結尾的url)的請求時,ServletDispatcher會根據你的請求,去調度並執行相應的Action。在Action執行之前,調用被Interceptor截取,Interceptor在Action執行前後執行。

SpringMVC 中的Interceptor 攔截請求是通過HandlerInterceptor 來實現的。在SpringMVC 中定義一個Interceptor 非常簡單,主要有兩種方式,第一種方式是要定義的Interceptor類要實現了Spring 的HandlerInterceptor 接口,或者是這個類繼承實現了HandlerInterceptor 接口的類,比如Spring 已經提供的實現了HandlerInterceptor 接口的抽象類HandlerInterceptorAdapter ;第二種方式是實現Spring的WebRequestInterceptor接口,或者是繼承實現了WebRequestInterceptor的類。

(1 )preHandle (HttpServletRequest request, HttpServletResponse response, Object handle) 方法,顧名思義,該方法將在請求處理之前進行調用。SpringMVC 中的Interceptor 是鏈式的調用的,在一個應用中或者說是在一個請求中可以同時存在多個Interceptor 。每個Interceptor 的調用會依據它的聲明順序依次執行,而且最先執行的都是Interceptor 中的preHandle 方法,所以可以在這個方法中進行一些前置初始化操作或者是對當前請求的一個預處理,也可以在這個方法中進行一些判斷來決定請求是否要繼續進行下去。該方法的返回值是布爾值Boolean類型的,當它返回爲false 時,表示請求結束,後續的Interceptor 和Controller 都不會再執行;當返回值爲true 時就會繼續調用下一個Interceptor 的preHandle 方法,如果已經是最後一個Interceptor 的時候就會是調用當前請求的Controller 方法。

(2 )postHandle (HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView) 方法,由preHandle 方法的解釋我們知道這個方法包括後面要說到的afterCompletion 方法都只能是在當前所屬的Interceptor 的preHandle 方法的返回值爲true 時才能被調用。postHandle 方法,顧名思義就是在當前請求進行處理之後,也就是Controller 方法調用之後執行,但是它會在DispatcherServlet 進行視圖返回渲染之前被調用,所以我們可以在這個方法中對Controller 處理之後的ModelAndView 對象進行操作。postHandle 方法被調用的方向跟preHandle 是相反的,也就是說先聲明的Interceptor 的postHandle 方法反而會後執行,這和Struts2 裏面的Interceptor 的執行過程有點類型。Struts2 裏面的Interceptor 的執行過程也是鏈式的,只是在Struts2 裏面需要手動調用ActionInvocation 的invoke 方法來觸發對下一個Interceptor 或者是Action 的調用,然後每一個Interceptor 中在invoke 方法調用之前的內容都是按照聲明順序執行的,而invoke 方法之後的內容就是反向的。

(3 )afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法,該方法也是需要當前對應的Interceptor 的preHandle 方法的返回值爲true 時纔會執行。顧名思義,該方法將在整個請求結束之後,也就是在DispatcherServlet 渲染了對應的視圖之後執行。這個方法的主要作用是用於進行資源清理工作的。

攔截器(Interceptor)和過濾器(Filter)的區別

Spring的Interceptor(攔截器)與Servlet的Filter有相似之處,比如二者都是AOP編程思想的體現,都能實現權限檢查、日誌記錄等。不同的是:
在這裏插入圖片描述

攔截器(Interceptor)和過濾器(Filter)的執行順序:
過濾前-攔截前-Action處理-攔截後-過濾後

攔截器(Interceptor)使用

interceptor 的執行順序大致爲:

  1. 請求到達 DispatcherServlet
  2. DispatcherServlet 發送至 Interceptor ,執行 preHandle
  3. 請求達到 Controller
  4. 請求結束後,postHandle 執行

Spring 中主要通過 HandlerInterceptor 接口來實現請求的攔截,實現 HandlerInterceptor 接口需要實現下面三個方法:

  • preHandle() – 在handler執行之前,返回 boolean 值,true 表示繼續執行,false 爲停止執行並返回。
  • postHandle() – 在handler執行之後, 可以在返回之前對返回的結果進行修改
  • afterCompletion() – 在請求完全結束後調用,可以用來統計請求耗時等等 統計請求耗時
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class ExecuteTimeInterceptor extends HandlerInterceptorAdapter{

    private static final Logger logger = Logger.getLogger(ExecuteTimeInterceptor.class);

    //before the actual handler will be executed
    public boolean preHandle(HttpServletRequest request,
        HttpServletResponse response, Object handler)
        throws Exception {

        long startTime = System.currentTimeMillis();
        request.setAttribute("startTime", startTime);

        return true;
    }

    //after the handler is executed
    public void postHandle(
        HttpServletRequest request, HttpServletResponse response,
        Object handler, ModelAndView modelAndView)
        throws Exception {

        long startTime = (Long)request.getAttribute("startTime");

        long endTime = System.currentTimeMillis();

        long executeTime = endTime - startTime;

        //modified the exisitng modelAndView
        modelAndView.addObject("executeTime",executeTime);

        //log it
        if(logger.isDebugEnabled()){
           logger.debug("[" + handler + "] executeTime : " + executeTime + "ms");
        }
    }
} 

使用mvc:interceptors標籤來聲明需要加入到SpringMVC攔截器鏈中的攔截器

<mvc:interceptors>  
<!-- 使用bean定義一個Interceptor,直接定義在mvc:interceptors根下面的Interceptor將攔截所有的請求 -->  
<bean class="com.company.app.web.interceptor.AllInterceptor"/>  
    <mvc:interceptor>  
         <mvc:mapping path="/**"/>  
         <mvc:exclude-mapping path="/parent/**"/>  
         <bean class="com.company.authorization.interceptor.SecurityInterceptor" />  
    </mvc:interceptor>  
    <mvc:interceptor>  
         <mvc:mapping path="/parent/**"/>  
         <bean class="com.company.authorization.interceptor.SecuritySystemInterceptor" />  
    </mvc:interceptor>  
</mvc:interceptors>

可以利用mvc:interceptors標籤聲明一系列的攔截器,然後它們就可以形成一個攔截器鏈,攔截器的執行順序是按聲明的先後順序執行的,先聲明的攔截器中的preHandle方法會先執行,然而它的postHandle方法和afterCompletion方法卻會後執行。

在mvc:interceptors標籤下聲明interceptor主要有兩種方式:
  1. 直接定義一個Interceptor實現類的bean對象。使用這種方式聲明的Interceptor攔截器將會對所有的請求進行攔截。
  2. 使用mvc:interceptor標籤進行聲明。使用這種方式進行聲明的Interceptor可以通過mvc:mapping子標籤來定義需要進行攔截的請求路徑。

經過上述兩步之後,定義的攔截器就會發生作用對特定的請求進行攔截了。

過濾器(Filter)使用

Servlet 的 Filter 接口需要實現如下方法:

  1. void init(FilterConfig paramFilterConfig) – 當容器初始化 Filter 時調用,該方法在 Filter 的生命週期只會被調用一次,一般在該方法中初始化一些資源,FilterConfig 是容器提供給
    Filter 的初始化參數,在該方法中可以拋出 ServletException 。init 方法必須執行成功,否則 Filter
    可能不起作用,出現以下兩種情況時,web 容器中 Filter 可能無效: 1)拋出 ServletException 2)超過 web
    容器定義的執行時間。
  2. doFilter(ServletRequest paramServletRequest, ServletResponse
  3. paramServletResponse, FilterChain paramFilterChain) – Web 容器每一次請求都會調用該方法。該方法將容器的請求和響應作爲參數傳遞進來, FilterChain 用來調用下一個 Filter。
  4. void destroy() – 當容器銷燬 Filter 實例時調用該方法,可以在方法中銷燬資源,該方法在 Filter的生命週期只會被調用一次。

攔截器(Interceptor)和過濾器(Filter)的一些用途

  • Authentication Filters
  • Logging and Auditing Filters
  • Image conversion Filters
  • Data compression Filters
  • Encryption Filters
  • Tokenizing Filters
  • Filters that trigger resource access events
  • XSL/T filters
  • Mime-type chain Filter

Request Filters 可以:

  • 執行安全檢查 perform security checks
  • 格式化請求頭和主體 reformat request headers or bodies
  • 審查或者記錄日誌 audit or log requests
  • 根據請求內容授權或者限制用戶訪問 Authentication-Blocking requests based on user identity.
  • 根據請求頻率限制用戶訪問

Response Filters 可以:

  • 壓縮響應內容,比如讓下載的內容更小 Compress the response stream
  • 追加或者修改響應 append or alter the response stream
  • 創建或者整體修改響應 create a different response altogether
  • 根據地方不同修改響應內容 Localization-Targeting the request and response to a particular locale.

demo

過濾器(Filter):

<filter>
        <description>字符集過濾器</description>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <description>字符集編碼</description>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

總結

1.過濾器:所謂過濾器顧名思義是用來過濾的,在java web中,你傳入的request,response提前過濾掉一些信息,或者提前設置一些參數,然後再傳入servlet或者struts的action進行業務邏輯,比如過濾掉非法url(不是login.do的地址請求,如果用戶沒有登陸都過濾掉),或者在傳入servlet或者struts的action前統一設置字符集,或者去除掉一些非法字符(聊天室經常用到的,一些罵人的話)。filter 流程是線性的, url傳來之後,檢查之後,可保持原來的流程繼續向下執行,被下一個filter, servlet接收等.

2.java的攔截器 主要是用在插件上,擴展件上比如 hibernate spring struts2等 有點類似面向切片的技術,在用之前先要在配置文件即xml文件裏聲明一段的那個東西。

參考資料
http://blog.csdn.net/heyeqingquan/article/details/71482169

http://einverne.github.io/post/2017/08/spring-interceptor-vs-filter.html

http://blog.csdn.net/xiaodanjava/article/details/32125687

整理自軍子的博客:過濾器(Filter)與攔截器(Interceptor )區別

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章