過濾器
Filter過濾器并不是標準的Servlet,它只是對Web容器和Servlet之間的過濾器。主要是對ServletRequest預(yù)處理和ServletResponse的后處理。
graph LR
webBrowser[web瀏覽器] --請求--> webContainer[web容器]
webContainer --請求--> filter[過濾器]
filter --請求--> servlet
servlet --響應(yīng)--> filter
filter --響應(yīng)--> webContainer
webContainer --響應(yīng)--> webBrowser
springboot實現(xiàn)
//編寫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("/*");
//設(shè)置順序
registration.setOrder(10);
return registration;
}
@Bean
public FilterRegistrationBean filter2(){
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new Filter2());
//過濾器名稱
registration.setName("filter2");
//攔截路徑
registration.addUrlPatterns("/*");
//設(shè)置順序
registration.setOrder(1);
return registration;
}
}
@GetMapping("/say")
public String hello() {
System.err.println("say hello");
return "hello boot";
}
執(zhí)行結(jié)果

result.png
查看發(fā)現(xiàn)過濾器已經(jīng)生效了,spring-boot使用
order設(shè)置過濾器的執(zhí)行順序,從小到大。
備注
Servlet3.0增加了通過@WebFilter注冊過濾器。但是使用注解方式實現(xiàn)無法配置執(zhí)行順序。
攔截器
過濾器為
Servlet內(nèi)的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) {
//注冊攔截器 攔截規(guī)則
//多個攔截器時 以此添加 執(zhí)行順序按添加順序
registry.addInterceptor(interceptor1()).addPathPatterns("/**").order(2);
registry.addInterceptor(interceptor2()).addPathPatterns("/**").order(1);
}
}
執(zhí)行結(jié)果

result.png
order設(shè)置執(zhí)行順序,從小到大。
RequestBodyAdvice/ResponseBodyAdvice
RequestBodyAdvice可攔截@RequestBody請求體參數(shù)的方法。
ResponseBodyAdvice對于返回內(nèi)容做攔截處理。
@RestControllerAdvice
public class RequestAdvice implements RequestBodyAdvice {
//判斷是否支持
@Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
//在請求體未讀取(轉(zhuǎn)換)時調(diào)用
@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);
}
//在請求體完成讀取后調(diào)用
@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;
}
//當請求體為空時調(diào)用
@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;
}
}
返回結(jié)果

result.png
備注
使用情況很少,場景多是對請求參數(shù)加密,返回結(jié)果加密。
區(qū)別

result.png
- 過濾器在攔截器之前執(zhí)行。
- 過濾器是
Servlet規(guī)范,所以攔截器只可用于web程序,攔截器是Spring規(guī)范,所以攔截器內(nèi)可注Spring對象。 - 攔截器比過濾器更加精細,可在請求前后,視圖渲染后攔截,而過濾器只可在
Servlet前后。 -
RequestBodyAdvice只可攔截參數(shù)注解@RequestBody的post請求。 - 攔截器,過濾器中使用
HttpServletRequst獲取body中的數(shù)據(jù)時只能使用輸入流讀取,但是輸入流只能讀取一次,所以需要將HttpServletRequest再次包裝緩存body內(nèi)容。Advice則可多次讀取。