過濾器(Filter)
1. 簡介
過濾器可以動態地攔截請求和響應,以變換或使用包含在請求或響應中的信息,它是 Servlet 技術中最實用的技術,屬於系統級別,主要是利用函數的回調實現。對 Jsp, Servlet 靜態圖片文件或靜態 html 文件等進行攔截。主要應用的場景有:如實現 URL 級別的權限訪問控制、過濾敏感詞匯、壓縮響應信息、設置字符編碼等一些高級功能。
它主要用於對用戶請求進行預處理,也可以對HttpServletResponse 進行后處理。使用Filter 的完整流程:Filter 對用戶請求進行預處理,接着將請求交給Servlet 進行處理並生成響應,最后Filter 再對服務器響應進行后處理。
Filter功能:
- 在HttpServletRequest 到達 Servlet 之前,攔截客戶的 HttpServletRequest 。 根據需要檢查 HttpServletRequest ,也可以修改HttpServletRequest 頭和數據。
- 在HttpServletResponse 到達客戶端之前,攔截HttpServletResponse 。 根據需要檢查 HttpServletResponse ,也可以修改HttpServletResponse頭和數據。
2. 方法
序號 | 方法 |
1 | public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) 該方法完成實際的過濾操作,當客戶端請求方法與過濾器設置匹配的 URL 時,Servlet 容器將先調用過濾器的 doFilter 方法。 FilterChain 用戶訪問后續過濾器。 |
2 | public void init(FilterConfig filterConfig) web 應用程序啟動時,web 服務器將創建 Filter 的實例對象,並調用其 init 方法,讀取 web.xml 配置,完成對象的初始化功能, 從而為后續的用戶請求作好攔截的准備工作(filter 對象只會創建一次,init 方法也只會執行一次)。開發人員通過 init 方法的參數, 可獲得代表當前 filter 配置信息的 FilterConfig 對象。 |
3 | public void destroy() Servlet 容器在銷毀過濾器實例前調用該方法,在該方法中釋放 Servlet 過濾器占用的資源。 |
3. 應用順序
web.xml 中的 filter-mapping 元素的順序決定了 Web 容器應用過濾器到 Servlet 的順序。
4. web.xml 文件配置信息
|
5. 應用實例
(1)簡單結構
1 public class AuthorityFilter implements Filter { 2 3 /** 4 * 銷毀 5 */ 6 @Override 7 public void destroy() { 8 9 } 10 11 @Override 12 public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) 13 throws IOException, ServletException { 14 HttpServletRequest request = (HttpServletRequest) req; 15 HttpServletResponse response = (HttpServletResponse) resp; 16 HttpSession session = request.getSession(); 17 18 boolean flag = false; 19 if(xxx) { 20 flag = false; 21 } else { 22 flag = true; 23 } 24 if (flag) { 25 chain.doFilter(req, resp); 26 return; 27 } else { 28 // 這是返回403錯誤 29 response.sendError(HttpServletResponse.SC_FORBIDDEN, ""); 30 return; 31 } 32 } 33 34 /** 35 * 初始化 36 */ 37 @Override 38 public void init(FilterConfig filterConfig) throws ServletException { 39 40 } 41 42 }
web.xml 配置
1 <filter> 2 <filter-name>authorityFilter</filter-name> 3 <filter-class>com.jd.nw.filter.AuthorityFilter</filter-class> 4 </filter> 5 <filter-mapping> 6 <filter-name>authorityFilter</filter-name> 7 <url-pattern>*</url-pattern> 8 </filter-mapping>
(2)中文亂碼過濾器
項目使用spring框架時。當前台JSP頁面和Java代碼中使用了不同的字符集進行編碼的時候就會出現表單提交的數據或者上傳/下載中文名稱文件出現亂碼的問題,那就可以使用這個過濾器。
<filter> <filter-name>encoding</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name><!--用來指定一個具體的字符集--> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name><!--true:無論request是否指定了字符集,都是用encoding;false:如果request已指定一個字符集,則不使用encoding--> <param-value>false</param-value> </init-param> </filter> <filter-mapping> <filter-name>encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
(3) Spring + Hibernate 的 OpenSessionInViewFilter 控制 session 的開關
當 hibernate + spring 配合使用的時候,如果設置了 lazy = true(延遲加載),那么在讀取數據的時候,當讀取了父數據后,hibernate 會自動關閉 session,這樣,當要使用與之關聯數據、子數據的時候,系統會拋出 lazyinit 的錯誤,這時就需要使用 spring 提供的OpenSessionInViewFilter 過濾器。
OpenSessionInViewFilter 主要是保持 Session 狀態直到 request 將全部頁面發送到客戶端,直到請求結束后才關閉 session,這樣就可以解決延遲加載帶來的問題。
注意:OpenSessionInViewFilter 配置要寫在 struts2 的配置前面。因為 tomcat 容器在加載過濾器的時候是按照順序加載的,如果配置文件先寫的是 struts2 的過濾器配置,然后才是 OpenSessionInViewFilter 過濾器配置,所以加載的順序導致,action 在獲得數據的時候 session 並沒有被 spring 管理。
1 <filter> 2 <filter-name>OpenSessionInViewFilter</filter-name> 3 <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> 4 <init-param> 5 <param-name>sessionFactoryBeanName</param-name><!-- 可缺省。默認是從spring容器中找id為sessionFactory的bean,如果id不為sessionFactory,則需要配置如下,此處SessionFactory為spring容器中的bean。 --> 6 <param-value>sessionFactory</param-value> 7 </init-param> 8 <init-param> 9 <param-name>singleSession</param-name><!-- singleSession默認為true,若設為false則等於沒用OpenSessionInView --> 10 <param-value>true</param-value> 11 </init-param> 12 </filter> 13 <filter-mapping> 14 <filter-name>OpenSessionInViewFilter</filter-name> 15 <url-pattern>*.do</url-pattern> 16 </filter-mapping>
6. 總結
過濾器顧名思義是用來過濾的,Java 的過濾器能夠為我們提供系統級別的過濾,也就是說,能過濾所有的 web 請求,這一點,是攔截器無法做到的。在 Java Web 中,你傳入的 request,response 提前過濾掉一些信息,或者提前設置一些參數,然后再傳入 servlet 或者 action 進行業務邏輯,比如過濾掉非法 url,或者在傳入servlet或者struts的action前統一設置字符集,或者去除掉一些非法字符。filter 流程是線性的,url 傳來之后,檢查之后,可保持原來的流程繼續向下執行,被下一個 filter, servlet 接收。
參考資料: