Filter(過濾器)


1、Filter(過濾器)的基本介紹

Servlet 過濾器可以動態地攔截請求和響應,以變換或使用包含在請求或響應中的信息。可以將一個或多個 Servlet 過濾器附加到一個 Servlet 或一組 Servlet。Servlet 過濾器也可以附加到 JavaServer Pages (JSP) 文件和 HTML 頁面。

調用 Servlet 前調用所有附加的 Servlet 過濾器。

Servlet 過濾器是可用於 Servlet 編程的 Java 類,可以實現以下目的:

  • 在客戶端的請求訪問后端資源之前,攔截這些請求。
  • 在服務器的響應發送回客戶端之前,處理這些響應。

 

Filter、Listener和 servlet 是 Java EE 的三大組件。

 

1.1、過濾器的作用

過濾器一般用於完成一些通用的操作,將一些公用邏輯從各個Servlet中抽離出來在過濾器里實現。比如:

  • 記錄日志、登錄檢查、全局設置等;
  • 統一編碼設置、敏感字符過濾等等

在HTTP請求到達Servlet之前,我們可以通過一個或多個Filter 對 servlet 進行預處理。

 

2、Filter的基本使用

過濾器是一個實現了 javax.servlet.Filter 接口的 Java 類。

javax.servlet.Filter 接口定義了三個方法:

  • public void doFilter (ServletRequest, ServletResponse, FilterChain):該方法完成實際的過濾操作,當客戶端請求方法與過濾器設置匹配的URL時,Servlet容器將先調用過濾器的doFilter方法。每一次請求被攔截時都會執行。
  • public void init(FilterConfig filterConfig):服務器啟動后將會自動創建 Filter 的實例對象,並自動調用其 init 方法,讀取web.xml配置,完成對象的初始化功能,從而為后續的用戶請求作好攔截的准備工作(filter對象只會創建一次,init方法也只會執行一次)
  • public void destroy():正常關閉服務器時,Filter 對象被銷毀,將會執行該方法(正常關閉時才會執行該方法)。一般可在該方法中釋放過濾器占用的資源。

 

定義一個 filter 跟定義一個 java 類沒什么差別。示例如下:

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter("/*")   //定義攔截的URL
public class FilterTest01 implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("filter被執行了。。");

        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");

        chain.doFilter(request, response);   //將請求放行
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }
}

