拦截器 Interceptor

拦截器 Interceptor

实现一个自己拦截器只需要两个步骤即可:

  1. 新建一个类实现HandlerInterceptor接口;
    重写我们需要的方法,如上的三个方法并不是必须的,视自己的业务需求而定。
public class MyInterceptor implements HandlerInterceptor {
    private Logger logger = LoggerFactory.getLogger(MyInterceptor.class);
    /**
     * 预处理回调方法,实现处理器的预处理(如检查登陆),第三个参数为响应的处理器,自定义Controller
     * 返回值:true表示继续流程(如调用下一个拦截器或处理器);
   *       false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;
   */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.info("preHandle");
        // 返回false会阻止调用链的继续进行
        return true;
    }
    /**
     * 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
   */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        logger.info("postHandle");
    }
    /**
    * 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finall
   * 但仅调用处理器执行链中preHandle返回true的拦截器的afterCompletion。
   */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        logger.info("afterCompletion");
    }
}
  1. 在实现了自己的拦截器后还不能马上使用,还需要在Spring中注册与配置,我们新建一个配置类,将上面我们实现的拦截器进行注册,此时拦截器就能生效了。
@Configuration
@EnableWebMvc
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor());
    }
}

多拦截器的处理过程

当我们需要多个拦截器的时候,每个拦截器的方法处理顺序如下:
Interceptor1:preHandle > Interceptor2:preHandle > Interceptor2:postHandle > Interceptor1:postHandle > Interceptor2:afterCompletion > Interceptor1:afterCompletion
为什么会有这样的执行结果呢?其实这和HandlerInterceptor中三个方法的执行时机有关系:

preHandle:在Controller处理之前做拦截进行处理,因此越是声明在前的拦截器,其preHandle方法就越先得到执行。

postHandle:在Controller处理之后,视图渲染返回之前进行处理,有点像括号嵌套的机制,左括号越是在前,其对应的右括号越是在后。

(PS:这里的“返回之前”只是针对视图渲染逻辑的处理,如果是Rest的接口,那么调用会在Controller处理之后直接返回,不会等到postHandle处理完之后才返回)

afterCompletion:在所有处理完成后用于对资源进行回收进行处理,因此,所有的afterCompletion都会在所有的preHandle和postHandle之后才会执行,且和postHandle一样,按照右括号规则执行。

对特定请求地址的拦截

我们可以在拦截器中定义对那些URL需要拦截,而哪些URL是不需要做任何处理的。

@Configuration
@EnableWebMvc
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 对所有的请求都要拦截,但是“/getInt”不在拦截的范围之内
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/**").excludePathPatterns("/getInt");
    }
}

拦截器适配器HandlerInterceptorAdapter

有时候我们可能只需要实现三个回调方法中的某一个,如果实现HandlerInterceptor接口的话,三个方法必须实现,不管你需不需要,此时spring提供了一个HandlerInterceptorAdapter适配器(一种适配器设计模式的实现),允许我们只实现需要的回调方法。

You must be logged in to post a comment