過濾器Filter學(xué)習(xí)
Filter 簡介
Filter 的基本功能是對 Servlet 容器調(diào)用 Servlet 的過程進行攔截,從而在 Servlet
進行響應(yīng)處理的前后實現(xiàn)一些特殊的功能。
在 Servlet API 中定義了三個接口類來開供開發(fā)人員編寫 Filter 程序:Filter, FilterChain,
FilterConfig。
Filter 程序是一個實現(xiàn)了 Filter 接口的 Java 類,與 Servlet 程序相似,它由 Servlet 容器進行調(diào)用和執(zhí)行。
Filter 程序需要在 web.xml 文件中進行注冊和設(shè)置它所能攔截的資源:Filter 程序可以攔截 Jsp, Servlet, 靜態(tài)圖片文件和靜態(tài)
html 文件
Filter 體系結(jié)構(gòu)
Filter并不是從真正意義上對來自客戶端的請求做出最終響應(yīng),而是進行部分的過濾工作,對請求數(shù)據(jù)進行檢測或者安全性檢查等工作。
Filter只有在客戶端請求或者發(fā)出響應(yīng)時才會自動進行調(diào)用,所以沒有必要把這些Filter字節(jié)嵌入到整個Web應(yīng)用系統(tǒng)的框架中,而是通過配置文件來設(shè)定。
當然,大部分情況下,并不需要給Web應(yīng)用程序設(shè)置Filter,因為它不是必需的。如果需要設(shè)置Filter,除了可以設(shè)置單個Filter關(guān)聯(lián)外,還可以設(shè)置Web應(yīng)用程序與一個Filter鏈(多個單Filter相串聯(lián))相關(guān)聯(lián)。
Filter的工作過程的相關(guān)步驟:
- 首先,通過部署描述器web.xml中對Filter的配置,特定Filter會捕捉到客戶端的請求信息。
- Filter調(diào)用內(nèi)置方法來檢查捕獲到的請求對象,根據(jù)分析結(jié)果來決定是把該請求傳遞給下一個Filter(如果存在另一個Filter的話),還是中止該請求并向客戶端發(fā)出一個響應(yīng)。如果不存在Filter鏈,即僅僅為單個Filter,則上一個Filter直接把客戶請求轉(zhuǎn)發(fā)給Web服務(wù)器進行相應(yīng)處理。
- 如果CSS應(yīng)用程序關(guān)聯(lián)了Filter,在客戶端請求設(shè)法通過各個Filter被服務(wù)器處理時,最終的響應(yīng)將以相反的順序通過Filter鏈,最后發(fā)送給客戶端。
Filter 基本工作原理
當在 web.xml 中注冊了一個 Filter 來對某個 Servlet 程序進行攔截處理時,這個 Filter 就成了 Servlet 容器與該
Servlet 程序的通信線路上的一道關(guān)卡,該 Filter 可以對 Servlet 容器發(fā)送給 Servlet 程序的請求和 Servlet 程序回送給
Servlet 容器相應(yīng)進行攔截,可以決定是否將請求繼續(xù)傳遞給 Servlet 程序,以及對請求和相應(yīng)信息是否進行修改。
在一個 web 應(yīng)用程序中可以注冊多個 Filter 程序,每個 Filter 程序都可以對一個或一組 Servlet 程序進行攔截。
若有多個 Filter 程序?qū)δ硞€ Servlet 程序的訪問過程進行攔截,當針對該 Servlet 的訪問請求到達時,web 容器將把多個 Filter
程序組合成一個 Filter 鏈(過濾器鏈)。Filter 鏈中各個 Filter 的攔截順序與它們在應(yīng)用程序的 web.xml 中映射的順序一致。
Filter的實現(xiàn)步驟
實現(xiàn)一個Filter的三個步驟:
- 首先編寫Filter的實現(xiàn)類程序。
- 其次,需要把實現(xiàn)的Filter添加到Web應(yīng)用程序中,也就是說,需要在Web部署描述文件Web.xml中聲明該Filter。
- 最后,將相關(guān)聯(lián)的Filter與應(yīng)用程序一起打包并部署。
Filter的主要作用及Filter API
Filter的主要作用
- 對用戶請求進行統(tǒng)一認證
- 對用戶的訪問請求進行記錄和審核
- 對用戶發(fā)送的數(shù)據(jù)進行過濾和替換
- 轉(zhuǎn)換圖象格式
- 對響應(yīng)內(nèi)容進行壓縮,減少傳輸量
- 對請求或響應(yīng)進行加解密處理
- 觸發(fā)資源訪問事件
- 對XML的輸出應(yīng)用XSLT
Filter API
與Filter開發(fā)相關(guān)的接口與類都包含在javax.servlet和javax.servlet.http包中,主要有下面的接口和類。
- javax.servlet.Filter接口
- javax.servlet.FilterConfig接口
- javax.servlet.FilterChain接口
- javax.servlet.ServletRequestWrapper類
- javax.servlet.ServletResponseWrapper類
- javax.servlet.http.HttpServletRequestWrappe
r類 - javax.servlet.http.HttpServletResponseWrapp
er類
Filter接口
開發(fā)Filter要實現(xiàn)javax.servlet.Filter接口,與開發(fā)Servlet要實現(xiàn)javax.servlet.Servlet接口類似。提供了一個公開的不帶參數(shù)的構(gòu)造方法。
在Filter接口中,定義了下面三個方法。
Filter接口的方法
public void init(FilterConfig filterConfig) throws
ServletException
ServletException
在 web 應(yīng)用程序啟動時,web 服務(wù)器將根據(jù) web.xml 文件中的配置信息來創(chuàng)建每個注冊的 Filter
實例對象,并將其保存在服務(wù)器的內(nèi)存中。Web容器創(chuàng)建 Filter 對象實例后,將立即調(diào)用該 Filter 對象的 init 方法。Init 方法在
Filter 生命周期中僅執(zhí)行一次,web 容器在調(diào)用 init 方法時,會傳遞一個包含 Filter 的配置和運行環(huán)境的 FilterConfig
對象(FilterConfig的用法和ServletConfig類似)。利用FilterConfig對象可以得到ServletContext對象,以及部署描述符中配置的過濾器的初始化參數(shù)。在這個方法中,可以拋出ServletException異常,通知容器該過濾器不能正常工作。
public void doFilter(ServletRequest request,ServletResponse
response,FilterChain chain) throws IOException,ServletException
response,FilterChain chain) throws IOException,ServletException
doFilter()方法類似于Servlet接口的service()方法。當客戶端請求目標資源的時候,容器就會調(diào)用與這個目標資源相關(guān)聯(lián)的過濾器的
doFilter()方法。其中參數(shù) request, response 為 web 容器或 Filter 鏈的上一個 Filter
傳遞過來的請求和相應(yīng)對象;參數(shù) chain 為代表當前 Filter 鏈的對象,在特定的操作完成后,可以調(diào)用 FilterChain 對象的
chain.doFilter(request,response)方法將請求交付給 Filter 鏈中的下一個 Filter 或者目標 Servlet
程序去處理,也可以直接向客戶端返回響應(yīng)信息,或者利用RequestDispatcher的forward()和include()方法,以及
HttpServletResponse的sendRedirect()方法將請求轉(zhuǎn)向到其他資源。這個方法的請求和響應(yīng)參數(shù)的類型是
ServletRequest和ServletResponse,也就是說,過濾器的使用并不依賴于具體的協(xié)議。
public void destroy()
Web容器調(diào)用該方法指示Filter的生命周期結(jié)束。在這個方法中,可以釋放Filter使用的資源。
與開發(fā)Servlet不同的是,F(xiàn)ilter接口并沒有相應(yīng)的實現(xiàn)類可供繼承,要開發(fā)過濾器,只能直接實現(xiàn)Filter接口。
FilterChain接口
代表當前 Filter
鏈的對象,由容器實現(xiàn),容器將其實例作為參數(shù)傳入過濾器對象的doFilter()方法中。過濾器對象使用FilterChain對象調(diào)用過濾器鏈中的下一個過濾器,如果該過濾器是鏈中最后一個過濾器,那么將調(diào)用目標資源。
FilterChain接口只有一個方法。
FilterChain接口的方法
public void doFilter(ServletRequest request,ServletResponse response)
throws IOException
throws IOException
調(diào)用該方法將使過濾器鏈中的下一個過濾器被調(diào)用。如果是最后一個過濾器,會調(diào)用目標資源。
FilterConfig接口
javax.servlet.FilterConfig接口類似于javax.servlet.ServletConfig接口,用于在Filter初始化時向其傳遞信息。FilterConfig接口有容器實現(xiàn),容器將其作為參數(shù)傳入Filter對象的init()方法中。
在FilterConfig接口中,定義了四個方法。
FilterConfig接口的方法
public String getFilterName()
得到描述符中指定的過濾器的名字。
public String getInitParameter(String name)
返回在部署描述中指定的名字為name的初始化參數(shù)的值。如果不存在返回null。
public Enumeration getInitParameterNames()
返回過濾器的所有初始化參數(shù)的名字的枚舉集合。
public ServletContext getSerlvetContext()
返回Servlet上下文對象的引用
Filter的部署
在實現(xiàn)一個Filter后,需要在部署描述符中對Filter進行配置,這是通過<filter>和<filter-mapping>元素來完成的。
<filter>元素
用于在Web應(yīng)用程序中聲明一個Filter。
在<filter>元素內(nèi),<description>、<display-name>、<icon>元素和以往serlvet的配置中的相同。
- <filter-name>用于為Filter指定一個名稱,該元素的內(nèi)容不能為空。
- <filter-class>元素用于指定Filter的完整的限定類名。
- <init-param>元素用于為Filter指定初始化參數(shù)。它的子元素<param-name>指定參數(shù)的名稱;<param-value>指定參數(shù)的值。
在Filter中,可以使用FilterConfig接口對象來訪問初始化參數(shù)。
<filter-mapping>元素
用于指定Filter關(guān)聯(lián)的url樣式或者Servlet。
- <filter-name>子元素的值必須是在<filter>元素中聲明過的Filter的名字。
- <url-pattern>元素指定Filter關(guān)聯(lián)的URL樣式。
- <servlet-name>元素指定Filter對應(yīng)的Servlet。
<url-pattern>元素和<servlet-name>元素可以選擇一個;用戶在訪問<url-pattern>元素指定的URL上的資源或<servlet-name>元素指定的Servlet時,該Filter才會被容器調(diào)用。
-------------------------------
Filter演示示例
創(chuàng)建一個簡單的Filter(TimeTrackFilter.java),跟蹤滿足一個客戶機的Web請求大致所花的時間。
創(chuàng)建Filter
TimeTrackFilter.java
package cn.jbit.auction.servlet; import java.io.IOException; import java.util.Date; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class TimeTrackFilter implementsFilter
{ private FilterConfig filterConfig = null; // 初始化Filterpublic void init(FilterConfig filterConfig) throws ServletException
{ // TODO Auto-generated method stub this.filterConfig = filterConfig; } // 執(zhí)行Filter功能public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{ // TODO Auto-generated method stub Date startTime,endTime; double totalTime; startTime = new Date(); // 把處理發(fā)送到下一個Filter chain.doFilter(request, response); // 接下來的語句就是處理請求的過程:計算開始到結(jié)束的時間 endTime = new Date(); totalTime = endTime.getTime()-startTime.getTime(); totalTime = totalTime / 1000; System.out.println("============================="); System.out.println("Total elapsed time is: " + totalTime + " seconds."); System.out.println("============================="); filterConfig.getServletContext(); }public void destroy()
{ // TODO Auto-generated method stub this.filterConfig = null; } }
配置Filter
實現(xiàn)了Filter后,還需要通過web.xml文件中的兩上XML元素來聲明該Filter。
配置web.xml
<filter> <filter-name>requestTimer
</filter-name> <filter-class>cn.jbit.auction.servlet.TimeTrackFilter
</filter-class> </filter> <filter-mapping> <filter-name>requestTimer
</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>