• 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 }

       

       

  • 相关阅读:
    Api记录
    选择排序、冒泡排序、二分查找(折半查找)
    inline关键字
    c++,虚函数,单继承,多继承虚表剖析
    关于类模版迭代器提出时的错误
    关于类模版迭代器提出时的错误2
    菱形继承,多继承,虚继承、虚表的内存结构全面剖析(逆向分析基础)
    VC++错误调试
    引用计数
    选择
  • 原文地址:https://www.cnblogs.com/caijh/p/7677270.html
Copyright © 2020-2023  润新知