什么是拦截器?
Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。
拦截器的作用:
拦截器可以说相当于是个过滤器:就是把不想要的或不想显示的内容给过滤掉。拦截器可以抽象出一部分代码可以用来完善原来的方法。同时可以减轻代码冗余,提高重用率。
拦截器执行流程:
(1)、程序先执行preHandle()方法,如果该方法的返回值为true,则程序会继续向下执行处理器中的方法,否则将不再向下执行;
(2)、在业务处理器(即控制器Controller类)处理完请求后,会执行postHandle()方法,然后会通过DispatcherServlet向客户端返回响应
(3)、在DispatcherServlet处理完请求后,才会执行afterCompletion()方法
1.拦截器的配置
创建一个类实现handlerInterceptor接口,并重写其中的方法,按照需求进行相应方法的重写,并且preHandle方法的返回值为true时,表示放行后面的方法才会被执行,为false则被拦截
public class Interceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return HandlerInterceptor.super.preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
xml配置
在xml文件中创建拦截器对象放入ioc容器中管理,并指明拦截器的拦截器路径和放行路径
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/home"/>
<bean id="Interceptor" class="com.letstalk.config.Interceptor"/>
</mvc:interceptor>
</mvc:interceptors>
2.拦截器的执行顺序
在执行处理器的过程中,springmvc会现根据请求获取一个执行链HandlerExecutionChain类型的都对象,其中包含了handler这个处理器方法和interceptorList是一个拦截器集合,其中包含了springmvc默认自带的拦截器和自己所配置的拦截器并按照在集合中的顺序是,默认的在前面,自己配置的按照配置的先后设置顺序
(1)preHandle方法的执行顺序
可以看出通过for循环来执行preHandle,执行成功后interceptorIndex加一,也就代表了interceptorIndex执行最后以一个拦截器方法执行成功的拦截器在集合中的索引,
for循环从0开始所以preHandle方法的执行顺序按照配置的前后顺序
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
this.triggerAfterCompletion(request, response, (Exception)null);
return false;
}
}
}
并在执行PreHandle方法后执行handler方法(处理器方法),并返回个modelandview类型的对象
(2) postHandle方法的执行顺序
从方法中可以看到for循环中倒序执行postHandle方法,所以postHandle方法的执行顺序是倒序
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = interceptors.length - 1; i >= 0; --i) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
从图可知posthandle方法在执行完成处理器方法之后
(3)afterCompletion方法的执行顺序
可以看出afterCompletion的执行顺序是从interceptorIndex开始倒序,也就是最后执行成功的拦截器开始倒序到第一个拦截器
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = this.interceptorIndex; i >= 0; --i) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable var8) {
logger.error("HandlerInterceptor.afterCompletion threw exception", var8);
}
}
}
}
afterCompletion方法执行在视图processDispatchResult方法之后,也就是视图被数据渲染之后