Filter的過濾鏈理解


一、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 }

 

   

   

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM