1.拦截器的使用
-
1.新建类实现HandlerInterceptor接口
-
2.重写三个方法
@Component
public class InterceptorController implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("HandlerInterceptor-->>preHandle");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
System.out.println("HandlerInterceptor-->>postHandle");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
System.out.println("HandlerInterceptor-->>afterCompletion");
}
}
-
3.在springmvc.xml中,装配拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/testInt"/>
<ref bean="interceptorController"></ref>
</mvc:interceptor>
</mvc:interceptors>
2.拦截器的工作原理
单个拦截器工作原理
-
浏览器发送请求
-
执行拦截器的preHandle方法
-
执行Controller中的方法,处理请求并作出响应
-
执行拦截器的postHandle方法
-
执行DispatchServlet中的视图渲染
-
执行拦截器的afterCompletion方法
-
响应
多个拦截器的工作原理
拦截器的顺序由配置的顺序决定
preHandle返回值问题
当第一个prehandle返回值为false时,程序终止
当第一个拦截器为true,第二个拦截器返回值为false时
-
执器的行当前拦截器和之前拦截preHandle方法,
-
执行之前拦截器的afterCompletion方法
拦截器源码解析
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
首先执行applyPreHandle方法,追进去看一下
使用了for循环正序调用自定义的preHandle方法。
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
for (int i = 0; i < this.interceptorList.size(); i++) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
return true;
}
调用handle准备执行controller方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
public String testInt(){
System.out.println("执行controller中的方法");
// int a=1/0;
return "success";
}
执行controller后执行applyPostHandle方法,可以看出这是一个倒叙循环,分别调用各个拦截器的postHandle方法
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
interceptor.postHandle(request, response, this.handler, mv);
}
}
进入视图渲染
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
渲染完成之后调用triggerAfterCompletion方法,这里也是一个倒叙循环,分别调用各个拦截器的afterCompletion方法
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
为什么第一个拦截器preHandle为true,第二个为false时,第一个拦截器的afterCompletion方法也会执行,因为在applyPreHandle方法在执行完成后会给一个属性interceptorIndex赋值。interceptorIndex默认值为-1.只有当第一个拦截器执行完成之后会赋值0.
当自定义的preHandle方法返回false时,会进入triggerAfterCompletion这个方法,该方法就是调用自定义的afterCompletion方法
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
for (int i = 0; i < this.interceptorList.size(); i++) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
return true;
}
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
还是倒叙调用afterCompletion方法
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
注意: 当controller层出现异常时,postHandle方法不会执行
3.拦截器和过滤器的区别
1.执行时机不同
过滤器的执行时机是servlet执行之前和servlet执行之后
拦截器的执行时机是DispatcherServlet后Controller之前,执行Controller之后DispatcherServlet之前和执行DispatcherServlet和视图渲染之后
2.作用范围不同
过滤器属于web服务组件
拦截器属于springMVC框架组件
3.配置方式不同
自定义拦截器要实现HandlerInterceptor接口并在spring中配置
过滤器需要实现Filter接口在web.xml中配置