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模式等都是责任链模式的体现

  • 相关阅读:
    POJ 2175 Evacuation Plan 费用流 负圈定理
    POJ 2983 Is the Information Reliable? 差分约束
    codeforces 420B Online Meeting
    POJ 3181 Dollar Dayz DP
    POJ Ant Counting DP
    POJ 1742 Coins DP 01背包
    中国儒学史
    产品思维30讲
    Java多线程编程核心技术
    编写高质量代码:改善Java程序的151个建议
  • 原文地址:https://www.cnblogs.com/mmdz/p/15475615.html
Copyright © 2011-2022 走看看