Filter概述
Filter是javax.servlet包中的一個接口,一個filter是對客戶請求/響應進行攔截任務的一個對象。Filter調用doFilter()方法,傳送給該方法的FilterConfig ,包含其初始化參數。
Filter的工作流程:
當客戶端發出Web資源的請求時,Web服務器根據應用程序配置文件設置的過濾規則進行檢查,若客戶請求滿足過濾規則,則對客戶請求/響應進行攔截,對請求頭和請求數據進行檢查或改動,並依次通過過濾器鏈,最後把請求/響應交給請求的Web資源處理。請求信息在過濾器鏈中可以被修改,也可以根據條件讓請求不發往資源處理器,並直接向客戶機發回一個響應。當資源處理器完成了對資源的處理後,響應信息將逐級逆向返回。同樣在這個過程中,用戶可以修改響應信息,從而完成一定的任務。
多個過濾器同時過濾一個請求時,組成過濾鏈FilterChain,服務器按web.xml中定義過濾器先後順序組成一條鏈,然後執行doFilter()方法。
執行流程:
執行第一個過濾器的chain.doFilter()之前的代碼——>第二個過濾器的chain.doFilter()之前的代碼——>…….——>第n個過濾器的chain.doFilter()之前的代碼——>所請求Servlet的service()方法中的代碼——>所請求的doGet()或doPost()方法中的代碼——>第n個過濾器的chain.doFilter()之後的代碼——>……——>第二個過濾器的chain.doFilter()之後的代碼——>第一個過濾器的chain.doFilter()之後的代碼。
常見過濾器種類
- 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:能改變XML內容
- Mime-type chain Filter:MIME類型過濾鏈
過濾器生命週期
- 實例化:Web容器在部署Web應用程序時對所有過濾器進行實例化;
- 初始化:Web容器回調init()方法;
- 過濾:當請求路徑匹配過濾器的URL映射,Web容器回調doFilter()方法;
- Web容器在卸載Web應用程序前回調destroy()方法,回收資源。
創建Filter步驟
- 創建實現javax.servlet.Filter接口的類;
- 在web.xml中配置Filter
package com.afy.servlet;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
@WebFilter(filterName="log",urlPatterns={"/hi"})
public class LogFilter implements Filter {
//FilterConfig可用於訪問Filter的配置信息
private FilterConfig config;
@Override
public void init(FilterConfig config) throws ServletException {
this.config = config;
}
@Override
public void destroy() {
this.config = null;
}
@Override
//過濾核心方法
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//--------以下代碼用於對用戶請求執行預處理--------
//獲取ServletContext對象,用於記錄日誌
ServletContext context = this.config.getServletContext();
long before = System.currentTimeMillis();
System.out.println("開始過濾.......");
//將請求轉換成HttpServletRequest請求
HttpServletRequest hrequest = (HttpServletRequest)request;
//輸出提示信息
System.out.println("Filter已經截獲到用戶的請求地址: " + hrequest.getServletPath());
//Filter只是鏈式地址,請求依然放到目的地址
chain.doFilter(request, response);
//------------以下代碼用於對服務器響應執行處後處理-------
long after = System.currentTimeMillis();
//輸出提示信息
System.out.println("過濾結束");
System.out.println("請求被定位到" + hrequest.getRequestURI() + "所花時間爲:" + (after-before));
}
}
doFilter()方法可以實現對用戶請求進行預處理,也可以實現對服務器-響應進行後處理,分界線爲是否調用chain.doFilter(),執行該方法前,對用戶請求進行預處理,執行後對服務器進行後處理。
Servlet過濾器API
Servlet過濾器API有3個接口,都在javax.servlet包中,分別是Filter接口、FilterChain接口、FilterConfig接口。
Filter接口定義了init(),doFilter(),destroy()方法
public void init(FilterConfig,filterConfig)
開始使用Servlet過濾服務時,Web容器調用此方法一次,爲服務準備過濾器;需要使用過濾器時調用doFilter(),傳送給次方法的FilterConfig對象,包含Servlet過濾器的初始化參數;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
過濾器在doFilter()方法中,可以通過它們的方法手機數據,或者給對象添加新的行爲,過濾器通過傳送至該方法的FilterChain參數,調用chain.doFilter()將控制權傳送給下一個過濾器。如果過濾器想要終止請求的處理或得到對響應的完全控制,可以不調用下一個過濾器,而將其重定向到其他頁面。當鏈中的最後一個過濾器調用chain.doFilter()方法時,將運行最初請求的Servlet。
public void destroy()
當doFilter()方法裏的所有線程退出或超時,容器調用此方法。
public interface FilterChain
FilterChain接口有一個方法public void doFilter(ServldtRequest request, ServletResponse response),此方法用於對資源過濾鏈的依次調用,通過FilterChain調用過濾器的下一個過濾器,如果是最後一個過濾器則調用目標資源。
public interface FilterConfig
FilterConfig接口檢索過濾器名,初始化參數和Servlet上下文。有4個方法。
- public java.lang.String getFilterName()返回web.xml文件中定義該過濾器的名稱。
- public java.lang.String getInitParameter(String name)返回過濾器初始化參數值的字符串形式,參數不存在則返回null,其中的name是初始化參數名。
- public java.util.Enumeration getInitParameterNames()以Enumeration形式返回過濾器所有初始化參數值,如果沒有初始化參數,返回爲空。
public ServletContext getServletContext()返回調用者所處的Servlet上下文。
Filter與Servlet近似,它們有相同的生命週期行爲。Filter的doFilter()方法裏多了一個FilterChain的參數,通過該參數可以控制是否放行用戶請求。實際應用中,Filter裏doFilter()方法裏的代碼是從多個Servlet的service()方法裏抽取的通用代碼,通過Filter實現更好的代碼複用。如果系統裏有多個Servlet,這些Servlet都需要進行一些通用出來就,如權限控制、記錄日誌、設置編碼等,這樣Servelet的service方法中有部分代碼會相同,這時可以考慮將這些通用處理放到Filter中完成,而Servlet裏只放特定請求相關的處理就代碼,把通用處理交給Filter完成。