一、Filter過濾鏈
web.xml配置了filter過濾器,在容器啟動的時候執行了init()方法進行了初始化,然后在容器關閉的時候執行了destroy()方法銷毀過濾器,在每次服務器接受請求的時候每次都會先過一遍過濾器,如果有合適的過濾器就會執行相應過濾器的doFilter方法。
doFilter方法有3個參數 ServletRequest、ServletResponse、FilterChain;前兩個分別是請求和返回對象,為的是過濾后還能夠進行請求或轉發。FilterChain是一個過濾鏈,他包含了相同過濾條件的所有過濾器,例如:
類似這種相同匹配模式的過濾器會存在於同一個過濾鏈中,然后按照初始化的先后順一次排列,實現逐層過濾。其中filterChain中有個doFilter方法,他的作用是將當前請求轉發給過濾鏈中的下一個過濾器進行過濾,然后將過濾結果,只有等待下一個過濾器執行過濾完成后才能繼續執行。該執行過程類似如下圖:
如上圖,通過過濾鏈逐層執行過濾就像一層嵌套,一層套一層,如果過濾鏈中只有一個過濾器(或者執行到最后一個)的話,執行了chain.doFilter()他會直接將請求轉發出去,獲取request resource資源,因為從始至終都是同一個request和response在傳遞,所以每次過濾都可以修改請求或返回結果,實現了過濾修改的目的。
代碼實例:(只貼主要代碼)
ResponseFilter.java
1 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 2 CustomResponseWrapper customResponseWrapper = new CustomResponseWrapper((HttpServletResponse) servletResponse); 3 System.out.println("ResponseFilter 執行前"); 4 filterChain.doFilter(servletRequest,customResponseWrapper);//執行下一層過濾 5 System.out.println("ResponseFilter 執行后"); 6 } 7 }
SecondFilter.java
1 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 2 System.out.println("Second doFilter執行前"); 3 filterChain.doFilter(servletRequest,servletResponse);//這是最后一層過濾器,會直接請求resource 4 System.out.println("Second doFilter執行后"); 5 }
web.xml (兩個過濾器使用了相同的匹配模式‘/*’,所以會處於同一過濾鏈中)
1 <filter> 2 <filter-name>ResponseFilter</filter-name> 3 <filter-class>filter.ResponseFilter</filter-class> 4 </filter> 5 <filter-mapping> 6 <filter-name>ResponseFilter</filter-name> 7 <url-pattern>/*</url-pattern> 8 </filter-mapping> 9 <filter> 10 <filter-name>SecondFilter</filter-name> 11 <filter-class>filter.SecondFilter</filter-class> 12 </filter> 13 <filter-mapping> 14 <filter-name>SecondFilter</filter-name> 15 <url-pattern>/*</url-pattern> 16 </filter-mapping>
執行結果:
從執行結果並結合以上分析可以很清楚的看出doFilter的執行順序
二、通過Filter過濾器實現對response內容的修改
CustomPrintWriter.java (重寫PrintWriter方法)
1 public class CustomPrintWriter extends PrintWriter{ 2 private StringBuilder buffer; 3 4 public CustomPrintWriter(Writer out) { 5 super(out); 6 buffer = new StringBuilder(); 7 } 8 9 @Override 10 public void write(char[] buf, int off, int len) { 11 char[] dest = new char[len]; 12 System.arraycopy(buf,off,dest,0,len);//深復制字符數組 13 buffer.append(dest); 14 } 15 16 public String getContent() { 17 return buffer.toString(); 18 } 19 }
CustomResponseWrapper.java (重寫HttpServletResponseWrapper方法)
1 public class CustomResponseWrapper extends HttpServletResponseWrapper{ 2 private CustomPrintWriter customPrintWriter; 3 4 public CustomResponseWrapper(HttpServletResponse response) { 5 super(response); 6 } 7 8 @Override 9 public PrintWriter getWriter() throws IOException { 10 customPrintWriter = new CustomPrintWriter(super.getWriter()); 11 return customPrintWriter; 12 } 13 14 public CustomPrintWriter getCustomPrintWriter() { 15 return customPrintWriter; 16 } 17 }
ResponseFilter.java (過濾器)
1 public class ResponseFilter implements Filter{ 2 public void init(FilterConfig filterConfig) throws ServletException {} 3 4 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 5 CustomResponseWrapper customResponseWrapper = new CustomResponseWrapper((HttpServletResponse) servletResponse); 6 filterChain.doFilter(servletRequest,customResponseWrapper);//轉發請求獲取請求返回結果 7 CustomPrintWriter writer = customResponseWrapper.getCustomPrintWriter();//獲取請求的返回結果 8 if(writer != null){ 9 String content = writer.getContent(); 10 /** 11 * 在不修改jsp源碼的情況下修改展示內容 12 */ 13 content = content.replace("XXX", LoginCheckServlet.username); 14 servletResponse.getWriter().write(content); 15 } 16 } 17 18 public void destroy() {} 19 }