方立勋_30天掌握JavaWeb_Servlet Filter(过滤器)未完
Filter簡介
Filter也稱之為過濾器,它是Servlet技術中最激動人心的技術,WEB開發人員通過Filter技術,對web服務器管理的所有web資源:例如Jsp, Servlet, 靜態圖片文件或靜態 html 文件等進行攔截,從而實現一些特殊的功能。例如實現URL級別的權限訪問控制、過濾敏感詞匯、壓縮響應信息等一些高級功能。
Servlet API中提供了一個Filter接口,開發web應用時,如果編寫的Java類實現了這個接口,則把這個java類稱之為過濾器Filter。通過Filter技術,開發人員可以實現用戶在訪問某個目標資源之前,對訪問的請求和響應進行攔截,如下所示:
Filter是如何實現攔截的?
Filter接口中有一個doFilter方法,當開發人員編寫好Filter,并配置對哪個web資源進行攔截后,WEB服務器每次在調用web資源的service方法之前,都會先調用一下filter的doFilter方法,因此,在該方法內編寫代碼可達到如下目的:
1. 調用目標資源之前,讓一段代碼執行
2. 是否調用目標資源(即是否讓用戶訪問web資源)
web服務器在調用doFilter方法時,會傳遞一個filterChain對象進來,filterChain對象是filter接口中最重要的一個對象,它也提供了一個doFilter方法,開發人員可以根據需求決定是否調用此方法,調用該方法,則web服務器就會調用web資源的service方法,即web資源就會被訪問,否則web資源不會被訪問。
3. 調用目標資源之后,讓一段代碼執行
filter在開發中的常見應用:
1. filter可以目標資源執行之前,進行權限檢查,檢查用戶有無權限,如有權限則放行,如沒有,則拒絕訪問
2. filter可以放行之前,對request和response進行預處理,從而實現一些全局性的設置
3. filter在放行之后,可以捕獲目標資源的輸出,從而對輸出做出類似于壓縮這樣的設置
筆記重點:
點擊頁面超鏈接 和 刷新的區別?
A:點擊鏈接,先看本地是否有緩存,有的話,則取出;刷新是每次刷新都是向服務器發送請求。
Filter開發入門
Filter開發分為二個步驟:
1. 編寫java類實現Filter接口,并實現其doFilter方法。
2. 在 web.xml 文件中使用和元素對編寫的filter類進行注冊,并設置它所能攔截的資源。
Filter鏈
在一個web應用中,可以開發編寫多個Filter,這些Filter組合起來稱之為一個Filter鏈。
web服務器根據Filter在web.xml文件中的注冊順序,決定先調用哪個Filter,當第一個Filter的doFilter方法被調用時,web服務器會創建一個代表Filter鏈的FilterChain對象傳遞給該方法。在doFilter方法中,開發人員如果調用了FilterChain對象的doFilter方法,則web服務器會檢查FilterChain對象中是否還有filter,如果有,則調用第2個filter,如果沒有,則調用目標資源。
Filter的生命周期
init(FilterConfig filterConfig)throws ServletException:
和我們編寫的Servlet程序一樣,Filter的創建和銷毀由WEB服務器負責。 web 應用程序啟動時,web 服務器將創建Filter 的實例對象,并調用其init方法,完成對象的初始化功能,從而為后續的用戶請求作好攔截的準備工作(注:filter對象只會創建一次,init方法也只會執行一次。示例 )
開發人員通過init方法的參數,可獲得代表當前filter配置信息的FilterConfig對象。(filterConfig對象見下頁PPT)
destroy():
在Web容器卸載 Filter 對象之前被調用。該方法在Filter的生命周期中僅執行一次。在這個方法中,可以釋放過濾器使用的資源。
FilterConfig接口
用戶在配置filter時,可以使用為filter配置一些初始化參數,當web容器實例化Filter對象,調用其init方法時,會把封裝了filter初始化參數的filterConfig對象傳遞進來。因此開發人員在編寫filter時,通過filterConfig對象的方法,就可獲得:
- String getFilterName():得到filter的名稱。
- String getInitParameter(String name): 返回在部署描述中指定名稱的初始化參數的值。如果不存在返回null.
- Enumeration getInitParameterNames():返回過濾器的所有初始化參數的名字的枚舉集合。
- public ServletContext getServletContext():返回Servlet上下文對象的引用。
Filter常見應用
統一全站字符編碼的過濾器:
通過配置參數encoding指明使用何種字符編碼,以處理Html Form請求參數的中文問題
禁止瀏覽器緩存所有動態頁面的過濾器:
- 有 3 個 HTTP 響應頭字段都可以禁止瀏覽器緩存當前頁面,它們在 Servlet 中的示例代碼如下:
response.setDateHeader(“Expires”,-1);
response.setHeader(“Cache-Control”,”no-cache”);
response.setHeader(“Pragma”,”no-cache”); - 并不是所有的瀏覽器都能完全支持上面的三個響應頭,因此最好是同時
- 使用上面的三個響應頭。
Expires數據頭:值為GMT時間值,為-1指瀏覽器不要緩存頁面
Cache-Control響應頭有兩個常用值:
no-cache指瀏覽器不要緩存當前頁面。
max-age:xxx指瀏覽器緩存頁面xxx秒。
控制瀏覽器緩存頁面中的靜態資源的過濾器:
- 場景:有些動態頁面中引用了一些圖片或css文件以修飾頁面效果,這些圖片和css文件經常是不變化的,所以為減輕服務器的壓力,可以使用filter控制瀏覽器緩存這些文件,以提升服務器的性能。
使用Filter實現URL級別的權限認證
- 情景:在實際開發中我們經常把一些執行敏感操作的servlet映射到一些特殊目錄中,并用filter把這些特殊目錄保護起來,限制只能擁有相應訪問權限的用戶才能訪問這些目錄下的資源。從而在我們系統中實現一種URL級別的權限功能。
- 要求:為使Filter具有通用性,Filter保護的資源和相應的訪問權限通過filter參數的形式予以配置。
實現用戶自動登陸的過濾器
- 在用戶登陸成功后,發送一個名稱為user的cookie給客戶端,cookie的值為用戶名和md5加密后的密碼。
- 編寫一個AutoLoginFilter,這個filter檢查用戶是否帶有名稱為user的cookie來,如果有,則調用dao查詢cookie的用戶名和密碼是否和數據庫匹配,匹配則向session中存入user對象(即用戶登陸標記),以實現程序完成自動登陸。
Filter的部署—注冊Filter
<filter><filter-name>testFitler</filter-name><filter-class>org.test.TestFiter</filter-class><init-param><param-name>word_file</param-name> <param-value>/WEB-INF/word.txt</param-value></init-param> </filter> <filter-name>用于為過濾器指定一個名字,該元素的內容不能為空。 <filter-class>元素用于指定過濾器的完整的限定類名。 <init-param>元素用于為過濾器指定初始化參數,它的子元素<param-name>指定參數的名字,<param-value>指定參數的值。在過濾器中,可以使用FilterConfig接口對象來訪問初始化參數。<filter-mapping>元素用于設置一個 Filter 所負責攔截的資源。一個Filter攔截的資源可通過兩種方式來指定:Servlet 名稱和資源訪問的請求路徑 1. <filter-name>子元素用于設置filter的注冊名稱。該值必須是在<filter>元素中聲明過的過濾器的名字 2. <url-pattern>設置 filter 所攔截的請求路徑(過濾器關聯的URL樣式) 3. <servlet-name>指定過濾器所攔截的Servlet名稱。 4. <dispatcher>指定過濾器所攔截的資源被 Servlet 容器調用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默認REQUEST。用戶可以設置多個<dispatcher> 子元素用來指定 Filter 對資源的多種調用方式進行攔截。<dispatcher> 子元素可以設置的值及其意義: REQUEST:當用戶直接訪問頁面時,Web容器將會調用過濾器。如果目標資源是通過RequestDispatcher的include()或forward()方法訪問時,那么該過濾器就不會被調用。INCLUDE:如果目標資源是通過RequestDispatcher的include()方法訪問時,那么該過濾器將被調用。除此之外,該過濾器不會被調用。FORWARD:如果目標資源是通過RequestDispatcher的forward()方法訪問時,那么該過濾器將被調用,除此之外,該過濾器不會被調用。ERROR:如果目標資源是通過聲明式異常處理機制調用時,那么該過濾器將被調用。除此之外,過濾器不會被調用。Filter的部署—映射Filter示例
<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>Filter高級開發
由于開發人員在filter中可以得到代表用戶請求和響應的request、response對象,因此在編程中可以使用Decorator(裝飾器)模式對request、response對象進行包裝,再把包裝對象傳給目標資源,從而實現一些特殊需求。
Decorator設計模式
當某個對象的方法不適應業務需求時,通常有2種方式可以對方法進行增強:
編寫子類,覆蓋需增強的方法
使用Decorator設計模式對方法進行增強疑問:在實際應用中遇到需增強對象的方法時,到底選用哪種方式呢?
- 沒有具體的定式,不過有一種情況下,必須使用Decorator設計模式:即被增強的對象,開發人員只能得到它的對象,無法得到它的class文件。
- 比如request、response對象,開發人員之所以在servlet中能通過sun公司定義的HttpServletRequest\response接口去操作這些對象,是因為Tomcat服務器廠商編寫了request、response接口的實現類。web服務器在調用servlet時,會用這些接口的實現類創建出對象,然后傳遞給servlet程序。
- 此種情況下,由于開發人員根本不知道服務器廠商編寫的request、response接口的實現類是哪個?在程序中只能拿到服務器廠商提供的對象,因此就只能采用Decorator設計模式對這些對象進行增強。
Decorator設計模式的實現
舉例:使用Decorator設計模式為BufferedReader類的readLine方法添加行號的功能。
request對象的增強
Servlet API 中提供了一個request對象的Decorator設計模式的默認實現類HttpServletRequestWrapper , (HttpServletRequestWrapper 類實現了request 接口中的所有方法,但這些方法的內部實現都是僅僅調用了一下所包裝的的 request 對象的對應方法)以避免用戶在對request對象進行增強時需要實現request接口中的所有方法。
案例:
1. 使用Decorator模式包裝request對象,完全解決get、post請求方式下的亂碼問題。
2. 使用Decorator模式包裝request對象,實現html標簽轉義功能(Tomcat服務器中提供了轉義html標簽的工具類)。
Servlet API 中提供了response對象的Decorator設計模式的默認實現類HttpServletResponseWrapper , (HttpServletResponseWrapper類實現了response接口中的所有方法,但這些方法的內部實現都是僅僅調用了一下所包裝的的 response對象的對應方法)以避免用戶在對response對象進行增強時需要實現response接口中的所有方法。
response增強案例—壓縮響應
應用HttpServletResponseWrapper對象,壓縮響應正文內容。思路:
- 通過filter向目標頁面傳遞一個自定義的response對象。
- 在自定義的response對象中,重寫getOutputStream方法和getWriter方法,使目標資源調用此方法輸出頁面內容時,獲得的是我們自定義的ServletOutputStream對象。
- 在我們自定義的ServletOuputStream對象中,重寫write方法,使寫出的數據寫出到一個buffer中。
- 當頁面完成輸出后,在filter中就可得到頁面寫出的數據,從而我們可以調用GzipOuputStream對數據進行壓縮后再寫出給瀏覽器,以此完成響應正文件壓縮功能。
實用案例-緩存數據到內存
對于頁面中很少更新的數據,例如商品分類,為避免每次都要從數據庫查詢分類數據,因此可把分類數據緩存在內存或文件中,以此來減輕數據庫壓力,提高系統響應速度。
動態代理
現在要生成某一個對象的代理對象,這個代理對象也要通過一個類來生成,所以首先要編寫用于生成代理對象的類。
代理誰
如何生成代理對象
設計一個類變量,以及一個構造函數,記住代理類 代理哪個對象。
設計一個方法生成代理對象(在方法內編寫代碼生成代理對象是此處編程的難點)
Java提供了一個Proxy類,調用它的newInstance方法可以生成某個對象的代理對象,使用該方法生成代理對象時,需要三個參數:
1.生成代理對象使用哪個類裝載器
2.生成哪個對象的代理對象,通過接口指定
3.生成的代理對象的方法里干什么事,由開發人員編寫handler接口的實現來指定。
初學者必須理解,或不理解必須記住的2件事情:
- Proxy類負責創建代理對象時,如果指定了handler(處理器),那么不管用戶調用代理對象的什么方法,該方法都是調用處理器的invoke方法。
- 由于invoke方法被調用需要三個參數:代理對象、方法、方法的參數,因此不管代理對象哪個方法調用處理器的invoke方法,都必須把自己所在的對象、自己(調用invoke方法的方法)、方法的參數傳遞進來。
動態代理應用
- 在動態代理技術里,由于不管用戶調用代理對象的什么方法,都是調用開發人員編寫的處理器的invoke方法(這相當于invoke方法攔截到了代理對象的方法調用)。
- 并且,開發人員通過invoke方法的參數,才可以在攔截的同時,知道用戶調用的是什么方法,因此利用這兩個特性,就可以實現一些特殊需求,例如:攔截用戶的訪問請求,以檢查用戶是否有訪問權限、動態為某個對象添加額外的功能。
總結
以上是生活随笔為你收集整理的方立勋_30天掌握JavaWeb_Servlet Filter(过滤器)未完的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 方立勋_30天掌握JavaWeb_jdb
- 下一篇: EL表达式取 Map、 List和数组的