Servlet2.3 Filter
1、Servlet Filter概述
凡是開發(fā)過J2EE的web application的人員都知道,經(jīng)常需要處理以下幾種情況:
訪問特定資源(Web 頁、JSP 頁、servlet)時的身份認(rèn)證 應(yīng)用程序級的訪問資源的審核和記錄 應(yīng)用程序范圍內(nèi)對資源的加密訪問,它建立在定制的加密方案基礎(chǔ)上 對被訪問資源的及時轉(zhuǎn)換, 包括從 servlet 和 JSP 的動態(tài)輸出 在servlet2.3之前這些功能處理是很難實現(xiàn)的,但是Java Servlet 2.3 規(guī)范新增了不少激動人心的功能,其中之一便是過濾器(Filter),其實這就是我們所說的管道和過濾器體系架構(gòu)在J2EE中的應(yīng)用實踐. 通過使用該模式使得Web Application開發(fā)者能夠在請求到達(dá)Web資源之前截取請求,在處理請求之后修改應(yīng)答。其結(jié)構(gòu)圖如下:
一個執(zhí)行過濾器的Java 類必須實現(xiàn)javax.servlet.Filter 接口。這一接口含有三個方法:
init(FilterConfig):這是容器所調(diào)用的初始化方法。它保證了在第一次 doFilter() 調(diào)用前由容器調(diào)用。它能獲取在 web.xml 文件中指定的filter初始化參數(shù)。
doFilter(ServletRequest, ServletResponse, FilterChain):這是一個完成過濾行為的方法。它同樣是上一個過濾器調(diào)用的方法。引入的 FilterChain 對象提供了后續(xù)過濾器所要調(diào)用的信息。
destroy():容器在銷毀過濾器實例前,doFilter()中的所有活動都被該實例終止后,調(diào)用該方法。
2、Filter鏈介紹
所有過濾器都服從調(diào)用的過濾器鏈,并通過定義明確的接口得到執(zhí)行。WebApplication可以指定許多過濾器來完成相關(guān)的工作.那么它們就組成一個過濾器鏈來完成相應(yīng)的工作.其結(jié)構(gòu)如下圖:
3、例子
3.1 簡單filter
在PetStore1.3.1中的就存在兩個Filter過濾器.其中一個過濾器,完成字符集的編碼的轉(zhuǎn)化,如大家經(jīng)常遇到的漢字編碼問題,你只需配置為GBK即可.它從Web.xml之中讀取這些參數(shù)的配置信息,然后進(jìn)行編碼的轉(zhuǎn)化.另一個是安全校驗Fliter,它負(fù)責(zé)進(jìn)行安全檢查哪些頁面可以進(jìn)行,哪些不可.它們組成一個Filter鏈,結(jié)構(gòu)圖和實現(xiàn)代碼如下:
public class EncodingFilter implements Filter { private FilterConfig config = null; // default to ASCII private String targetEncoding = "ASCII";
public void init(FilterConfig config) throws ServletException { this.targetEncoding = config.getInitParameter("encoding"); } //在過濾器中實現(xiàn)字符集編碼轉(zhuǎn)化 public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)srequest; request.setCharacterEncoding(targetEncoding); // move on to the next chain.doFilter(srequest,sresponse); } public void destroy() { …………….. } }
public class SignOnFilter implements Filter { public void init(FilterConfig config) throws ServletException { this.config = config; URL protectedResourcesURL = null; try { protectedResourcesURL = config.getServletContext().getResource("/WEB-INF/signon-config.xml"); ............... } catch (java.net.MalformedURLException ex) { System.out.println("SignonFilter: malformed URL exception: " + ex); } }
public void destroy() { config = null; } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ........ } } | 容器通過 Web 應(yīng)用程序中的配置描述符 web.xml 文件解析過濾器配置信息。有兩個新的標(biāo)記與過濾器相關(guān):<filter> 和 <filter-mapping>。<filter> 標(biāo)記是一個過濾器定義,它必定有一個 <filter- name> 和 <filter-class> 子元素。<filter-name> 子元素給出了一個與過濾器實例相關(guān)的名字。<filter-class> 指定了由容器載入的實現(xiàn)類。您能隨意地包含一個 <init-param> 子元素為過濾器實例提供初始化參數(shù)。<filter-mapping> 標(biāo)記代表了一個過濾器的映射,指定了過濾器會對其產(chǎn)生作用的 URL 的子集。
<!-- Encoding Filter Declaration Start --> <filter> <filter-name>EncodingFilter</filter-name> <display-name>Encoding Filter</display-name> <description>no description</description> <filter-class>com.sun.j2ee.blueprints.encodingfilter.web.EncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <!-- Encoding Filter Declaration End --> <!-- Signon Filter Declaration Start --> <filter> <filter-name>SignOnFilter</filter-name> <display-name>SignOn Filter</display-name> <description>no description</description> <filter-class>com.sun.j2ee.blueprints.signon.web.SignOnFilter</filter-class> </filter> <!-- Signon Filter Declaration End -->
<!-- Encoding Filter Mapping Start--> <filter-mapping> <filter-name>EncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Encoding Filter Mapping End --> <!-- Signon Filter Mapping Start--> <filter-mapping> <filter-name>SignOnFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Signon Filter Mapping End --> | 3.2 復(fù)雜的filter
上面是petstore的例子,演示了通過Fliter修改字符編碼和安全認(rèn)證的功能.下面提供一個示例演示通過修改返回數(shù)據(jù)(通過過濾器把response的字符串變成大寫).
public class UCaseResponse extends HttpServletResponseWrapper { public UCaseResponse(HttpServletResponse response) { super(response); }
public PrintWriter getWriter() throws IOException { return new UCaseWriter(super.getWriter()); } }
public class UCaseWriter extends PrintWriter { public UCaseWriter(Writer out) { super(out); } public void write(int c) { super.write(Character.toUpperCase( (char) c)); } public void write(char buf[], int off, int len) { for (int i = 0;i < len;i++) { write(buf[off + i]); } } public void write(String s, int off, int len) { for (int i = 0;i < len;i++) { write(s.charAt(off + i)); } } }
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) { try { filterChain.doFilter(request, new UCaseResponse((HttpServletResponse)(response))); }catch(Exception sx) { filterConfig.getServletContext().log(sx.getMessage()); } | 該示例使用HttpServletResponseWrapper技術(shù),它是對HttpServletResponse的包裝,其實就是裝飾(decorate)設(shè)計模式的應(yīng)用.這個例子能夠工作的關(guān)鍵是UCaseResponse和UCaseWriter類,它實現(xiàn)了對每個要輸出的字符都轉(zhuǎn)成了大寫后再寫入實際的輸出流的功能。
4、體系架構(gòu)的實現(xiàn)
實現(xiàn)一個管道和過濾器一般要注意以下幾個方面:
把系統(tǒng)任務(wù)分成一系列處理階段。
根據(jù)管道和過濾器的設(shè)計方案,必須把系統(tǒng)處理的任務(wù)分割成相應(yīng)獨立的任務(wù),如日志,數(shù)據(jù)轉(zhuǎn)化,安全認(rèn)證等.這樣每個階段僅依賴其前一階段的輸出。通過數(shù)據(jù)流將所有階段相連起來。并且你可以進(jìn)行替換每個步驟,或者可以調(diào)整它們之間的順序,以產(chǎn)生新的結(jié)果.如petstore中的編碼轉(zhuǎn)化Filter和安全Filter,分成兩個獨立的處理階段.
定義沿每個管道傳輸?shù)臄?shù)據(jù)格式。
我們知道每個過濾器,定義一個統(tǒng)一格式以獲得最大的靈活性,因為它使過濾器的重組變得容易。如:每個過濾器的方法是doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)它們的參數(shù)是必須相同的.
決定如何實現(xiàn)每個管道連接
Filter過濾器的連接是推得方式來實現(xiàn)的.前一個過濾器主動的調(diào)用filterChain.doFilter(request, response);來實現(xiàn)轉(zhuǎn)向下一個過濾器.
設(shè)計和實現(xiàn)過濾器
設(shè)計每個Filter具有獨立的功能,如編碼轉(zhuǎn)化,安全校驗,等功能.并且每個Fliter都應(yīng)該在實現(xiàn)javax.servlet.Filter接口.
建立處理流水線
過濾器的部署是在Web.xml中進(jìn)行配置,描述過濾器的實現(xiàn)類以及它們的map關(guān)系,來確定它們的順序.
| |