过滤器
Filter过滤器并不是标准的Servlet,它只是对Web容器和Servlet之间的过滤器。主要是对ServletRequest预处理和ServletResponse的后处理。
graph LR
webBrowser[web浏览器] --请求--> webContainer[web容器]
webContainer --请求--> filter[过滤器]
filter --请求--> servlet
servlet --响应--> filter
filter --响应--> webContainer
webContainer --响应--> webBrowser
springboot实现
//编写Filter
public class Filter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//主要是为了打印看的清楚
System.err.println("Filter1");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
System.err.println("请求URL:" + httpServletRequest.getRequestURI());
System.err.println("Filter1");
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
//编写Filter
public class Filter2 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.err.println("Filter2");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
System.err.println("请求URL:" + httpServletRequest.getRequestURI());
System.err.println("Filter2");
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
//注册Filter
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean filter1(){
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new Filter1());
//过滤器名称
registration.setName("filter1");
//拦截路径
registration.addUrlPatterns("/*");
//设置顺序
registration.setOrder(10);
return registration;
}
@Bean
public FilterRegistrationBean filter2(){
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new Filter2());
//过滤器名称
registration.setName("filter2");
//拦截路径
registration.addUrlPatterns("/*");
//设置顺序
registration.setOrder(1);
return registration;
}
}
@GetMapping("/say")
public String hello() {
System.err.println("say hello");
return "hello boot";
}
执行结果

result.png
查看发现过滤器已经生效了,spring-boot使用
order设置过滤器的执行顺序,从小到大。
备注
Servlet3.0增加了通过@WebFilter注册过滤器。但是使用注解方式实现无法配置执行顺序。
拦截器
过滤器为
Servlet内的Api。HandlerInterceptor为Spring 提供的拦截器。
//编写拦截器
public class Interceptor1 extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.err.println("Interceptor1 请求前");
return super.preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.err.println("Interceptor1 请求后");
super.postHandle(request, response, handler, modelAndView);
}
}
public class Interceptor2 extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.err.println("Interceptor2 请求前");
return super.preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.err.println("Interceptor2 请求后");
super.postHandle(request, response, handler, modelAndView);
}
}
//拦截器配置
//注册拦截器
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
// 直接 new 不能注入组件
@Bean
public Interceptor1 interceptor1(){
return new Interceptor1();
}
@Bean
public Interceptor2 interceptor2(){
return new Interceptor2();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册拦截器 拦截规则
//多个拦截器时 以此添加 执行顺序按添加顺序
registry.addInterceptor(interceptor1()).addPathPatterns("/**").order(2);
registry.addInterceptor(interceptor2()).addPathPatterns("/**").order(1);
}
}
执行结果

result.png
order设置执行顺序,从小到大。
RequestBodyAdvice/ResponseBodyAdvice
RequestBodyAdvice可拦截@RequestBody请求体参数的方法。
ResponseBodyAdvice对于返回内容做拦截处理。
@RestControllerAdvice
public class RequestAdvice implements RequestBodyAdvice {
//判断是否支持
@Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
//在请求体未读取(转换)时调用
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
System.err.println("RequestAdvice beforeBodyRead");
return new TestHttpInputMessage(inputMessage);
}
//在请求体完成读取后调用
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
System.err.println("RequestAdvice afterBodyRead");
System.err.println(body);
return body;
}
//当请求体为空时调用
@Override
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
System.err.println("RequestAdvice handleEmptyBody");
return body;
}
class TestHttpInputMessage implements HttpInputMessage {
private HttpHeaders headers;
private InputStream body;
public TestHttpInputMessage(HttpInputMessage httpInputMessage) throws IOException {
this.headers = httpInputMessage.getHeaders();
this.body = httpInputMessage.getBody();
}
@Override
public InputStream getBody() throws IOException {
return body;
}
@Override
public HttpHeaders getHeaders() {
return headers;
}
}
}
@RestControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
//判断是否支持
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
System.err.println("ResponseAdvice");
System.err.println(body);
return body;
}
}
返回结果

result.png
备注
使用情况很少,场景多是对请求参数加密,返回结果加密。
区别

result.png
- 过滤器在拦截器之前执行。
- 过滤器是
Servlet规范,所以拦截器只可用于web程序,拦截器是Spring规范,所以拦截器内可注Spring对象。 - 拦截器比过滤器更加精细,可在请求前后,视图渲染后拦截,而过滤器只可在
Servlet前后。 -
RequestBodyAdvice只可拦截参数注解@RequestBody的post请求。 - 拦截器,过滤器中使用
HttpServletRequst获取body中的数据时只能使用输入流读取,但是输入流只能读取一次,所以需要将HttpServletRequest再次包装缓存body内容。Advice则可多次读取。