上面配置的過濾器過濾的URL為 /*,則表示所有路徑的資源都會被過濾器攔截到並進行處理。不僅僅是 servlet,只要是訪問服務器上的資源,比如 jsp、html、css、js 、圖片等等,這些也都能被過濾器攔截到。

在 doFilter() 方法內部,要將該請求放行,允許后面的資源或者后面的 Filter 處理請求,則必須調用 chain.doFilter(req, resp)。否則,請求雖然能成功,但不會有內容返回,默認響應是200+空白輸出,比如如果請求的是 jsp 或者是 html 資源,將會看到空白頁面。

 

在 chain.doFilter(req, resp) 前面的語句會在資源響應前先執行這些代碼,但在 chain.doFilter(req, resp) 后面的語句將會在資源返回后執行,所以一般這些語句可用於對響應的信息進行操作。

 

注意,doFilter() 中的參數是 ServletRequest,而不是 servlet 中的 HttpServletRequest。HttpServletRequest和ServletRequest都是接口,HttpServletRequest繼承自ServletRequest。HttpServletRequest比ServletRequest多了一些針對於Http協議的方法。 例如:getHeader(), getMethod() , getSession() 等。

要想使用 HttpServletRequest 中的參數,應該對 ServletRequest 進行強轉換:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest)request;  
       
        String uri = httpServletRequest.getRequestURI();
}

 

2.1、使用 web.xml 配置過濾器

除了可以使用注解 @WebFilter() 來配置過濾器,我們也可以使用 web.xml 來配置過濾器。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <filter>
        <filter-name>filterTestName</filter-name>  <!-- filter名稱 -->
        <filter-class>test.FilterTest01</filter-class>   <!-- 完整類名 -->
    </filter>
    <filter-mapping>
        <filter-name>filterTestName</filter-name>
        <url-pattern>/*</url-pattern>   <!-- 攔截路徑 -->
    </filter-mapping>
</web-app>

跟 servlet 的配置類型,其中,filter-class 是完整的類名,filter-name 給你所配置的過濾器指定了一個名稱,下面的 filter-mapping 里面的 filter-name 跟上面的 filter-name 相匹配,url-pattern 指定的是該過濾器的攔截路徑。

使用 web.xml 配置過后注解就可以不使用了。

 

web.xml配置各節點說明:

  • <filter>指定一個過濾器。
    • <filter-name>用於為過濾器指定一個名字,該元素的內容不能為空。
    • <filter-class>元素用於指定過濾器的完整的限定類名。
    • <init-param>元素用於為過濾器指定初始化參數,它的子元素<param-name>指定參數的名字,<param-value>指定參數的值。
    • 在過濾器中,可以使用FilterConfig接口對象來訪問初始化參數。
  • <filter-mapping>元素用於設置一個 Filter 所負責攔截的資源。一個Filter攔截的資源可通過兩種方式來指定:Servlet 名稱和資源訪問的請求路徑
    • <filter-name>子元素用於設置filter的注冊名稱。該值必須是在<filter>元素中聲明過的過濾器的名字
    • <url-pattern>設置 filter 所攔截的請求路徑(過濾器關聯的URL樣式)
  • <servlet-name>指定過濾器所攔截的Servlet名稱。
  • <dispatcher>指定過濾器所攔截的資源被 Servlet 容器調用的方式,可以是REQUEST,INCLUDE,FORWARDERROR之一,默認REQUEST。用戶可以設置多個<dispatcher>子元素用來指定 Filter 對資源的多種調用方式進行攔截。
  • <dispatcher>子元素可以設置的值及其意義:
    • REQUEST(默認值):當用戶直接訪問頁面時,Web容器將會調用過濾器。如果目標資源是通過RequestDispatcher的include()或forward()方法訪問時,那么該過濾器就不會被調用。
    • INCLUDE:如果目標資源是通過RequestDispatcher的include()方法訪問時,那么該過濾器將被調用。除此之外,該過濾器不會被調用。
    • FORWARD:如果目標資源是通過RequestDispatcher的forward()方法訪問時,那么該過濾器將被調用,除此之外,該過濾器不會被調用。
    • ERROR:如果目標資源是通過聲明式異常處理機制調用時,那么該過濾器將被調用。除此之外,過濾器不會被調用。
    • ASYNC:異步訪問資源時,過濾器被調用

 

2.2、配置詳解

2.2.1、路徑配置(urlPatterns)

攔截路徑的寫法:

  • 攔截所有資源:@WebFilter("/*"),訪問所有資源時,過濾器都會執行
  • 攔截目錄:比如@WebFilter("/user/*"),訪問 /user 下的所有資源時,過濾器都會執行
  • 后綴名攔截:比如@WebFilter("*.jsp"),訪問所有后綴名為 jsp 的資源時,過濾器都會執行
  • 攔截具體資源:比如@WebFilter("/index.jsp")、@WebFilter("/user/servletTest01"),這樣的話只有訪問到該資源時,過濾器才會被執行

 

2.2.2、攔截方式配置(資源被以什么方式請求時才被攔截)

我們可以配置服務器上的資源被以什么方式被請求時才會被攔截,比如被瀏覽器訪問時、服務器請求轉發等等方式

使用注解時,我們可以通過設置 dispatcherTypes 屬性來配置攔截方式,或者使用 web.xml 配置的<dispatcher>節點來設置。

示例:

@WebFilter(value = "/*", dispatcherTypes = DispatcherType.REQUEST)   //注解配置

//同時配置多種方式
@WebFilter(value = "/*", dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD})

 

該屬性可以設置的值及其意義:

  • REQUEST(默認值):當用戶直接訪問頁面時,Web容器將會調用過濾器。如果目標資源是通過RequestDispatcher的include()或forward()方法訪問時,那么該過濾器就不會被調用。
  • INCLUDE:如果目標資源是通過RequestDispatcher的include()方法訪問時,那么該過濾器將被調用。除此之外,該過濾器不會被調用。
  • FORWARD:如果目標資源是通過RequestDispatcher的forward()方法訪問時,那么該過濾器將被調用,除此之外,該過濾器不會被調用。
  • ERROR:如果目標資源是通過聲明式異常處理機制調用時,那么該過濾器將被調用。除此之外,過濾器不會被調用。
  • ASYNC:異步訪問資源時,過濾器被調用

 

2.3、過濾器鏈(多個過濾器時的執行順序)

我們可以添加多個過濾器,只需定義多個過濾器類即可。

有多個過濾器時,過濾器的執行順序跟使用注解配置還是 web.xml 配置有關。

當使用注解配置時,將會按照字符串的比較規則來比較過濾器的完整類名,值小的先執行。比如 atest.BFilter 和 btest.AFilter,則 atest.BFilter 過濾器先執行。

當使用 web.xml 配置時,哪個過濾器的在 web.xml 里面的定義代碼在上面,哪個就先執行。比如下面配置,BFilter 定義在上面,則該過濾器先執行:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <filter>
        <filter-name>BFilterName</filter-name>
        <filter-class>test.BFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>BFilterName</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>AFilterName</filter-name>
        <filter-class>atest.AFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>AFilterName</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

 

開始的過濾器執行順序即按照上面所說,但在資源執行后時,執行順序又是開始時的倒序(即在chain.doFilter(req, resp) 后面的語句的執行順序是該語法前面的語句的執行順序的倒序)。比如有兩個過濾器,過濾器1和過濾器2,執行順序如下:

  1. 過濾器1
  2. 過濾器2
  3. 資源執行
  4. 過濾器2
  5. 過濾器1

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM