1、什么是 Interceptor?
SpringMVC 的拦截器 HandlerInterceptor,针对调用 Controller 的请求,进行拦截和处理。
- 我们首先自定义一个Interceptor
public class DemoInterceptor implements HandlerInterceptor {
// 在进入控制器之前执行
// 如果返回值为false,阻止进入控制器
// 用途:拦截未登录请求;控制代码
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
//arg2是准备调用的 Controller方法
System.out.println("arg2=" + arg2);
return true;
}
// 控制器执行完成,进入到 jsp之前执行
// 用途:日志记录、敏感词语过滤
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
//arg3.getViewName()可获得准备跳转的视图逻辑名 View
System.out.println("往" + arg3.getViewName() + "跳转");
//arg3.getModel()可获得视图数据 Model
System.out.println("data1的值" + arg3.getModel().get("data1"));
String word = arg3.getModel().get("data1").toString();
String newWord = word.replace("色情", "**");
arg3.getModel().put("data1", newWord);
// arg3.getModel().put("data1", "修改后的内容");
}
// jsp执行完成后执行或 Controller方法出现异常时执行
// 用途:记录执行过程中出现的异常
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
// arg3是Controller方法中出现的异常
System.out.println("arg3:" + arg3);
if (arg3 != null) {
//若是除零导致的,则arg3.getMessage()显示:/ by zero
System.out.println( arg3.getMessage() );
}
}
}
我们从SpringMVC运行流程中也可以看出拦截器的生效时机:(留意中文注释即可)
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
try {
ModelAndView mv = null;
try {
processedRequest = checkMultipart(request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest, false);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Apply preHandle methods of registered interceptors.
// 调用拦截器的 preHandle方法
HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
if (interceptors != null) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
return;
}
interceptorIndex = i;
}
}
// Actually invoke the handler.
// 适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// ——————————— HandlerAdapter调用 Controller方法 ————————————
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// Do we need view name translation?
if (mv != null && !mv.hasView()) {
mv.setViewName(getDefaultViewName(request));
}
// Apply postHandle methods of registered interceptors.
// 调用拦截器的 postHandle方法
if (interceptors != null) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
}
}
}
...
}
}
2、springmvc.xml 文件的拦截器配置
<!-- 拦截器 -->
<mvc:interceptors>
<!--拦截所有控制器 <bean class="com.ljm.interceptor.DemoInterceptor"></bean> -->
<!-- 拦截特定的的url -->
<mvc:interceptor>
<mvc:mapping path="/demo" />
<mvc:mapping path="/demo1" />
<mvc:mapping path="/demo2" />
<bean class="com.bjsxt.interceptor.DemoInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
3、拦截器栈
当多个拦截器同时生效时,将组成拦截器栈。
执行顺序和Interceptor在 springmvc.xml 中的配置顺序有关。例如,先配置拦截器 A ,后配置拦截器 B ,则执行顺序为 :
preHandle(A) --> preHandle(B) --> 控制器方法 --> postHandle(B) --> postHanle(A) --> JSP --> afterCompletion(B) --> afterCompletion(A)
(先进后出)