Author:相忠良
Email: ugoood@163.com
起始於:June 17, 2018
最後更新日期:June 18, 2018css
聲明:本筆記依據傳智播客方立勳老師 Java Web 的授課視頻內容記錄而成,中間加入了本身的理解。本筆記目的是強化本身學習所用。如有疏漏或不當之處,請在評論區指出。謝謝。
涉及的圖片,文檔寫完後,一次性更新。html
創建 day19 web工程。java
Filter 簡介:
Filter也稱之爲過濾器,它是Servlet技術中最激動人心的技術,WEB開發人員經過Filter技術,對web服務器管理的全部web資源:例如Jsp, Servlet, 靜態圖片文件或靜態 html 文件等進行攔截,從而實現一些特殊的功能。例如實現URL級別的權限訪問控制、過濾敏感詞彙、壓縮響應信息等一些高級功能。
Servlet API中提供了一個Filter接口,開發web應用時,若是編寫的Java類實現了這個接口,則把這個java類稱之爲過濾器Filter。經過Filter技術,開發人員能夠實現用戶在訪問某個目標資源以前,對訪問的請求和響應進行攔截,以下所示:
web
入門例子:
需求:攔截index.jsp瀏覽器
1.創建cn.wk.web.filter.FilterDemo1
攔截器:緩存
public class FilterDemo1 implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("haha!!!"); chain.doFilter(request, response); // 放行 System.out.println("wowo!!!"); } public void init(FilterConfig filterconfig) throws ServletException {} public void destroy() {} }
2.在 web.xml 中配置攔截器:服務器
<filter> <filter-name>FilterDemo1</filter-name> <filter-class>cn.wk.web.filter.FilterDemo1</filter-class> </filter> <filter-mapping> <filter-name>FilterDemo1</filter-name> <url-pattern>/index.jsp</url-pattern> </filter-mapping>
3.index.jsp:app
<head> <title>Filter入門</title> </head> <body> <% System.out.println("index!!!"); %> </body>
控制檯輸出結果爲:jsp
haha!!! index!!! wowo!!!
觀察結果,瞭解到:
web 瀏覽器 -> web 服務器 -> filter -> index.jsp -> filter -> web 服務器 -> web 瀏覽器
post
filter在開發中的常見應用:
解決亂碼問題:
弄一個filter攔截全部資源:
<filter> <filter-name>FilterDemo1</filter-name> <filter-class>cn.wk.web.filter.FilterDemo1</filter-class> </filter> <filter-mapping> <filter-name>FilterDemo1</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
在FilterDemo1這個filter裏寫:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); chain.doFilter(request, response); // 放行 }
這樣,全部資源全UTF-8編碼,完全解決亂碼問題。
Filter 鏈:
多個filter組成鏈,順序由 web.xml 文件中 filter-mapping 的順序來決定,以下:
filter-mapping 順序爲:
<filter-mapping> <filter-name>FilterDemo1</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>FilterDemo2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
結果爲(即filter鏈裏的filter順序爲先 filter1 後 filter2):
filterdemo1以前!!! filterdemo2以前!!! index!!! filterdemo2以後!!! filterdemo1以後!!!
Filter 的生命週期:
filter 的生命週期和 web 應用是同樣的。
一個攔截器,服務器中只有1個攔截器對象。不一樣攔截器有與之對應的不一樣的攔截器對象。
注意到public void init(FilterConfig filterconfig) {}
中的FilterConfig
對象,這是初始化filter的一個對象。這個對象在web.xml中配置。當filter初始化時,web.xml中相應的配置會被自動讀取。以下:
<filter> <filter-name>FilterDemo1</filter-name> <filter-class>cn.wk.web.filter.FilterDemo1</filter-class> <init-param> <param-name>xxx</param-name> <param-value>yyy</param-value> </init-param> </filter>
程序中輸出初始化參數:
public void init(FilterConfig filterconfig) throws ServletException { String value = filterconfig.getInitParameter("xxx"); System.out.println(value); }
當服務器啓動時,初始化該過濾器同時打印yyy
。有些內容不想在程序中固定,就可經過這種配置的方式設置。
有時咱們想在 doFilter 方法中使用初始化參數,作法是:
FilterDemo1
中定義成員變量private FilterConfig config;
String value = this.config.getInitParameter("xxx");
得到參數值。package cn.wk.web.filter.example; public class CharacterEncodingFilter implements Filter { private FilterConfig config; private String defaultCharset = "UTF-8"; // <- 默認 public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { // 獲取要設置的字符集 String charset = this.config.getInitParameter("charset"); if (charset == null) charset = defaultCharset; HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; request.setCharacterEncoding(charset); response.setCharacterEncoding(charset); response.setContentType("text/html;charset" + charset); chain.doFilter(request, response); } public void destroy() {} public void init(FilterConfig arg0) throws ServletException {} }
web.xml配置,還配置了初始化參數charset,以下:
<filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>cn.wk.web.filter.example.CharacterEncodingFilter</filter-class> <init-param> <param-name>charset</param-name> <!--charset 設置--> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
這樣,該 web 應用之後不用再考慮亂碼問題,且可在 web.xml 文件中的過濾器中靈活設置 charset。
常見應用2,故事:
因爲 jsp 顯示內容來源於 servlet,內容是動態的,因此緩存 jsp 文件沒意義。因此,如今要作一個不緩存jsp文件的過濾器。
控制不緩存的過濾器:
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; // 設定3頭,不留緩存 response.setDateHeader("Expires", -1); response.setHeader("Cache-Control", "no-cache"); response.setHeader("Pragma", "no-cache"); chain.doFilter(request, response); }
web.xml中cache-mapping的配置:
<filter-mapping> <filter-name>NoCacheFilter</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping>
常見應用3:控制瀏覽器緩存頁面中的靜態資源的過濾器
場景:有些動態頁面中引用了一些圖片或css文件以修飾頁面效果,這些圖片和css文件常常是不變化的,因此爲減輕服務器的壓力,可使用 filter 控制瀏覽器緩存這些文件,以提高服務器的性能。
靈活的過濾器:
<filter> <filter-name>CacheFilter</filter-name> <filter-class>cn.wk.web.filter.example.CacheFilter</filter-class> <init-param> <param-name>css</param-name> <param-value>10</param-value> <!--css 緩存10分鐘--> </init-param> <init-param> <param-name>jpg</param-name> <param-value>1</param-value> <!--jpg 緩存1分鐘--> </init-param> <init-param> <param-name>js</param-name> <param-value>20</param-value> <!--js 緩存1分鐘--> </init-param> </filter> <!--同一個 filter,三種 mapping--> <filter-mapping> <filter-name>CacheFilter</filter-name> <url-pattern>*.jpg</url-pattern> </filter-mapping> <filter-mapping> <filter-name>CacheFilter</filter-name> <url-pattern>*.css</url-pattern> </filter-mapping> <filter-mapping> <filter-name>CacheFilter</filter-name> <url-pattern>*.js</url-pattern> </filter-mapping>
cn.wk.web.filter.example.CacheFilter
代碼:
// 控制瀏覽器緩存的過濾器 public class CacheFilter implements Filter { private FilterConfig config; public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; // 1. 獲取用戶想訪問的資源 String uri = request.getRequestURI(); // 2. 獲取該資源的緩存時間 int expires = 0; if (uri.endsWith(".jpg")) { expires = Integer.parseInt(this.config.getInitParameter("jpg")); } else if (uri.endsWith(".js")) { expires = Integer.parseInt(this.config.getInitParameter("js")); } else { expires = Integer.parseInt(this.config.getInitParameter("css")); } response.setDateHeader("expires", System.currentTimeMillis() + expires * 60 * 1000); chain.doFilter(request, response); } public void init(FilterConfig filterconfig) throws ServletException { this.config = filterconfig; } public void destroy() {} }
略
<filter-mapping>
元素用於設置一個 Filter 所負責攔截的資源。
一個Filter攔截的資源可經過兩種方式來指定:Servlet 名稱 和 資源訪問的請求路徑。
<filter-name>
子元素用於設置filter的註冊名稱。該值必須是在<filter>
元素中聲明過的過濾器的名字<url-pattern>
設置 filter 所攔截的請求路徑(過濾器關聯的URL樣式)<servlet-name>
指定過濾器所攔截的Servlet名稱。<dispatcher>
指定過濾器所攔截的資源被 Servlet 容器調用的方式,能夠是 REQUEST,INCLUDE,FORWARD和ERROR之一,默認REQUEST。用戶能夠設置多個
一個資源被調用的方式共有四種:REQUEST, INCLUDE, FORWARD 和 ERROR。
例子,如圖:
上圖中表示:servlet forward(request, response) 到一個jsp頁面。此時,若作對jsp攔截器,控制緩存的話,就需在攔截器中設置<dispatcher>FORWARD</dispatcher>
,才能觸發這個攔截器。
部署案例:
<filter-mapping> <filter-name>testFilter</filter-name> <url-pattern>/test.jsp</url-pattern> </filter-mapping> <filter-mapping> <filter-name>testFilter</filter-name> <url-pattern>/index.jsp</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> </filter-mapping>
下面代碼解決了包括post和get請求在內的全部亂碼問題。
HttpServletRequestWrapper
包裝類,避免本身一個個覆蓋不想加強的方法!注意:request.setCharacterEncoding("UTF-8");
只解決 post,不能解決 get 亂碼問題。
本案例經過重寫 getParameter() 方法,調整得到值得編碼從 iso8859-1 到 request.getCharacterEncoding() 方法所指定的編碼方式完成 get 請求方式下的亂碼解決問題。
//真正解決全站亂碼 public class CharacterEncodingFilter2 implements Filter { public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; request.setCharacterEncoding("UTF-8"); // 只解決 post,不能解決 get response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); chain.doFilter(new MyRequest(request), response); //request.getparameter("password"); } /* 1.寫一個類,實現與被加強對象相同的接口 2.定義一個變量,記住被加強對象 3.定義一個構造方法,接收被加強對象 4.覆蓋想加強的方法 5.對於不想加強的方法,直接調用被加強對象(目標對象)的方法 */ class MyRequest extends HttpServletRequestWrapper{ private HttpServletRequest request; public MyRequest(HttpServletRequest request) { super(request); this.request = request; } public String getParameter(String name) { String value = this.request.getParameter(name); if(!request.getMethod().equalsIgnoreCase("get")) {return value;} if(value==null){return null;} try { return value = new String(value.getBytes("iso8859-1"), request.getCharacterEncoding()); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e);}}} public void destroy() {} public void init(FilterConfig filterConfig) throws ServletException {} }
不要忘記在 web.xml 中配置這個過濾器,配置方法略。
之後再說。