java filter過濾器的功能簡要介紹

filter功能.它使用戶可以改變一個 request和修改一個response. Filter 不是一個servlet,它不能產生一個response,它能夠在一個request到達servlet之前預處理request,也可以在離開 servlet時處理response.換種說法,filter其實是一個”servlet chaining”(servlet 鏈).
一個filter 包括:
1. 在servlet被調用之前截獲;
2. 在servlet被調用之前檢查servlet request;
3. 根據需要修改request頭和request數據;
4. 根據需要修改response頭和response數據;
5. 在servlet被調用之後截獲.
通俗點說法filter相當於加油站,request是條路,response是條路,目的地是servlet,這個加油站設在什麼地方對什麼數據操作可以由你來控制。
一些需要過濾器的情況:
(1)認證Filter
(2)日誌和審覈Filter
(3)圖片轉換Filter
(4)數據壓縮Filter
(5)密碼Filter
(6)令牌Filter
(7)觸發資源訪問事件的Filter
(8)XSLT Filter
(9)媒體類型鏈Filter
1.批量設置請求編碼
爲了避免提交數據的中文亂碼問題,需要在每次使用請求之前設置request.setCharacterEncoding(“gb2312”)編碼格式,麻煩。Filter可以批量攔截修改servlet的請求和響應。
我們編寫一個EncodingFilter.java,來批量設置請求編碼。
public class EncodingFilter implements Filter {
public void init(FilterConfig config) throws ServletException {}
public void destroy() {}
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
request.setCharacterEncoding(“gb2312”);
chain.doFilter(request, response);
}
}
在此EncodingFilter實現了Filter接口,Filter接口中定義的三個方法都要在EncodingFilter中實現,其中doFilter()的代碼實現主要的功能:

爲請求設置gb2312編碼並執行chain.doFilter()繼續下面的操作。
轉換成對應HttpServletRequest和HttpServletResponse才能進行下面的session操作和頁面重定向。
與servlet相似,爲了讓filter發揮作用還需要在web.xml進行配置。

EncodingFilter
sam.EncodingFilter


