zoukankan      html  css  js  c++  java
  • SpringBoot_Filter的详解

    SpringBoot&Filter的详解

    过滤器实际上就是对web资源进行拦截,做一些处理后再交给下一个过滤器或servlet处理 通常都是用来拦截request进行处理的,也可以对返回的response进行拦截处理

    大概流程图如下

    应用场景

    • 自动登录

    • 统一设置编码格式

    • 访问权限控制

    • 敏感字符过滤等

    • ......


    1、Filter的使用

      要想使用filter,需要写一个方法继承Filter类,我们写如下两个自己的Filter类,首先是FirstFilter类,其中@Order里边的数字越小代表越先被该Filter过滤,@WebFilter代表这是个Filter类并把这个类注入到容器中。

    注意:

        SpringBoot 实现 Filter 两种方式:

    1. 自定义Filter通过FilterRegistrationBean 类来注入;(不推荐)

    2. 自定义Filter通过 实现接口 Filter方法,@WebFilter注入。

    FirstFilter

    @Order(1)
    @WebFilter(filterName="firstFilter", urlPatterns="/*")
    public class FirstFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            System.out.println("first filter 1111111111111111111");
            chain.doFilter(request, response);
            System.out.println("first filter 2222222222222222222");
        }
    
        @Override
        public void destroy() {
    
        }
    }

    SecondFilter

    @Order(2)
    @WebFilter(filterName="secondFilter", urlPatterns="/*")
    public class SecondFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            System.out.println("second filter 1=============================");
            System.out.println("before:" + response);
            chain.doFilter(request, response);
            System.out.println("after:" + response);
            System.out.println("second filter 2=============================");
    
        }
    
        @Override
        public void destroy() {
    
        }
    }

    TestController

    @RestController
    public class TestController {
    
        @GetMapping("/test1")
        public String test1() {
            System.out.println("method in controller");
            return "test1";
        }
    
    }

    postman测试:http://localhost:8080/test1

    输出结果:

    first filter 1111111111111111111
    second filter 1=============================
    before:org.apache.catalina.connector.ResponseFacade@1d2aafd8
    method in controller
    after:org.apache.catalina.connector.ResponseFacade@1d2aafd8
    second filter 2=============================
    first filter 2222222222222222222

    过程:

    总结:

      我们可以看出代码执行的流程,首先请求被firstfilter截获,打印出first filter 1,然后去执行chain.doFilter(request, response),这句话代表着请求会转发给过滤器链上下一个对象,也就是secondfilter,所以打印出secondfilter里的second filter 1,接下来再执行secondfilter里的chain.dofilter()方法,请求再转发给下一个对象,由于没有其他的filter了,所以会转发给controller,打印出了controller类中的method in controller,接下来再去内存栈里调用secondfilter的print("second filter 2"),然后再去内存栈里调用firstfilter的print("first filter 1")。所以如果在自己实现的Filter类的doFilter方法里不加chain.doFilter(req, rep)是万万不行的,那样会导致请求到了这个filter里就不再往下走了,永远进不了controller中。

      我们也可以在print("before:" + response)和print("after:" + response)这两个地方打上断点,然后调试一下,你会发现在before那里的response里是什么都么有的,而在after那里的response里则是已经有了test1字符串,也就是说controller类test1方法的返回值已经添加进了response,所以如果你想对请求的response做一下过滤处理,那么一定要在chain.doFilter(res, rep)之后写你的逻辑。


    2、@WebFilter注解说明

      @WebFilter 用于将一个类声明为过滤器,该注解将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器。该注解具有下表给出的一些常用属性 ( 以下所有属性均为可选属性,但是 value、urlPatterns、servletNames 三者必需至少包含一个,且 value 和 urlPatterns 不能共存,如果同时指定,通常忽略 value 的取值 )

    @WebFilter 的常用属性

    属性名类型说 明
    filterName String 指定过滤器的 name 属性,等价与 <filter-name> 标签
    value String[] 该属性等价于 <url-pattern> 标签,但是两者不应该同时使用
    urlPatterns String[] 指定一组过滤器的 URL 匹配模式。等价于 <url-pattern> 标签。
    servletNames String[] 用于指定过滤的servlet。取值是 @WebServlet 中的 name 属性的取值,或者是 web.xml 中 <servlet-name> 的取值。
    dispatcherTypes DispatcherType[] 指定过滤器的转发模式。具体取值包括:ASYNC、ERROR、FORWARD、INCLUDE、REQUEST
    initParams WebInitParam[] 用于设置该过滤器类的一些初始化参数,等同于<init-param> 标签
    asyncSupported Boolean 声明过滤器是否支持异步操作模式,等价于 <async supported> 标签
    description String 对该过滤器的描述信息,等价于 <description> 标签
    displayName String 过滤器显示名,通常配合工具使用,等同与<display-name> 标签

    3、责任链模式的实际应用

    Filter和FilterChain都是怎么用责任链模式实现的,自定义实现一下, 使用Filter模式来模拟

    Filter接口

    public interface Filter {
        /**
         * 过滤器
         * @param request 请求对象
         * @param response 返回对象
         */
        public void doFilter(Request request, Response response, FilterChain chain);
    
    }

    FilterChain类 { 过滤器链 }

    /**
     * @Desc: TODO 过滤器链【执行责任链模式的主要成员】
     */
    public class FilterChain implements Filter {
    
        /**
         * 过滤器列表
         */
        private List<Filter> filters = new ArrayList<>();
    
        int index = 0;
    
        /**
         * 添加过滤器
         * @param filter
         */
        public FilterChain addFilter(Filter filter) {
            filters.add(filter);
            return this;
        }
    
        @Override
        public void doFilter(Request request, Response response, FilterChain chain) {
            if(index == filters.size()) {
                /**
                 * 真正处理请求(此时开始处理 controller业务逻辑)
                 */
                return;
            }
            Filter filter = filters.get(index);
            index++;
            filter.doFilter(request, response, chain);
        }
    
    }

    Request类和Response类

    public class Request {
        public String requestStr;
    }
    public class Response {
        public String responseStr;
    }

    实现类(业务中需要的过滤器,以下举例)

    EncodeFilter{ 设置统一编码 }

    public class EncodeFilter implements Filter {
        @Override
        public void doFilter(Request request, Response response, FilterChain chain) {
            request.requestStr = request.requestStr + "  设置编码 UTF-8";
            System.out.println("EncodeFilter request Str:" + request.requestStr);
            chain.doFilter(request, response, chain);
            response.responseStr = response.responseStr + "-------------设置编码 UTF-8";
            System.out.println("EncodeFilter response Str:" + response.responseStr);
        }
    }

    VerifyParameterFilter{ 参数校验 }

    public class VerifyParameterFilter  implements Filter {
        @Override
        public void doFilter(Request request, Response response, FilterChain chain) {
            request.requestStr = request.requestStr + "  参数验证 成功";
            System.out.println("VerifyParameterFilter request str:" + request.requestStr);
            chain.doFilter(request, response, chain);
            response.responseStr = response.responseStr + "======================";
            System.out.println("VerifyParameterFilter response str:" + response.responseStr);
        }
    }

    测试

    public class FilterTest {
        public static void main(String[] args) {
            String msg = "张三";
            Request request = new Request();
            request.requestStr = msg;
            Response response = new Response();
            response.responseStr = "success *****";
    
            FilterChain fc = new FilterChain();
            fc.addFilter(new EncodeFilter())
                    .addFilter(new VerifyParameterFilter())
                    .doFilter(request, response, fc);
        }
    }

    结果:

    EncodeFilter request Str:张三  设置编码 UTF-8
    VerifyParameterFilter request str:张三  设置编码 UTF-8  参数验证 成功
    VerifyParameterFilter response str:success *****======================
    EncodeFilter response Str:success *****======================-------------设置编码 UTF-8

    总结

    1. Filter是针对请求进行拦截、意在请求前进行一些过滤、权限校验、日志记录、统一编码等

    2. 所有Filter统一在FilterChain中组成一个链条,然后调用也统一由FilterChain来协调,确保以链条的模式执行

    3. 责任链模式是一种重要的设计模式,如Servlet中的Filter模式、Mybatis中的Plugin模式等都是责任链模式的体现

  • 相关阅读:
    Firefox for macOS 标签关闭按钮设置在左侧
    Nginx 非编译安装 stream 模块实现四层负载均衡
    苹果手机卡死,强制关机方法
    Git安装完成,文件夹下右键菜单不出现出现Git Bash Here 和Git UI Here问题
    AESUtil
    若依框架清空select2选择
    RSAUtils
    springboot 延时任务
    Mqtt的坑,真的坑
    springboot 支付宝支付业务网页端扫码
  • 原文地址:https://www.cnblogs.com/mmdz/p/15475615.html
Copyright © 2011-2022 走看看