SpringBoot HandlerInterceptor 拦截器

环境

  • SpringBoot 环境

相关

  • spring-boot在web层面使用了spring mvc的拦截器功能,并没有做其他处理,故我们只要熟悉mvc的拦截器,自然而然可以将拦截器加入到spring-boot上
  • 已知request 请求处理顺序,Filter -> HandlerInterceptor 拦截器 -> AOP
  • Filter 过滤器属于 Servlet 范畴的API, 与Spring 没什么关系
  • HandlerInterceptor 拦截器 属于Spring 的范畴
  • 只有经过 dispatchservlet 的请求,才会走拦截器chain,我们自定义的的servlet 请求是不会被拦截的
  • 但过滤器会拦截所有请求

拦截器提供更精细的控制-时间段区分

  • 在request被controller 响应之前,只有返回true 才会进入后续interceptor 和 controller
  • 在request被响应之后-dispatcherServlet进行视图渲染之前,可以在此处对Controller 处理后的ModelAndView对象进行处理
  • 视图渲染之后,用于资源清理

特点

我们不能通过修改拦截器修改request内容,但可以通过抛出异常(或者返回false)暂停request执行

案例

基础
Spring MVC 中拦截器顶层是 HandlerInterceptor, 它有3个方法

public interface HandlerInterceptor {

    //controller 方法执行前执行,当return TRUE 时进入下一个 拦截器 或直接进入 Controller 方法
    boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception;

    void postHandle(
            HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception;

    
    void afterCompletion(
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception;

}

通常情况下继承 HandlerInterceptorAdapter 抽象类 来实现自定义拦截器

public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {

    /**
     * This implementation always returns  true
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        return true; //硬编码为TRUE,自定义拦截器 可以覆盖
    }

    /**
     * This implementation is empty.
     */
    @Override
    public void postHandle(
            HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception {
            //空实现
    }

    /**
     * This implementation is empty.
     */
    @Override
    public void afterCompletion(
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
            //空实现
    }

    /**
     * This implementation is empty.
     */
    @Override
    public void afterConcurrentHandlingStarted(
            HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
    }

}

AsyncHandlerInterceptor接口代码

public interface AsyncHandlerInterceptor extends HandlerInterceptor {

    /**
     * Called instead of {@code postHandle} and {@code afterCompletion}, when
     * the a handler is being executed concurrently.
     * <p>Implementations may use the provided request and response but should
     * avoid modifying them in ways that would conflict with the concurrent
     * execution of the handler. A typical use of this method would be to
     * clean up thread-local variables.
     * @param request the current request
     * @param response the current response
     * @param handler the handler (or {@link HandlerMethod}) that started async
     * execution, for type and/or instance examination
     * @throws Exception in case of errors
     */
    void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception;

}

注

  • HandlerInterceptorAdapter 是 适配器 模式的一种
    • 实现适配器模式有两种方式:继承 和 组合
  • 实现接口时,可以将某些接口方法写死,然后让继承类覆盖
  • AsyncHandlerInterceptor 接口只增添了一个接口,这种设计模式可以留意下

自定义拦截器

@Slf4j
public class MyHandlerInterceptor1 extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("handler interceptor1 preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("handler interceptor1 postHandle");
        //super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("handler interceptor1 afterComplete");
        //super.afterCompletion(request, response, handler, ex);
    }
}
@Slf4j
public class MyHandlerInterceptor2 extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("handler interceptor2 preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("handler interceptor2 postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("handler interceptor2 afterComplete");
    }
}

注册拦截器

@Configuration //标记为配置类,本质上是将该类纳入上下文从而执行addInterceptor动作,故@Component注解亦可
public class MyInterceptorConfigure extends WebMvcConfigurerAdapter {
    //继承WebMVCConfigureAdapter,并覆盖 addInterceptror 方法
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyHandlerInterceptor1());
        registry.addInterceptor(new MyHandlerInterceptor2()); //添加顺序决定了拦截顺序
        super.addInterceptors(registry);
    }
}

controller

@RestController
@RequestMapping("/interceptor")
public class MyInterceptorController {

