前言

本文记录一下在 SpringBoot 项目中是如何使用 Filter 过滤器

代码、测试

Filter 过滤器是 servlet 包下面的东西,因此我们不需要再额外引包

方法一

直接实现 Filter 接口,并使用 @Component 注解标注为组件自动注入 bean

  1. package cn.huanzi.qch.springbootfilter.filter;
  2. import org.springframework.stereotype.Component;
  3. import javax.servlet.*;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpServletResponse;
  6. import java.io.IOException;
  7. @Component
  8. public class TestFilter implements Filter {
  9. @Override
  10. public void init(FilterConfig filterConfig) throws ServletException {
  11. }
  12. @Override
  13. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  14. HttpServletRequest request = (HttpServletRequest) servletRequest;
  15. HttpServletResponse response = (HttpServletResponse) servletResponse;
  16. System.out.println("TestFilter,"+request.getRequestURI());
  17. //执行
  18. filterChain.doFilter(servletRequest, servletResponse);
  19. }
  20. @Override
  21. public void destroy() {
  22. }
  23. }

查看日志可以发现,SpringBoot 已经帮我们注入了一个 filter,拦截路径是 /*,拦截所有,如果我们需要进一步拦截具体的则需要我们自己在代码里控制

在SpringBoot中使用Filter过滤器 - 图1

方法二

实现 Filter 接口,用 @WebFilter 注解,指定拦截路径以及一些参数,同时需要在启动类使用 @ServletComponentScan 扫描带 @WebFilter、@WebServlet、@WebListener 并将帮我们注入 bean

请看官网介绍:https://docs.spring.io/spring-boot/docs/2.1.5.RELEASE/reference/htmlsingle/#boot-features-embedded-container-servlets-filters-listeners-scanning

在SpringBoot中使用Filter过滤器 - 图2

  1. package cn.huanzi.qch.springbootfilter.filter;
  2. import javax.servlet.*;
  3. import javax.servlet.annotation.WebFilter;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpServletResponse;
  6. import java.io.IOException;
  7. //配置拦截路径
  8. @WebFilter(filterName = "testFilter",urlPatterns = {"/test"})
  9. public class TestFilter implements Filter {
  10. @Override
  11. public void init(FilterConfig filterConfig) throws ServletException {
  12. }
  13. @Override
  14. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  15. HttpServletRequest request = (HttpServletRequest) servletRequest;
  16. HttpServletResponse response = (HttpServletResponse) servletResponse;
  17. System.out.println("TestFilter,"+request.getRequestURI());
  18. //执行
  19. filterChain.doFilter(servletRequest, servletResponse);
  20. }
  21. @Override
  22. public void destroy() {
  23. }
  24. }
  1. package cn.huanzi.qch.springbootfilter;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.boot.web.servlet.ServletComponentScan;
  5. //自动扫描与当前类的同包以及子包
  6. @ServletComponentScan
  7. @SpringBootApplication
  8. public class SpringbootFilterApplication {
  9. public static void main(String[] args) {
  10. SpringApplication.run(SpringbootFilterApplication.class, args);
  11. }
  12. }

查看日志发现,以及帮我们注入了 testFilter,拦截路径是 / test

在SpringBoot中使用Filter过滤器 - 图3

只指定拦截路径,不设置 filterName 一样可以注入

  1. //配置拦截路径
  2. @WebFilter({"/test"})

在SpringBoot中使用Filter过滤器 - 图4

方法三

当然了,我们也可以既使用 @Component 同时也使用 @WebFilter

  1. package cn.huanzi.qch.springbootfilter.filter;
  2. import org.springframework.stereotype.Component;
  3. import javax.servlet.*;
  4. import javax.servlet.annotation.WebFilter;
  5. import javax.servlet.http.HttpServletRequest;
  6. import javax.servlet.http.HttpServletResponse;
  7. import java.io.IOException;
  8. //配置拦截路径
  9. @WebFilter(filterName = "testFilter",urlPatterns = {"/test"})
  10. @Component
  11. public class TestFilter implements Filter {
  12. @Override
  13. public void init(FilterConfig filterConfig) throws ServletException {
  14. }
  15. @Override
  16. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  17. HttpServletRequest request = (HttpServletRequest) servletRequest;
  18. HttpServletResponse response = (HttpServletResponse) servletResponse;
  19. System.out.println("TestFilter,"+request.getRequestURI());
  20. //执行
  21. filterChain.doFilter(servletRequest, servletResponse);
  22. }
  23. @Override
  24. public void destroy() {
  25. }
  26. }
  1. package cn.huanzi.qch.springbootfilter;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.boot.web.servlet.ServletComponentScan;
  5. //自动扫描与当前类的同包以及子包
  6. @ServletComponentScan
  7. @SpringBootApplication
  8. public class SpringbootFilterApplication {
  9. public static void main(String[] args) {
  10. SpringApplication.run(SpringbootFilterApplication.class, args);
  11. }
  12. }

但是做会注入两个 bean,如果你的 @WebFilter 没有指定 filterName 或者指定的名称与类名相同,由于注入两个相同名称的 bean,程序启动报错,叫我们修改其中一个的名字,或者启用覆盖 bean

在SpringBoot中使用Filter过滤器 - 图5

这里建议如果你硬要采用第三种方法,最好启用覆盖,因为改名将会注入两个 bean,处理逻辑一样但拦截路径不一样,这并不是我们想要的,例如:

在SpringBoot中使用Filter过滤器 - 图6

启用覆盖

  1. #启用覆盖同名bean
  2. spring.main.allow-bean-definition-overriding=true

在SpringBoot中使用Filter过滤器 - 图7

PS:这里额外说一点,如果我们采用第三种方法,@ServletComponentScan 放在 TestFilter 类上 @WebFilter 也会被扫描到,不需要放在启动类,第二种方法如果也这样做就不行,估计是受到了 @Component 注解的影响

  1. //配置拦截路径
  2. @WebFilter(filterName = "testFilter",urlPatterns = {"/test"})
  3. @ServletComponentScan
  4. @Component
  5. public class TestFilter implements Filter