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.
     * 

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;
    }

}

运行结果

  • 运行方式:启动server,postman 发送请求 url: http://localhost:8080/interceptor?param=test
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

你可能感兴趣的:(SpringBoot HandlerInterceptor 拦截器)