一、Filter簡介
Filter也稱之為過濾器,它是Servlet技術(shù)中最激動人心的技術(shù),WEB開發(fā)人員通過Filter技術(shù),對web服務(wù)器管理的所有web資源:例如Jsp, Servlet, 靜態(tài)圖片文件或靜態(tài) html 文件等進行攔截,從而實現(xiàn)一些特殊的功能。例如實現(xiàn)URL級別的權(quán)限訪問控制、過濾敏感詞匯、壓縮響應(yīng)信息等一些高級功能。
Servlet API中提供了一個Filter接口,開發(fā)web應(yīng)用時,如果編寫的Java類實現(xiàn)了這個接口,則把這個java類稱之為過濾器Filter。通過 Filter技術(shù),開發(fā)人員可以實現(xiàn)用戶在訪問某個目標(biāo)資源之前,對訪問的請求和響應(yīng)進行攔截,如下所示:
在攔截器出來之前,F(xiàn)ilter是web開發(fā)的基礎(chǔ)核心,可以負(fù)責(zé)權(quán)限控制、日志記錄、字符集處理等等
二、Filter是如何實現(xiàn)攔截的?
Filter接口中有一個doFilter方法,當(dāng)我們編寫好Filter,并配置對哪個web資源進行攔截后,WEB服務(wù)器每次在調(diào)用web 資源的service方法之前,都會先調(diào)用一下filter的doFilter方法,因此,在該方法內(nèi)編寫代碼可達(dá)到如下目的:
調(diào)用目標(biāo)資源之前,讓一段代碼執(zhí)行。
1、是否調(diào)用目標(biāo)資源(即是否讓用戶訪問web資源)。
2、調(diào)用目標(biāo)資源之后,讓一段代碼執(zhí)行。
web服務(wù)器在調(diào)用doFilter方法時,會傳遞一個filterChain對象進來,filterChain對象是filter接口中最重 要的一個對象,它也提供了一個doFilter方法,開發(fā)人員可以根據(jù)需求決定是否調(diào)用此方法,調(diào)用該方法,則web服務(wù)器就會調(diào)用web資源的service方法,即web資源就會被訪問,否則web資源不會被訪問。
三、Filter開發(fā)入門
3.1、Filter開發(fā)步驟
Filter開發(fā)分為二個步驟:
1、編寫java類實現(xiàn)Filter接口,并實現(xiàn)其doFilter方法。
2、在 web.xml 文件中使用<filter>和<filter-mapping>元素對編寫的filter類進行注冊,并設(shè)置它所能攔截的資源。
下面以字符集處理的過濾器進行舉例。
在java開發(fā)中,經(jīng)常會遇到中文亂碼的問題,原因就是頁面提交的中文是ISO88590-1格式的,到后臺如果不進行轉(zhuǎn)碼,就會出現(xiàn)中文亂碼。但是不能每個請求都要手動轉(zhuǎn)碼吧,所以采用filter就可以輕松解決這個問題了。
public class CharacterEncodingFilter implements Filter {
private FilterConfig filterConfig = null;
//設(shè)置默認(rèn)的字符編碼
private String defaultCharset = "UTF-8";
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
String charset = filterConfig.getInitParameter("charset");
if (charset == null) {
charset = defaultCharset;
}
request.setCharacterEncoding(charset);
response.setCharacterEncoding(charset);
response.setContentType("text/html;charset=" + charset);
chain.doFilter(request, response);
}
public void init(FilterConfig filterConfig) throws ServletException {
//得到過濾器的初始化配置信息
this.filterConfig = filterConfig;
}
public void destroy() {
}
}
原理就是在每個請求時,設(shè)置request和response的字符集都是UTF-8
3.2、Filter鏈
在一個web應(yīng)用中,可以開發(fā)編寫多個Filter,這些Filter組合起來稱之為一個Filter鏈。
web服務(wù)器根據(jù) Filter在web.xml文件中的注冊順序,決定先調(diào)用哪個Filter,當(dāng)?shù)谝粋€Filter的doFilter方法被調(diào)用時,web服務(wù)器會創(chuàng)建 一個代表Filter鏈的FilterChain對象傳遞給該方法。在doFilter方法中,開發(fā)人員如果調(diào)用了FilterChain對象的 doFilter方法,則web服務(wù)器會檢查FilterChain對象中是否還有filter,如果有,則調(diào)用第2個filter,如果沒有,則調(diào)用目 標(biāo)資源。
四、Filter的生命周期
4.1、Filter的創(chuàng)建
Filter的創(chuàng)建和銷毀由WEB服務(wù)器負(fù)責(zé)。 web 應(yīng)用程序啟動時,web 服務(wù)器將創(chuàng)建Filter 的實例對象,并調(diào)用其init方法,完成對象的初始化功能,從而為后續(xù)的用戶請求作好攔截的準(zhǔn)備工作,filter對象只會創(chuàng)建一次,init方法也只會執(zhí)行一次。通過init方法的參數(shù),可獲得代表當(dāng)前filter配置信息的FilterConfig對象。
4.2、Filter的銷毀
Web容器調(diào)用destroy方法銷毀Filter。destroy方法在Filter的生命周期中僅執(zhí)行一次。在destroy方法中,可以釋放過濾器使用的資源。
4.3、FilterConfig接口
用戶在配置filter時,可以使用<init-param>為filter配置一些初始化參數(shù),當(dāng)web容器實例化Filter 對象,調(diào)用其init方法時,會把封裝了filter初始化參數(shù)的filterConfig對象傳遞進來。因此開發(fā)人員在編寫filter時,通過 filterConfig對象的方法,就可獲得:
- 1、String getFilterName():得到filter的名稱。
- 2、String getInitParameter(String name): 返回在部署描述中指定名稱的初始化參數(shù)的值。如果不存在返回null.
- 3、Enumeration getInitParameterNames():返回過濾器的所有初始化參數(shù)的名字的枚舉集合。
- 4、public ServletContext getServletContext():返回Servlet上下文對象的引用。
五、Filter的部署
Filter的部署分為兩個步驟:
- 1、注冊Filter
- 2、映射Filter
5.1、注冊Filter
開發(fā)好Filter之后,需要在web.xml文件中進行注冊,這樣才能夠被web服務(wù)器調(diào)用
在web.xml文件中注冊Filter范例:
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>com.critc.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>charset</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
5.2、映射Filter
在web.xml文件中注冊了Filter之后,還要在web.xml文件中映射Filter
<!--映射過濾器-->
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- 1、<filter-mapping>元素用于設(shè)置一個 Filter 所負(fù)責(zé)攔截的資源。一個Filter攔截的資源可通過兩種方式來指定:Servlet 名稱和資源訪問的請求路徑
- 2、<filter-name>子元素用于設(shè)置filter的注冊名稱。該值必須是在<filter>元素中聲明過的過濾器的名字
- 3、<url-pattern>設(shè)置 filter 所攔截的請求路徑(過濾器關(guān)聯(lián)的URL樣式)
現(xiàn)在有了SpringMVC的攔截器和Struts的攔截器,F(xiàn)ilter用的越來越少,不過原理還是要掌握的,便于讀懂歷史項目。