1.Filter的介紹
Filter技術是servlet 2.3新增加的功能。它能夠對Servlet容器的請求和響應對象進行檢查和修改。
Filter本身並不生成請求和響應對象,只是提供過濾功能。
Filter能夠在Servlet被調用之前檢查Request對象,並修改Request Header和Request內容;在Servlet被調用之后檢查Response對象,修改Response Header和Response的內容。
Filter可以過濾的Web組件包括Servlet,JSP和HTML等文件。
2.Filter的工作原理
當客戶端發出Web資源的請求時,Web服務器根據應用程序配置文件設置的過濾規則進行檢查,若客戶請求滿足過濾規則,則對客戶請求/響應進行攔截,對請求頭和請求數據進行檢查或改動,並依次通過過濾器鏈,最后把請求/響應交給請求的Web資源處理。請求信息在過濾器鏈中可以被修改,也可以根據條件讓請求不發往資源處理器,並直接向客戶機發回一個響應。當資源處理器完成了對資源的處理后,響應信息將逐級逆向返回。同樣在這個過程中,用戶可以修改響應信息,從而完成一定的任務。
兩個過濾器同時過濾一個請求時,就要用到過濾鏈FilterChain。Filter的FilterChain中,服務器會按照web.xml中過濾器定義的先后循序組裝成一條鏈,然后一次執行其中的doFilter()方法。執行的順序就如下圖所示,執行第一個過濾器的chain.doFilter()之前的代碼,第二個過濾器的chain.doFilter()之前的代碼,請求的資源,第二個過濾器的chain.doFilter()之后的代碼,第一個過濾器的chain.doFilter()之后的代碼,最后返回響應。
Filter的執行流程就是:執行第一個過濾器的chain.doFilter()之前的代碼——>第二個過濾器的chain.doFilter()之前的代碼——>……——>第n個過濾器的chain.doFilter()之前的代碼——>所請求servlet的service()方法中的代碼——>所請求servlet的doGet()或doPost()方法中的代碼——>第n個過濾器的chain.doFilter()之后的代碼——>……——>第二個過濾器的chain.doFilter()之后的代碼——>第一個過濾器的chain.doFilter()之后的代碼。
3.Filter生命周期的四個階段
(1)實例化:Web容器在部署Web應用程序時對所有過濾器進行實例化。Web容器回調它的無參構造方法。
(2)初始化:實例化完成之后,馬上進行初始化工作。Web容器回調init()方法。
(3)過濾:請求路徑匹配過濾器的URL映射時。Web容器回調doFilter()方法——主要的工作方法。
(4)銷毀: Web容器在卸載Web應用程序前,Web容器回調destroy()方法。
4.Filter的API
public Interface Filter
所有的過濾器都必須實現Filter接口。該接口定義了init,doFilter0,destory()三個方法:
(1) public void init (FilterConfig filterConfig)
當開始使用servlet過濾器服務時,Web容器調用此方法一次,為服務准備過濾器;然后在需要使用過濾器的時候調用doFilter(),傳送給此方法的FilterConfig對象,包含servlet過濾器的初始化參數。
示例:
Filter的init方法中提供了一個FilterConfig對象,提供相關的操作:
<filter> <filter-name>LoginFilter</filter-name> <filter-class>com.itzhai.login.LoginFilter</filter-class> <init-param> <param-name>username</param-name> <param-value>HelloWorld</param-value> </init-param> </filter>
在init方法中獲取:
@Override public void init(FilterConfig filterConfig) throws ServletException { //獲取Filter初始化參數 String username = filterConfig.getInitParameter("username"); }
(2)public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)
每個過濾器都接受當前的請求和響應,且FilterChain過濾器鏈中的過濾器(應該都是符合條件的)都會被執行。doFilter方 法中,過濾器可以對請求和響應做它想做的一切,通過調用他們的方法收集數據,或者給對象添加新的行為。過濾器通過傳送至 此方法的FilterChain參數,調用chain.doFilterO將控制權傳送給下一個過濾器。當這個調用返回后,過濾器可以在它的 Filter方法的最后對響應做些其他的工作。如果過濾器想要終止請求的處理或得到對響應的完全控制,則可以不調用下一個過濾 器,而將其重定向至其它一些頁面。當鏈中的最后一個過濾器調用chain.doFilterO方法時,將運行最初請求的Servlet。
(3)public void destroy()
一旦doFilterO方法里的所有線程退出或已超時,容器調用此方法。服務器調用destoryO以指出過濾器已結束服務,用於釋放過濾器占用的資源。
5.例子
過濾敏感詞匯
package com.zhouyu.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class FilterTest implements Filter { @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 轉換成實例的請求和響應對象 HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; // 獲取評論並屏蔽關鍵字 String str = req.getParameter("str"); str = str.replace("你妹呀", "***"); // 重新設置參數 req.setAttribute("str", str); // 繼續執行 chain.doFilter(request, response); } @Override public void init(FilterConfig filterConfig) throws ServletException { // TODO Auto-generated method stub } }