1. 程式人生 > 實用技巧 >Servlet三大元件_Filter過慮器

Servlet三大元件_Filter過慮器

Filter過慮器

  Filter(過濾器)用於攔截使用者請求,在伺服器作出響應前,可以在攔截後修改request和response。可以實現一次編碼,多處應用。Filter不像Servlet,它不能產生一個請求或者響應,它只是修改對某一資源的請求,或者修改從某一的響應。

  作用:

  Filter主要的作用有兩個:

  • 攔截修改請求:在HttpServletRequest到達Servlet之前,攔截客戶的HttpServletRequest。根據需要檢查HttpServletRequest,也可以修改HttpServletRequest頭和資料。
  • 攔截修改響應:在HttpServletResponse到達客戶端之前,攔截HttpServletResponse。根據需要檢查HttpServletResponse,也可以修改HttpServletResponse頭和資料。

  原理:

  通常Filter完整的工作流程是:Filter對使用者請求進行預處理,接著將請求交給Servlet進行處理並生成響應,最後Filter再對伺服器響應進行後處理。

  Filter的底層原理是基於函式回撥的,很容易聯想到設計模式中的責任鏈模式

  原理圖

  

  自定義過慮器

public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException { 
    }

    @Override
    
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { System.out.println("MyFilter......."); //對使用者請求執行預處理的程式碼邏輯 precode... //交給FilterChain的下一個物件處理 //如果還有filter則呼叫下一個filter //如果沒有,則呼叫目標資源。 chain.doFilter(req, resp);
//對伺服器響應執行後處理 postcode... } @Override public void destroy() { } }

  其中:

  • preCode為Filter的doFilter()中chain.doFilter(request,response)呼叫之前的程式碼語句用於對使用者請求執行預處理
  • postCode為Filter的doFilter()中chain.doFilter(request,response)呼叫之後的程式碼語句用於對伺服器響應執行後處理

  

生命週期

  Filter的生命週期和Servlet一樣,Filter的建立和銷燬也是由WEB伺服器負責。

  

  

  • init(FilterConfig filterConfig)
    • 初始化方法,只會在web應用程式啟動時呼叫一次
    • 和我們編寫的Servlet程式一樣,Filter的建立和銷燬由WEB伺服器負責。
    • web 應用程式啟動時,web 伺服器將建立Filter 的例項物件,並呼叫其init方法,讀取web.xml配置,完成物件的初始化功能,從而為後續的使用者請求作好攔截的準備工作(filter物件只會建立一次,init方法也只會執行一次)。開發人員通過init方法的引數,可獲得代表當前filter配置資訊的FilterConfig物件。
    • Filter物件建立之後會駐留在記憶體,一直服務。
  • doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    • 完成實際的過濾操作。當客戶請求訪問與過濾器關聯的URL的時候,Servlet過濾器將先執行doFilter方法。FilterChain引數用於訪問後續過濾器。
  • destroy();
    • 銷燬方法,只會在當web應用移除或伺服器停止時才呼叫一次來解除安裝Filter物件。
    • 通常在這個方法中,可以釋放過濾器使用的資源。

  

FilterChain

  在一個web應用當中,可以開發編寫多個Filter,這些Filter組合起來稱之為一個Filter鏈,其中每個過濾器(Filter)都可以決定是否執行下一步。

  FilterChain實際上是一個介面,該介面中有一個方法:

  • doFilter():。該方法被FilterChain物件呼叫,表示對Filter過濾器過濾範圍下的資源進行放行,讓鏈中下一個物件進行處理。

  FilterChain在tomcat中的實現類是ApplicationFilterChain,一個ApplicationFilterChain物件包含幾個主要引數

  • n => filter個數
  • pos => 下一個要執行的filter的位置
  • Servlet => 當pos >= n,即過濾完成時,呼叫Servlet的service方法,把請求交給Servlet
  • filters => Filter的相關配置資訊

  FilterChain持有所有Filter的配置資訊,它們儲存在一個數組中,然後通過移動pos,來獲取後續的Filter並執行的,這就符合之前的鏈式處理流程。

  

FilterConfig

  與普通的 Servlet 程式一樣,Filter 也很可能需要訪問 Servlet 容器。Servlet 規範將代表 ServletContext 物件和 Filter 的配置引數資訊都封裝到一個稱為 FilterConfig 的物件中。

  FilterConfig介面中有如下四個方法:

  • getInitParameter():獲取初始化引數。
  • getInitParameterNames():獲取所有初始化引數的名稱。
  • getFilterName():獲取過濾器的配置名稱。
  • getServletContext():獲取application。

使用方法

  建立使用一個Filter只需要兩個步驟:

  • 建立一個實現javax.servlet.Filter介面的Filter處理類實現過濾邏輯
  • 配置Filter到伺服器中

  Filter實現類

  實現Filter介面,然後寫對應的業務程式碼即可

  

public class MyFilter implements Filter {
    public void destroy() {
        /*銷燬時呼叫*/
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        /*過濾方法 主要是對request和response進行一些處理,然後交給下一個過濾器或Servlet處理*/
           precode...
        chain.doFilter(req, resp);
        postcode...
    }

    public void init(FilterConfig config) throws ServletException {
        /*初始化方法  接收一個FilterConfig型別的引數 該引數是對Filter的一些配置*/

    }
}

  配置方法

  將Filter配置到伺服器中有兩種方法:

  • 使用web.xml 配置

  

            <filter>
                <filter-name>myFilter</filter-name>
                <filter-class>whu.web.filter.myFilter</filter-class>
            </filter>
            <filter-mapping>
                <filter-name>myFilter</filter-name>
                <url-pattern>/*</url-pattern>
            </filter-mapping>

  

  基於註解的配置

  @WebFilter("/*") 

一些常用配置項:

  • urlPatterns:配置攔截的資源路徑
    • 精確匹配 —— 如/foo.htm,只會匹配foo.htm這個URL
    • 路徑匹配 —— 如/foo/*,會匹配以foo為字首的URL
    • 字尾匹配 —— 如*.htm,會匹配所有以.htm為字尾的URL
    • 通配——/*,會攔截所有web資源
  • initParams:配置初始化引數
    • initParams = { @WebInitParam(name = "key",value = "value") }
    • 配置之後即可通過Filterconfig.getInitParameter("key")獲得對應value
  • dispatcherTypes:配置攔截的型別,可配置多個
    • REQUEST:直接訪問目標資源時執行過濾器。包括:在位址列中直接訪問、表單提交、超連結、重定向,只要在位址列中可以看到目標資源的路徑,就是REQUEST;
    • FORWARD:轉發訪問執行過濾器。包括RequestDispatcher#forward()方法、< jsp:forward>標籤都是轉發訪問;
    • INCLUDE:包含訪問執行過濾器。包括RequestDispatcher#include()方法、< jsp:include>標籤都是包含訪問;
    • ERROR:當目標資源在web.xml中配置為< error-page>中時,並且真的出現了異常,轉發到目標資源時,會執行過濾器。

  Filter執行順序

  Filter的執行順序是按照FilterChain來執行的,FilterChain中Filter的順序不同配置方式下的組織情況不同,具體如下:

  • 基於註解配置:按照類名的字串比較規則比較,值小的先執行
  • 使用web.xml配置:根據對應的Mapping的順序組織,誰定義在上邊誰就在前

  實際運用

  在實際使用過程中,Filter通常有以下用途:

    • 處理全站中文亂碼問題
    • 過濾非法請求
    • 實現自動登入
    • 過濾敏感詞彙
    • 壓縮網頁
    • 選擇性讓瀏覽器快取
    • 結合日誌記錄使用者操作