    @RequestMapping("") //没有主method属性,表示接受任意method请求
    public String testIntercept(String param) {  //未加 @RequestParam() 同样也可绑定方法参数param 
        System.out.println("param: " + param);
        return param;
    }

}

运行结果

2018-01-17 01:16:50.993  INFO 568 --- [           main] c.l.s.interceptor.MyHandlerInterceptor1  : handler interceptor1 preHandle
2018-01-17 01:16:50.993  INFO 568 --- [           main] c.l.s.interceptor.MyHandlerInterceptor2  : handler interceptor2 preHandle
param: test
2018-01-17 01:16:51.029  INFO 568 --- [           main] c.l.s.interceptor.MyHandlerInterceptor2  : handler interceptor2 postHandle
2018-01-17 01:16:51.030  INFO 568 --- [           main] c.l.s.interceptor.MyHandlerInterceptor1  : handler interceptor1 postHandle
2018-01-17 01:16:51.032  INFO 568 --- [           main] c.l.s.interceptor.MyHandlerInterceptor2  : handler interceptor2 afterComplete
2018-01-17 01:16:51.032  INFO 568 --- [           main] c.l.s.interceptor.MyHandlerInterceptor1  : handler interceptor1 afterComplete

添加Aspect后的运行结果
Aspect 代码

@Component
@Aspect
@Slf4j
public class TestAspect {

    @Pointcut(("execution(public * com.lance.spring.controller.*.*(..))"))
    public void restPoint() {

    }

    @Before("restPoint()")
    public void before(JoinPoint joinPoint) {
        log.info("aspect before pointcut");
    }

    @After("restPoint()")
    public void after(JoinPoint joinPoint) {
        log.info("aspect after pointcut");
    }

    @Around("restPoint()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("aspect around before target method");
        joinPoint.proceed();
        log.info("aspect around after target method");
    }
}

结果

2018-01-17 01:19:42.860  INFO 6256 --- [           main] c.l.s.interceptor.MyHandlerInterceptor1  : handler interceptor1 preHandle
2018-01-17 01:19:42.860  INFO 6256 --- [           main] c.l.s.interceptor.MyHandlerInterceptor2  : handler interceptor2 preHandle
2018-01-17 01:19:42.889  INFO 6256 --- [           main] com.lance.spring.aop.TestAspect          : aspect around before target method
2018-01-17 01:19:42.889  INFO 6256 --- [           main] com.lance.spring.aop.TestAspect          : aspect before pointcut
param: test
2018-01-17 01:19:42.899  INFO 6256 --- [           main] com.lance.spring.aop.TestAspect          : aspect around after target method
2018-01-17 01:19:42.899  INFO 6256 --- [           main] com.lance.spring.aop.TestAspect          : aspect after pointcut
2018-01-17 01:19:42.915  INFO 6256 --- [           main] c.l.s.interceptor.MyHandlerInterceptor2  : handler interceptor2 postHandle
2018-01-17 01:19:42.916  INFO 6256 --- [           main] c.l.s.interceptor.MyHandlerInterceptor1  : handler interceptor1 postHandle
2018-01-17 01:19:42.916  INFO 6256 --- [           main] c.l.s.interceptor.MyHandlerInterceptor2  : handler interceptor2 afterComplete
2018-01-17 01:19:42.916  INFO 6256 --- [           main] c.l.s.interceptor.MyHandlerInterceptor1  : handler interceptor1 afterComplete
参考:http://jinnianshilongnian.iteye.com/blog/1675504
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 137,341评论 19赞 139
  • 姓名: 李小娜 [嵌牛导读]: SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,...
    n184阅读 3,343评论 0赞 4
  • 1、Spring MVC请求流程 (1)初始化:(对DispatcherServlet和ContextLoderL...
    拾壹北阅读 2,068评论 0赞 12
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 47,456评论 6赞 342
  • 你托三月的风捎来 春的消息 柔声细语的温柔 和煦是你的眼眸 你命七月的雨冷却 夏的狂热 冰与火的交织里 你纷扬的衣...
    岁往阅读 427评论 0赞 1

友情链接更多精彩内容