HandlerExecutionChain 是一个执行链,包含一个请求的处理器,同时包括若干个对该请求的拦截器。当 HandlerMapping 返回 HandlerExecutionChain 后,DispatchServlet 将请求交给定义在 HandlerExecutionChain 中的拦截器和处理器一并处理
HandlerExecutionChain 的结构
HandlerExecutionChain 是负责处理请求并返回 ModelANdView 的处理执行链。请求在被 Handler 执行的前后,链中装配的 HandlerInterceptor 会实施拦截操作
拦截器的接口方法
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) : 在请求到达 Handler 之前,先执行这个前置处理方法。当该方法返回false时,请求直接返回,不会传递到链中下一个拦截器,更不会调用处理器链末端的 Handler 中,只有返回 true 时请求才向链中的下一个处理节点传递
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) : 请求被 HandlerAdapter 执行后,执行这个后置处理方法
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) : 在响应已经被渲染后,执行该方法
位于处理器末端是一个 Handler,DispatcherServlet 通过 HandlerAdapter 适配器对 Handler 进行封装,并按统一的适配器接口对 Handler 处理方式进行调用
在 spring-mvc.xml 中
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd"
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping
path="/**"/>
<!-- 排除前端页面-->
<mvc:exclude-mapping
path="/insurance/**"
/>
<bean
class="com.insurance.web.component.interceptor.LoggerInterceptor"
/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping
path="/member/status"/>
<mvc:mapping
path="/member/mobile"/>
<bean
class="com.insurance.consumer.web.intercept.BigPlatformLoginInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping
path="/member/status"/>
<mvc:mapping
path="/member/mobile"/>
<mvc:mapping
path="/order/*"/>
<bean
class="com.insurance.consumer.web.intercept.LoginTokenInterceptor"
/>
</mvc:interceptor>
</mvc:interceptors>
拦截器实现类中
public class
LoggerInterceptor
extends HandlerInterceptorAdapter {
private static Logger
log
= LoggerFactory.getLogger(LoggerInterceptor.class);
// 重写initial method , 解决相同线程进入多次报exception
private
ThreadLocal<Long> startTimeThreadLocal
=
new ThreadLocal<Long>() {
@Override
protected
Long initialValue() {
return System.currentTimeMillis();
}
};
@Override
public boolean
preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o)
throws
Exception {
startTimeThreadLocal.set(System.currentTimeMillis());
String accessUri = httpServletRequest.getRequestURI().substring(httpServletRequest.getContextPath().length());
log.info("call method:"
+ accessUri);
return true;
}
@Override
public void
postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView)
throws
Exception {
}
@Override
public void
afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e)
throws
Exception {
long endTime = System.currentTimeMillis();//2、结束时间
long
beginTime = startTimeThreadLocal.get();//得到线程绑定的局部变量(开始时间)
startTimeThreadLocal.remove();
String accessUri = httpServletRequest.getRequestURI().substring(httpServletRequest.getContextPath().length());
StringBuilder logs =
new
StringBuilder("\n");
logs.append("**************** call method ****************");
logs.append("\n").append("call
method :" + accessUri +
" , used time :" + (endTime - beginTime) +
" ms.");
Map<String, String[]> parameters = httpServletRequest.getParameterMap();
for (String key : parameters.keySet()) {
logs.append("\n").append(key
+ " = "
+ parameters.get(key)[0]);
}
if (e !=
null) {
log.error(e.getMessage(), e);
}
logs.append("\n").append("****************
call method end ****************");
log.info(logs.toString());
}
}
可以配置多个拦截器,每个拦截器都可以指定一个匹配的映射路径,以限制拦截器作用范围