拦截器Interceptor用来对http请求的处理过程进行拦截,以插入特定的处理逻辑,比如权限鉴别,有点AOP的味道。上文讲过,HandlerMapping对匹配的http请求会返回一个HandlerExecutionChain,而Interceptor正是这个chain的一部分。
HandlerInterceptor
拦截器必须实现HandlerInterceptor接口:
public interface HandlerInterceptor {
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception;
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex);
}
- preHandle方法调用发生在http请求的处理器方法执行之前,如果返回false,那么会中断当前的处理流程。
- postHandle方法调用发生在http请求的处理器方法执行之后,view的渲染之前,该处理器方法可以向modelAndView插入额外数据。
- afterCompletion方法调用发生在http请求完全被处理(处理结果已经返回给客户端)之后,如果preHandle放回false,则不会被调用。
对于@ResponseBody的处理器方法,postHandle调用时返回视图的渲染已经完成,此时想修改返回给用户的数据,已经迟了。此类需求可通过ResponseBodyAdvice来满足。
配置拦截器
最好的方式是实现WebMvcConfigurer接口的addInterceptors方法:
@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new BlockInterceptor()).addPathPatterns("/block");
registry.addInterceptor(new TraceInterceptor()).addPathPatterns("/trace");
registry.addInterceptor(new TraceInterceptor()).addPathPatterns("/exception");
}
}
实际上,这些Intercetor会被注入到每个HandlerMapping实例里面,这发生在HandlerMapping被创建的过程中,因此对于手动创建的SimpleUrlHandlerMapping,上面配置的interceptor不会生效,需要手动加进去:
@Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setUrlMap(Collections.singletonMap("/simple","controller"));
mapping.setOrder(5);
mapping.setInterceptors(new TraceInterceptor());
return mapping;
}