美文网首页
spring-boot 拦截

spring-boot 拦截

作者: EricDD | 来源:发表于2019-08-03 11:27 被阅读0次

过滤器

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

相关文章

网友评论

      本文标题:spring-boot 拦截

      本文链接:https://www.haomeiwen.com/subject/xiqjdctx.html