EncodingFilter
/*

filter標籤部分定義使用的過濾器,filter-mapping標籤告訴服務器把哪些請求交給過濾器處理。這裏的/表示所有請求,/表示根路徑,(星號)代表所有請求,加在一起就變成了根路徑下的所有請求。
這樣,所有的請求都會先被EncodingFilter攔截,並在請求裏設置上指定的gb2312編碼。
2.用filter控制用戶訪問權限
出於信息安全和其他一些原因的考慮,項目中的一些頁面要求用戶滿足了一定條件之後才能訪問讓用戶輸入帳號和密碼,如果輸入的信息正確就在session裏做一個成功的標記,這裏的成功標誌就是session中的username有值;
其後在請求保密信息的時候判斷session中是否有已經登錄成功的標記,存在則可以訪問,不存在則禁止訪問。
假設我們要保護的頁面是admin/index.jsp
編寫SecurityFilter.java,控制用戶訪問權限
public class SecurityFilter implements Filter {
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {

HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
HttpSession session = req.getSession();
if (session.getAttribute("username") != null) {
    chain.doFilter(request, response);
} else {
    res.sendRedirect("../failure.jsp");
}

}
web.xml進行如下配置

SecurityFilter
sam.SecurityFilter


SecurityFilter
/admin/*

定義SecurityFilter過濾器,讓它過濾匹配/admin/*的所有請求,/admin/路徑下的所有請求都會接受SecurityFilter的檢查
因爲Filter本來設計成爲多種協議服務,http協議僅僅是其中一種,將ServletRequest和ServletResponse轉換成HttpServletRequest和HttpServletResponse才能進行下面的session操作和頁面重定向。
得到了http請求之後,可以獲得請求對應的session,判斷session中的username變量是否爲null,如果不爲null,說明用戶已經登錄,就可以調用doFilter繼續請求訪問的資源。如果爲null,說明用戶還沒有登錄,禁止用戶訪問,並使用頁面重定向跳轉到failure.jsp頁面顯示提示信息。
因爲/failure.jsp的位置在/admin/目錄的上一級,所以加上兩個點才能正確跳轉到failure.jsp,兩個點(..)代表當前路徑的上一級路徑。
3.日誌和審覈Filter
public class LoggingFilter implements Filter {
private FilterConfig filterConfig = null;
public void init(FilterConfig config) throws ServletException {
this.filterConfig = config;
}

//下面是向服務器控制檯輸出log,這裏做的是演示,更多的是使用log4j
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
String address = request.getRemoteAddr();
filterConfig.getServletContext().log(“User IP: ” + address);
chain.doFilter(request, response);
}
public void destroy() {
}
}
web.xml配置

LoggingFilter
samjava.filter.LoggingFilter


LoggingFilter
/*

4.filter所謂的特性
請求映射filter-mapping和servlet-mapping都是將對應的filter或servlet映射到某個url-pattern上,當客戶發起某一請求時,服務器先將此請求與web.xml中定義的所有url-pattern進行匹配,然後執行匹配通過的filter和servlet。
你可以使用三種方式定義url-pattern。
直接映射一個請求。

TestServlet
/TestServlet

映射一個路徑下的所有請求。

EncodingFilter
/*

需要注意的是,這種寫法必須以/開頭,寫成與絕對路徑的形式,即便是映射所有請求也要寫成/,不能簡化成
映射結尾相同的一類請求。

ControllerServlet
*.do

需要注意的是,這種請求映射就不能指定某一路徑了,它必須是以星號()開始字母結尾,不能寫成/.do的形式。
5.過濾鏈
我們使用了兩個過濾器,EncodingFilter負責設置編碼,SecurityFilter負責控制權限,那這兩個過濾器是怎麼起作用的呢?
所有的奧祕就在Filter中的FilterChain中。服務器會按照web.xml中過濾器定義的先後循序組裝成一條鏈,然後一次執行其中的doFilter()方法。執行的順序就如上圖所示,執行第一個過濾器的chain.doFilter()之前的代碼,第二個過濾器的chain.doFilter()之前的代碼,請求的資源,第二個過濾器的chain.doFilter()之後的代碼,第一個過濾器的chain.doFilter()之後的代碼,最後返回響應。
代碼執行順序是:
(1)執行EncodingFilter.doFilter()中chain.doFilter()之前的部分:request.setCharacterEncoding(“gb2312”);
(2)執行SecurityFilter.doFilter()中chain.doFilter()之前的部分:判斷用戶是否已登錄
(3)如果用戶已登錄,則訪問請求的資源:/admin/index.jsp
(4)如果用戶未登錄,則頁面重定向到:/failure.jsp
(5)執行SecurityFilter.doFilter()中chain.doFilter()之後的部分;
(6)執行EncodingFilter.doFilter()中chain.doFilter()之後的部分;
說的簡單點就是filter將按照在web.xml文件中的聲明順序調用。
過濾鏈的好處是,執行過程中任何時候都可以打斷,只要不執行chain.doFilter()就不會再執行後面的過濾器和請求的內容。
要特別注意過濾鏈的執行順序問題,像EncodingFilter就一定要放在所有Filter之前(在web.xml文件中),這樣才能確保在使用請求中的數據前設置正確的編碼。

6.filter的詳細配置
我們已經瞭解了filter的基本用法,還有一些細節配置在特殊情況下起作用。
在servlet-2.3中,Filter會過濾一切請求,包括服務器內部使用forward轉發請求和<%@ include file=”/index.jsp”%>的情況。
到了servlet-2.4中Filter默認下只攔截外部提交的請求,forward和include這些內部轉發都不會被過濾,但是有時候我們需要forward的時候也用到Filter,這樣就需要如下配置。

TestFilter
sam.TestFilter


TestFilter
/*
REQUEST
FORWARD
INCLUDE
EXCEPTION

這樣TestFilter就會過濾所有狀態下的請求。如果我們沒有進行設置,默認使用的就是REQUEST。而EXCEPTION是在isErrorPage=”true”的情況下出現的,這個用處不多,看一下即可。
這裏FORWARD是解決request.getDispatcher(“index.jsp”).forward(request, response);無法觸發Filter的關鍵,配置上這個以後再進行forward的時候就可以觸發過濾器了。

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/yudaoai/archive/2009/06/01/4231333.aspx

Filter是Web編程裏一把利器,它本質上就是一個攔截器,但實際應用中很靈活,用途也很廣,下面是本人在開發中對filter應用的一個小結:
1)轉換字符編碼
中文網頁編碼常用的就是gb2312或是UTF-8,但TOMCAT會默認用編碼iso-8859-1,所以需要把所有經過TOMCAT的中文字符進行轉換,如果手動在request裏改很麻煩,可以用一個filter對所有的request進行攔截,進行編碼轉換,一勞永逸
2)管理Hibernate的session
在Web 裏用Hibernate常常是把session綁定到線程,但往往要求一個session在一個請求的活動中都有效,這樣可以保證同一活動中能共享 lazy bean。用filter能到達這個目的,在doFilter之前綁定session到線程,在doFilter後關閉session,這樣既可以保證 session不會泄漏,也能讓lazy bean在同一請求週期裏共享
3)做權限審查
在web層裏需要對很多資源進行邏輯類似的安全保障,通過filter可以在調用這些資源前加上一個屏障,這樣既可以把安全代碼和邏輯代碼相分離,也可以很好的reuse這些安全模塊
4)做cache
在web層常常需要對一些請求返回進行緩存,這樣可以有效的減輕服務器的壓力,filter可以對請求進行攔截,查詢緩存,若有效則直接返回緩存內容,若無效則進行實際的服務器請求,返回給用戶,並對緩存進行更新,以備下次請求
5)做攔截器的代理
有的時候需要把一些攔截器用到web層,filter可以很好地充當代理的角色,比如可以在Spring裏做好攔截器的Bean,再通過filter把這些Bean和相應的web請求橋接起來。
6)過濾特殊字符
有時需要過濾特殊字符,比如防止sql注入,Filter可以很好達到這個目的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章