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());
}
}
可以配置多个拦截器,每个拦截器都可以指定一个匹配的映射路径,以限制拦截器作用范围