美文网首页SpringSpringHome
SpringBoot2.X 实战3 -- Filter

SpringBoot2.X 实战3 -- Filter

作者: 聆世冷暖 | 来源:发表于2018-08-07 20:10 被阅读9次

    一.前言

    1.Filter简介

    Filter具有这样的能力:它能够对资源(servlet或静态内容)的请求上执行过滤任务,或者在资源的响应上执行过滤任务,或者两者都执行。过滤器在doFilter方法中执行过滤。 每个Filter都可以访问FilterConfig对象,从该对象可以获取其初始化参数,即可以使用的ServletContext引用,例如,加载过滤任务所需的资源。过滤器是在web应用程序的部署描述符中配置的。

    ServletRequest 会在到达 Servlet 之前,先接受到 ServletRequest 请求;

    在这里可以根据需要检测 ServletRequest 头信息也可以修改响应的头信息,如检测用户的 IP 是否在白名单里面,打印日志等;

    在 ServletResponse 到达用户之前进行数据检测和修改;

    2.Filter 种类很多如:

    a.权限管理类的 Filter: 负责检查用户是否有权限访问当前资源(SpringSecurity);
    b.ErrorPageFilter:它注册错误页面,并通过过滤请求并转发到错误页面来处理应用程序错误,而不是让服务器处理它们。错误页面是servlet规范的一个特性,但是没有用于在规范中注册它们的Java API。
    c.LoggerContextFilter:简单的请求日志记录过滤器,它将请求URI(或查询字符串)写入公有日志。

    二.Filter 运行流程

    1.Filter 对用户的请求进行与预处理;
    2.将请求交给 Servlet 处理并生成响应;
    3.Filter 对服务器响应进行后处理.

    三.Filter接口方法

    写自己的 Filter 需要实现 javax.servlet.Filter 接口并覆写其中的三个方法:

    1.init 方法:

    该方法由 web 容器调用,以指示 Filter 已经投入使用。servlet容器在实例化过滤器之后调用init方法一次。在要求过滤器执行任何过滤工作之前,init方法必须成功完成。当 init 方法出现以下情况时 Filter 将不生效:
    a.抛出了 ServletException 异常;
    b.在一段时间内没有返回结果(超时了).

    2.destroy方法:

    由web容器调用,以指示 Filter 它正在从服务中取出。此方法只在过滤器的doFilter方法中的所有线程退出或超时时间过后调用。在web容器调用此方法之后,它将不会在过滤器的这个实例上再次调用doFilter方法。此方法使 Filter 有机会清除所有正在保留的资源(例如,内存,文件句柄,线程),并确保任何持久状态与过滤器在内存中的当前状态同步。

    3.doFilter方法

    这个是整个过滤器中最重要的方法.该部分是使用的责任链的设计模式。责任链设计模式中使用了一个钩子指向下一个过滤器(filterChain.doFilter()方法指向下一个过滤器)每当请求/响应对通过链时,容器都会调用过滤器的 doFilter 方法,这是由于客户端在链末端对资源的请求。传递给此方法的FilterChain允许过滤器将请求和响应传递给链中的下一个实体。
    此方法的典型实现将遵循以下原则:
    a.检查请求
    b.可以选择用自定义实现包装请求对象,以过滤用于输入过滤的内容或标题;
    c.可以选择用自定义实现包装响应对象,以过滤用于输出过滤的内容或标题;
    d. 使用FilterChain对象(filterChain.doFilter())调用链中的下一个实体或者不将请求/响应对传递给过滤器链中的下一个实体以阻止请求处理;
    e.在调用过滤器链中的下一个实体后,直接在响应上设置标头。

    四.自定义 Filter

    根据第三小节描述,首先继承 javax.servlet.Filter 并实现三个方法:

    1.基本用法

    @WebFilter 标识该过滤器的一些基本信息:
    filterName:过滤器名称;
    urlPatterns = "/filter1" :过滤的路由

    @Slf4j
    @WebFilter(filterName = "filter1", urlPatterns = "/filter1")
    public class RestFilter1 implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            log.info("RestFilter1 初始化了");
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
            log.info("RestFilter1 请求处理");
            String result = request.getReader().lines().reduce("", String::concat);
            System.out.println("result:" + result.replace("\t",""));
            filterChain.doFilter(request, response);
        }
    
        @Override
        public void destroy() {
            log.info("RestFilter1 销毁");
        }
    }
    

    RestController 代码

        @PostMapping("/filter1")
        public String postString1(){
            return "post-filter1";
        }
    
    

    当我们请求接口时能获得如下结果:


    1屏幕快照 2018-08-07 下午8.42.png

    2.带执行顺序的过滤器

    只要在类上加@Order(1)注解(org.springframework.core.annotation.Order)。
    数字越小执行顺序越靠前。

    @Slf4j
    @Order(0)
    @WebFilter(filterName = "filter1", urlPatterns = "/filter1")
    public class RestFilter1 implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            log.info("RestFilter1 初始化了");
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
            log.info("RestFilter1 请求处理");
            String result = request.getReader().lines().reduce("", String::concat);
            System.out.println("result:" + result.replace("\t",""));
            filterChain.doFilter(request, response);
        }
    
        @Override
        public void destroy() {
            log.info("RestFilter1 销毁");
        }
    }
    

    3.在过滤器执行期间直接返回结果

    使用场景:用户的 IP 在黑名单里

    @Slf4j
    @Order(1)
    @WebFilter(filterName = "filter2", urlPatterns = "/filter2")
    public class RestFilter2 implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            log.info("RestFilter2 初始化了");
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            String result = request.getReader().lines().reduce("", String::concat);
            response.getWriter().write(result.replace("\t",""));
        }
    
        @Override
        public void destroy() {
    
        }
    }
    

    这时直接返回请求体内的数据:
    RestController 代码:

        @PostMapping("/filter2")
        public String postString2(){
            return "post-filter2";
        }
    

    请求达到的结果:


    2屏幕快照 2018-08-07 下午8.41.png

    五.代码路径

    https://github.com/shaopro/SpringBootFilter

    相关文章

      网友评论

        本文标题:SpringBoot2.X 实战3 -- Filter

        本文链接:https://www.haomeiwen.com/subject/gtxzvftx.html