springboot 自定义过滤器

865 阅读5分钟

springboot 自定义过滤器

Filter 过滤器主要是用来过滤用户请求的,它允许我们对用户请求进行前置处理和后置处理,比如实现 URL 级别的权限控制、过滤非法请求等等。Filter 过滤器是面向切面编程——AOP 的具体实现(AOP切面编程只是一种编程思想而已)。

自定义 Filter 只需要实现 import javax.servlet.Filter 接口即可。Filter 接口依赖于 Servlet 容器,Filter 接口就在 Servlet 包下,属于 Servlet 规范的一部分。

javax.servlet.Filter

public interface Filter {
  
   //初始化过滤器后执行的操作
    default void init(FilterConfig filterConfig) throws ServletException {
    }
   // 对请求进行过滤
    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
   // 销毁过滤器后执行的操作,主要用户对某些资源的回收
    default void destroy() {
    }
}
​

Filter 是如何实现拦截的?

通过 FIlter 接口中的 doFilter 方法,实现了对用户请求的过滤,其中请求流程为

用户发送请求到 web 服务器,请求会先到过滤器; 过滤器会对请求进行一些处理比如过滤请求的参数、修改返回给客户端的 response 的内容、判断是否让用户访问该接口等等。 用户请求响应完毕。 进行一些自己想要的其他操作。

img

自定义 Filter 的方法

提供两种方法

第一种 @WebFilter + @ServletComponentScan 注解

下自定义过滤器 ReqResFilter 必须实现 javax.servlet.Filter。

然后添加注解 @WebFilter(javax.servlet.annotation.WebFilter),urlPatterns 过滤器要过滤的URL规则配置,filterName 过滤器的名称。然后在启动类上加一个注解 @ServletComponentScan 就可以了

@Order(int) 注解,配合 @WebFilter 注解使用,用于多个过滤器时定义执行顺序,值越小越先执行。

MyFilter1

@WebFilter(filterName = "bb" , urlPatterns = {"/*"})
@Order(1)//指定过滤器的执行顺序,值越大越靠后执行
public class MyFilter1 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("MyFilter11 初始化");
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("MyFilter11 请求处理之前");
        //将请求传递给下一个过滤器
        filterChain.doFilter(request, response);
        System.out.println("MyFilter11 请求处理之后");
    }
    @Override
    public void destroy() {
        System.out.println("MyFilter11 销毁");
    }
}
​

MyFilter2

@WebFilter(filterName = "aa",urlPatterns = {"/*"})
@Order(2)
public class MyFilter2 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("MyFilter12 初始化");
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("MyFilter12 请求处理之前");
        //将请求传递给下一个过滤器
        filterChain.doFilter(request, response);
        System.out.println("MyFilter12 请求处理之后");
    }
    @Override
    public void destroy() {
        System.out.println("MyFilter12 销毁");
    }
}
​

使用@Order注解指定一个int值,越小越先执行。很多博客文章都是这么说的,但你真正的试了吗?真的可以使用这个注解指定顺序吗?答案是否定的。

经过测试,发现 @Order 注解指定 int 值没有起作用,是无效的。为啥?因为看源码发现 @WebFilter 修饰的过滤器在加载时,没有使用 @Order 注解,而是使用的类名来实现自定义Filter顺序,详细的可以参考这篇或者是这篇

所以这种方式下想定义Filter的顺序,就必须限定 Filter 的类名,比如刚才那个 Filter 叫 ReqResFilter , 加入我们现在新写了一个 Filter 叫 AlibabaFilter , 那么顺序就是 AlibabaFilter > ReqResFilter 。

所以这种方式虽然实现起来简单,只需要注解,但自定义顺序就必须要限定类名,使用类名达到排序效果了。

如果要实现自定义顺序,就用下面这种。

第二种 自定义配置类配置过滤器

自定义配置类加载自定义过滤器 ,确保 WebConfig 类能被扫描到就可以了,然后启动springboot 访问你的接口就会看到打印过滤器里的内容了。

MyFilter1

public class MyFilter1 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("MyFilter21 初始化");
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("MyFilter21 请求处理之前");
        //将请求传递给下一个过滤器
        filterChain.doFilter(request, response);
        System.out.println("MyFilter21 请求处理之后");
    }
    @Override
    public void destroy() {
        System.out.println("MyFilter21 销毁");
    }
}
​

MyFilter2

public class MyFilter2 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("MyFilter22 初始化");
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("MyFilter22 请求处理之前");
        //将请求传递给下一个过滤器
        filterChain.doFilter(request, response);
        System.out.println("MyFilter22 请求处理之后");
    }
    @Override
    public void destroy() {
        System.out.println("MyFilter22 销毁");
    }
}
​

现在我们有两个过滤器 MyFilter1 和 MyFilter2 ,怎么设置执行顺序。请看下面的代码。

这里我们,咋 WebConfig 类里再写一个 reqResFilter1 方法注册新增的这个过滤器。和刚才不同的是我们指定了 多个过滤器的 Order 即执行顺序,ReqResFilter1 的 Order 为2,设置 ReqResFilter 的Order为1。

@Configuration
public class WebConfig{
​
    @Bean
    public FilterRegistrationBean myFilter1() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
​
        MyFilter1 myFilter1 = new MyFilter1();
​
        filterRegistrationBean.setFilter(myFilter1);
        filterRegistrationBean.addUrlPatterns("/*");//配置过滤规则
        filterRegistrationBean.addInitParameter("name","hahahhhaa");//设置init参数
        filterRegistrationBean.setName("myFilter1");//设置过滤器名称
        filterRegistrationBean.setOrder(2);//执行次序
​
        return filterRegistrationBean;
    }
​
    @Bean
    public FilterRegistrationBean myFilter2() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
​
        MyFilter2 myFilter2 = new MyFilter2();
​
        filterRegistrationBean.setFilter(myFilter2);
​
        //配置多个过滤规则
//        List<String> urls = new ArrayList<>();
//        urls.add("/order/*");
//        urls.add("/user/*");
//        filterRegistrationBean.setUrlPatterns(urls);
​
        filterRegistrationBean.addUrlPatterns("/*");//配置过滤规则
        filterRegistrationBean.setName("myFilter2");//设置过滤器名称
        filterRegistrationBean.setOrder(1);//执行次序
​
        return filterRegistrationBean;
    }
}
​

另外 filterRegistrationBean.addInitParameter("name","hahahhhaa");//设置init参数 设置的参数在 Filter 的init 方法里的 FilterConfig 对象里可以获取到,即 filterConfig.getInitParameter("name")

另外 filterRegistrationBean.setUrlPatterns(urls); 可以设置多个URL匹配规则,setUrlPatterns接收一个List类型的参数

当不设置 setOrder 次序时,过滤器的执行顺序默认是 Bean 的加载顺序。在当前 WebConfig 类中,先加载的是 myFilter2方法 即 myFilter2过滤器,后加载的是 myFilter1 方法 即 myFilter1 过滤器。

需要注意的是,此时myFilter1和myFilter2不能添加@Component注解标识为为Spring Bean,则WebConfig不会生效,或者springboot启动失败。

其他方式:SpringBoot注册第三方过滤器

假如我们在项目里引入了第三方的jar,要使用jar里面带的 Filter 的话,如果引用的某个jar包中的过滤器,且这个过滤器在实现时没有使用 @Component标识为Spring Bean,则这个过滤器将不会生效。此时需要通过java代码去注册这个过滤器。也是使用该种方式进行注册。

参考:

www.cnblogs.com/ibigboy/p/1…

blog.csdn.net/qq_37175706…

blog.csdn.net/lianghecai5…