過濾器(Filter)與攔截器(Interceptor )區別

過濾器(Filter)

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

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

      Filter有以下幾個用處。git

  • 在HttpServletRequest到達Servlet以前,攔截客戶的HttpServletRequest。
  • 根據須要檢查HttpServletRequest,也能夠修改HttpServletRequest頭和數據。
  • 在HttpServletResponse到達客戶端以前,攔截HttpServletResponse。
  • 根據須要檢查HttpServletResponse,也能夠修改HttpServletResponse頭和數據。

     Filter有以下幾個種類。github

  • 用戶受權的Filter:Filter負責檢查用戶請求,根據請求過濾用戶非法請求。
  • 日誌Filter:詳細記錄某些特殊的用戶請求。
  • 負責解碼的Filter:包括對非標準編碼的請求解碼。
  • 能改變XML內容的XSLT Filter等。
  • Filter能夠負責攔截多個請求或響應;一個請求或響應也能夠被多個Filter攔截。

     建立一個Filter只需兩個步驟web

  1. 建立Filter處理類
  2. web.xml文件中配置Filter

   建立Filter必須實現javax.servlet.Filter接口,在該接口中定義了以下三個方法。spring

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

 攔截器(Interceptor)

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

攔截器,在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編程思想的體現,都能實現權限檢查、日誌記錄等。不一樣的是:

Filter Interceptor Summary
Filter 接口定義在 javax.servlet 包中 接口 HandlerInterceptor 定義在org.springframework.web.servlet 包中  
Filter 定義在 web.xml 中    
Filter在只在 Servlet 先後起做用。Filters 一般將 請求和響應(request/response) 當作黑盒子,Filter 一般不考慮servlet 的實現。 攔截器可以深刻到方法先後、異常拋出先後等,所以攔截器的使用具備更大的彈性。容許用戶介入(hook into)請求的生命週期,在請求過程當中獲取信息,Interceptor 一般和請求更加耦合。 在Spring構架的程序中,要優先使用攔截器。幾乎全部 Filter 可以作的事情, interceptor 都可以輕鬆的實現
Filter 是 Servlet 規範規定的。 而攔截器既能夠用於Web程序,也能夠用於Application、Swing程序中。 使用範圍不一樣
Filter 是在 Servlet 規範中定義的,是 Servlet 容器支持的。 而攔截器是在 Spring容器內的,是Spring框架支持的。 規範不一樣
Filter 不可以使用 Spring 容器資源 攔截器是一個Spring的組件,歸Spring管理,配置在Spring文件中,所以能使用Spring裏的任何資源、對象,例如 Service對象、數據源、事務管理等,經過IoC注入到攔截器便可 Spring 中使用 interceptor 更容易
Filter 是被 Server(like Tomcat) 調用 Interceptor 是被 Spring 調用 所以 Filter 老是優先於 Interceptor 執行

攔截器(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主要有兩種方式:

  • 直接定義一個Interceptor實現類的bean對象。使用這種方式聲明的Interceptor攔截器將會對全部的請求進行攔截。
  • 使用mvc:interceptor標籤進行聲明。使用這種方式進行聲明的Interceptor能夠經過mvc:mapping子標籤來定義須要進行攔截的請求路徑。

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

過濾器(Filter)使用

Servlet 的 Filter 接口須要實現以下方法:

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

    FrequencyLimitFilter com.company.filter.FrequencyLimitFilter FrequencyLimitFilter /login/*

攔截器(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

SpringMVC中的Interceptor攔截器及與Filter區別

相關文章
相關標籤/搜索