原文: http://www.cnblogs.com/Fskjb/archive/2010/03/27/1698448.html
?
Filter介紹 ?
Filter可認為是Servlet的一種“變種”,它主要用于對用戶請求進行預處理,也可以對HttpServletResponse進行后處理,是個典型的處理鏈。它與Servlet的區別在于:它不能直接向用戶生成響應。完整的流程是: Filter對用戶請求進行預處理,接著將請求交給Servlet進行處理并生成響應,最后Filter再對服務器響應進行后處理。
Filter有如下幾個用處。
- 在HttpServletRequest到達Servlet之前,攔截客戶的HttpServletRequest。
- 根據需要檢查HttpServletRequest,也可以修改HttpServletRequest頭和數據。
- 在HttpServletResponse到達客戶端之前,攔截HttpServletResponse。
- 根據需要檢查HttpServletResponse,也可以修改HttpServletResponse頭和數據。
Filter有如下幾個種類。
- 用戶授權的Filter:Filter負責檢查用戶請求,根據請求過濾用戶非法請求。
- 日志Filter:詳細記錄某些特殊的用戶請求。
- 負責解碼的Filter:包括對非標準編碼的請求解碼。
- 能改變XML內容的XSLT Filter等。
- Filter可負責攔截多個請求或響應;一個請求或響應也可被多個請求攔截。
創建一個Filter只需兩個步驟:
- 建Filter處理類;
- web.xml文件中配置Filter。
?
下面先介紹一個簡單的記錄日志的Filter,這個Filter負責攔截所有的用戶請求,并將請求的信息記錄在日志中。
?

{
// FilterConfig可用于訪問Filter的配置信息
private ?FilterConfig?config;
// 實現初始化方法
public ? void ?init(FilterConfig?config)
{
this .config? = ?config;?
}
// 實現銷毀方法
public ? void ?destroy()
{
this .config? = ? null ;?
}
// 執行過濾的核心方法
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;
// 記錄日志
context.log( " Filter已經截獲到用戶的請求地址:? " ? + ?hrequest.getServletPath());
// Filter只是鏈式處理,請求依然放行到目的地址
chain.doFilter(request,?response);?
// ---------下面代碼用于對服務器響應執行后處理---------
long ?after? = ?System.currentTimeMillis();
// 記錄日志
context.log( " 過濾結束 " );
// 再次記錄日志
context.log( " 請求被定位到 " ? + ?hrequest.getRequestURI()? + ? " 所花的時間為:? " ? + ?(after? - ?before));?
}
}
?
?
上面程序實現了doFilter()方法,實現該方法就可實現對用戶請求進行預處理,也可實現對服務器響應進行后處理——它們的分界線為是否調用了chain.doFilter(),執行該方法之前,即對用戶請求進行預處理;執行該方法之后,即對服務器響應進行后處理。
在上面的請求Filter中,僅在日志中記錄請求的URL,對所有的請求都執行chain.doFilter (request,reponse)方法,當Filter對請求過濾后,依然將請求發送到目的地址。如果需要檢查權限,可以在Filter中根據用戶請求的HttpSession,判斷用戶權限是否足夠。如果權限不夠,直接調用重定向即可,無須調用chain.doFilter(request,reponse)方法。
?
?

