Spring Boot自定义过滤器

什么是过滤器?

Filter 也称之为过滤器,它是Servlet技术中最实用的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如JSP,Servlet,静态图片文件或静态HTML文件进行拦截,从而实现一些特殊功能。例如实现 URL级别的权限控制 、 过滤敏感词汇 、 压缩响应信息 等一些高级功能。

Filter的执行原理

当客户端发出Web资源的请求时,Web服务器根据应用程序配置文件设置的过滤规则进行检查,若客户请求满足过滤规则,则对客户请求/响应进行拦截,对请求头和请求数据进行检查或改动,并依次通过过滤器链,最后把请求/响应交给请求的Web资源处理。请求信息在过滤器链中可以被修改,也可以根据条件让请求不发往资源处理器,并直接向客户机发回一个响应。当资源处理器完成了对资源的处理后,响应信息将逐级逆向返回。同样在这个过程中,用户可以修改响应信息,从而完成一定的任务。

服务器会按照过滤器定义的先后循序组装成一条链 ,然后一次执行其中的 doFilter() 方法。这一点 Filter 和 Servlet 是不一样的,执行的顺序不同:

  1. 执行第一个过滤器的 chain.doFilter() 之前的代码
  2. 第二个过滤器的 chain.doFilter() 之前的代码,
  3. 请求的资源,第二个过滤器的 chain.doFilter() 之后的代码
  4. 第一个过滤器的 chain.doFilter() 之后的代码
  5. 最后返回响应

如何自定义一个Filter?

只需要实现 javax.servlet.Filter这个接口,重写其中的方法。实例如下:

1
2
3
4
5
6
7
8
@Component
public class CrosFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 继续执行下一个过滤器
filterChain.doFilter(servletRequest, servletResponse);
}
}

Spring Boot如何配置Filter?

配置类中使用@Bean注入【推荐使用】

只需要将 FilterRegistrationBean 这个实例注入到IOC容器中即可,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Configuration
public class FilterConfig {

@Autowired
CrosFilter crosFilter;

@Bean
FilterRegistrationBean<CrosFilter> crosFilter() {
FilterRegistrationBean<CrosFilter> registrationBean = new FilterRegistrationBean<CrosFilter>();
registrationBean.setFilter(crosFilter);
registrationBean.addUrlPatterns("/*");
registrationBean.setName("crosFilter");
// 设置优先级别
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return registrationBean;
}

}

使用@WebFilter

@WebFilter 是Servlet3.0的一个注解,用于标注一个Filter,Spring Boot也是支持这种方式,只需要在自定义的Filter上标注该注解即可,如下:

1
2
3
4
5
6
7
8
@WebFilter(filterName = "crosFilter2", urlPatterns = {"/*"})
public class CrosFilter2 implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 继续执行下一个过滤器
filterChain.doFilter(servletRequest, servletResponse);
}
}

要想 @WebFilter 注解生效,需要在配置类上标注另外一个注解 @ServletComponentScan 用于扫描使其生效 ,如下:

1
2
3
@SpringBootApplication
@ServletComponentScan(value = {"com.monochrome.filter"})
public class SpringbootApplication {}

举个栗子

对于前后端分离的项目来说跨域是一个难题,什么是跨域问题?如何造成的? 对于跨域问题有多中解决方案,比如JSONP,网关支持等等。如何使用过滤器来解决跨域问题?

其实原理很简单,只需要在请求头中添加相应支持跨域的内容即可,如下代码仅仅是简单的演示下,针对细致的内容还需自己完善,比如白名单等等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Component
public class CrosFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletRequest;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", " Origin, X-Requested-With, Content-Type,Accept");
// 继续执行下一个过滤器
filterChain.doFilter(servletRequest, servletResponse);
}
}