1.拦截器: 用于对handle进行预处理和后处理
2.执行过程
在org.springframework.web.servlet.DispatcherServlet#doDispatch中:
HandlerExecutionChain mappedHandler = null;
//首先获取HandlerExecutionChain(handle和拦截器)
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest, false);
...
//1.拦截器开始作用(PreHandle方法:说明切点是在执行handle之前)
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
//只要有拦截器返回false就退出,同时在catch语句块中触发AfterCompletion
return;
}
//通过applyPreHandle的for循环可以看出PreHandle的执行顺序为顺序执行
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (getInterceptors() != null) {
for (int i = 0; i < getInterceptors().length; i++) {
HandlerInterceptor interceptor = getInterceptors()[i];
//只要一个preHandle返回false,就返回false
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
//执行handle
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//2.执行PostHandle(切点在handle执行后,视图返回之前)
mappedHandler.applyPostHandle(processedRequest, response, mv);
//通过applyPostHandle的for循环可以知道PostHandle执行顺序为逆序
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
if (getInterceptors() == null) {
return;
}
for (int i = getInterceptors().length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = getInterceptors()[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
//3.AfterCompletion在下面的方法中被调用(AfterCompletion切入点是在视图渲染后(执行异常后也会被调用),也就是视图返回前执行)
//视图渲染,处理异常(视图渲染之后会执行triggerAfterCompletion)
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
//出现异常错误后执行
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
//afterCompletion被使用的方法:(从for循环可以看出是逆序执行)
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {
if (getInterceptors() == null) {
return;
}
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = getInterceptors()[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
3.拦截器各个方法的作用
a)preHandle
//Called after HandlerMapping determined an appropriate handler object, but before HandlerAdapter invokes the handler.(在handle被调用之前执行)
//return false表示拦截,不向下执行
//return true表示放行
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception;
作用:用于身份认证、身份授权
b)postHandle
//Called after HandlerAdapter actually invoked the handler, but before the DispatcherServlet renders the view.(handlle执行之后,视图返回之前)
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception;
作用:将公用的模型数据在这里传到视图,也可以在这里统一指定视图(比如:菜单导航)
c)afterCompletion
//Callback after completion of request processing, that is, after rendering the view.(视图渲染后执行)
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception;
作用:统一异常处理,统一日志处理,资源清理
4.拦截器的配置和使用
配置:
主要使用springmvc配置类似全局的拦截器,springmvc框架将配置的类似全局的拦截器注入到每个HandlerMapping中。
在springMVC的配置文件中配置
<mvc:interceptors>
<!--多个拦截器,顺序执行 -->
<mvc:interceptor>
<!-- /**表示所有url包括子url路径 -->
<mvc:mapping path="/**"/>
<bean class="cn.itcast.ssm.interceptor.HandlerInterceptor1"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="cn.itcast.ssm.interceptor.HandlerInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
当需要配置公开地址时,在<mvc:interceptor>
中添加:
<!--将公开地址配置在path中-->
<mvc:exclude-mapping path="/"/>
使用:
实现org.springframework.web.servlet.HandlerInterceptor这个接口
public class HandlerInterceptor1 implements HandlerInterceptor{...}
5.注意点
1)对于统一日志处理之类的全局设置:需要将对应的拦截器放在拦截器链的第一个
2)preHandle方法按拦截器配置的顺序执行,postHandle和afterCompletion按拦截器配置的逆向顺序执行。
3)只要有一个拦截器不放行,postHandle不会执行,只有在拦截器链内所有拦截器放行(即返回true)才会执行
4)只有preHandle返回true,afterCompletion才会执行
运行示例
比如两个拦截器:
1)第一个拦截器放行,第二个放行:
HandlerInterceptor1...preHandle
HandlerInterceptor2...preHandle
HandlerInterceptor2...postHandle
HandlerInterceptor1...postHandle
HandlerInterceptor2...afterCompletion
HandlerInterceptor1...afterCompletion
2)第一个拦截器放行,第二个拦截:
HandlerInterceptor1...preHandle
HandlerInterceptor2...preHandle
HandlerInterceptor1...afterCompletion
3)第一个拦截器拦截,第二个放行(或者不放行):
HandlerInterceptor1…preHandle