================== ???
package ?com.test.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;???
??
public ? class ?FirstFilter? implements ?Filter?{???
??
????@Override??
???? public ? void ?destroy()?{???
??
????}???
??
????@Override??
???? public ? void ?doFilter(ServletRequest?request,?ServletResponse?response,???
????????????FilterChain?chain)? throws ?IOException,?ServletException?{???
????????System.out.println( " before?invoke?firstFilter's?chain.doFilter()?.. " );???
????????chain.doFilter(request,?response);???
????????System.out.println( " after?invoke?firstFilter's?chain.doFilter()?.. " );???
????}???
??
????@Override??
???? public ? void ?init(FilterConfig?arg0)? throws ?ServletException?{???
????????System.out.println( " firstFilter?init()... " );?
??
============ ???
SecondFilter.java ???
============= ??
??
package ?com.test.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;???
??
public ? class ?SecondFilter? implements ?Filter?{???
??
????@Override??
???? public ? void ?destroy()?{???
??
????}???
??
????@Override??
???? public ? void ?doFilter(ServletRequest?request,?ServletResponse?response,???
????????????FilterChain?chain)? throws ?IOException,?ServletException?{???
????????System.out.println( " before?invoke?secondFilter's?chain.doFilter()?.. " );???
????????chain.doFilter(request,?response);???
????????System.out.println( " after?invoke?secondFilter's?chain.doFilter()?.. " );???
????}???
??
????@Override??
???? public ? void ?init(FilterConfig?filterConfig)? throws ?ServletException?{???
????????System.out.println( " secondFilter?init()... " );???
????}
========== ??
FirstServlet.java ???
========== ??
package ?com.test.servlet;???
??
import ?java.io.IOException;???
??
import ?javax.servlet.ServletException;???
import ?javax.servlet.http.HttpServlet;???
import ?javax.servlet.http.HttpServletRequest;???
import ?javax.servlet.http.HttpServletResponse;???
??
public ? class ?FirstServlet? extends ?HttpServlet?{???
??
????@Override??
???? protected ? void ?doGet(HttpServletRequest?req,?HttpServletResponse?resp)???
???????????? throws ?ServletException,?IOException?{???
????????System.out.println( " servlet?doGet?be?invoked... " );???
????????req.getRequestDispatcher( " test.jsp " ).forward(req,?resp);???
????}???
??
????@Override??
???? protected ? void ?doPost(HttpServletRequest?req,?HttpServletResponse?resp)???
???????????? throws ?ServletException,?IOException?{???
???????? // ?TODO?Auto-generated?method?stub???
????????doGet(req,?resp);???
????}?
?
web.xml ??

<? xml?version="1.0"?encoding="UTF-8" ?> ???
< web-app? version ="2.5" ?xmlns ="http://java.sun.com/xml/ns/javaee" ??
????xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" ??
????xsi:schemaLocation ="http://java.sun.com/xml/ns/javaee????
????http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" > ???
???? < welcome-file-list > ???
???????? < welcome-file > index.jsp </ welcome-file > ???
???? </ welcome-file-list > ???
???? < filter > ???
???????? < filter-name > firstFilter </ filter-name > ???
???????? < filter-class > com.test.filter.FirstFilter </ filter-class > ???
???? </ filter > ???
???? < filter > ???
???????? < filter-name > secondFilter </ filter-name > ???
???????? < filter-class > com.test.filter.SecondFilter </ filter-class > ???
???? </ filter > ???
???? < filter-mapping > ???
???????? < filter-name > secondFilter </ filter-name > ???
???????? < url-pattern > /* </ url-pattern > ???
???? </ filter-mapping > ???
???? < filter-mapping > ???
???????? < filter-name > firstFilter </ filter-name > ???
???????? < url-pattern > /* </ url-pattern > ???
???? </ filter-mapping > ???
??
???? < servlet > ???
???????? < servlet-name > firstServlet </ servlet-name > ???
???????? < servlet-class > com.alimama.servlet.FirstServlet </ servlet-class > ???
???? </ servlet > ???
???? < servlet-mapping > ???
???????? < servlet-name > firstServlet </ servlet-name > ???
???????? < url-pattern > /firstServlet </ url-pattern > ???
???? </ servlet-mapping > ???
</ web-app > ???
?
?然后發布,發現打印的日志如下:
。。。
firstFilter init()...
secondFilter init()...
。。。
信息: Server startup in 3665 ms
?
這里過濾器初始化好了。
當我們訪問我們的 應用: http://127.0.0.1:8080/appName
發現打印日記如下:
before invoke secondFilter's chain.doFilter() ..
before invoke firstFilter's chain.doFilter() ..
after invoke firstFilter's chain.doFilter() ..
after invoke secondFilter's chain.doFilter() ..
?
當我們將web.xml中filter的位置進行調整后(注意 filter-mapping 的順序):
?

< web-app? version ="2.5" ?xmlns ="http://java.sun.com/xml/ns/javaee" ??
????xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" ??
????xsi:schemaLocation ="http://java.sun.com/xml/ns/javaee????
????http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" > ??
???? < welcome-file-list > ??
???????? < welcome-file > index.jsp </ welcome-file > ??
???? </ welcome-file-list > ??
???? < filter > ??
???????? < filter-name > firstFilter </ filter-name > ??
???????? < filter-class > com.test.filter.FirstFilter </ filter-class > ??
???? </ filter > ??
???? < filter > ??
???????? < filter-name > secondFilter </ filter-name > ??
???????? < filter-class > com.test.filter.SecondFilter </ filter-class > ??
???? </ filter > ??
???????????? < SPAN? style ="COLOR:?#ff0000" > ? < filter-mapping > ??
???????? < filter-name > firstFilter </ filter-name > ??
???????? < url-pattern > /* </ url-pattern > ??
???? </ filter-mapping > ??
??
???? < filter-mapping > ??
???????? < filter-name > secondFilter </ filter-name > ??
???????? < url-pattern > /* </ url-pattern > ??
???? </ filter-mapping ></ SPAN > ??
???????
???? < servlet > ??
???????? < servlet-name > firstServlet </ servlet-name > ??
???????? < servlet-class > com.alimama.servlet.FirstServlet </ servlet-class > ??
???? </ servlet > ??
???? < servlet-mapping > ??
???????? < servlet-name > firstServlet </ servlet-name > ??
???????? < url-pattern > /firstServlet </ url-pattern > ??
???? </ servlet-mapping > ??
</ web-app > ??
?
?
然后在啟動應用,會看到打印:
before invoke firstFilter's chain.doFilter() ..
before invoke secondFilter's chain.doFilter() ..
after invoke secondFilter's chain.doFilter() ..
after invoke firstFilter's chain.doFilter() ..
?
?
下面是一個實例:
?

?
?
上面Filter的doFilter方法里3行斜體字代碼用于獲取Filter的配置參數,而程序中粗體字代碼則是此Filter的核心,①號代碼按配置參數設置了request編碼所用的字符集,接下來的粗體字代碼判斷session范圍內是否有user屬性——沒有該屬性即認為沒有登錄,如果既沒有登錄,而且請求地址也不是登錄頁和處理登錄頁,系統直接跳轉到登錄頁面。
在web.xml文件中配置該Filter,使用init-param元素為該Filter配置參數,init-param可接受如下兩個子元素:
param-name:指定參數名。
param-value:指定參數值。
該Filter的配置片段如下:

?
上面配置片段中粗體字代碼為該Filter指定了3個配置參數,指定loginPage為/login.jsp,proLogin為/proLogin.jsp,這表明:如果沒有登錄該應用,普通用戶只能訪問/login.jsp和/proLogin.jsp頁面。只有當用戶登錄該應用后才可自由訪問其他頁面。
?
?
實際上Filter和Servlet極其相似,區別只是Filter不能直接對用戶生成響應。實際上Filter里doFilter()方法里的代碼就是從多個Servlet的service()方法里抽取的通用代碼,通過使用Filter可以實現更好的復用。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
