一、拦截器
Spring MVC提供了拦截器机制,允许在运行目标方法前进行一些拦截工作,或者在目标方法运行之后进行一些其他处理
Spring MVC 中的拦截器是HandlerInterceptor接口,该接口包含了三个方法
- preHandler:这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求进行处理,如果需要该拦截器对请求进行拦截处理后还要调用其他拦截器,或者是业务处理器进行处理,则返回True既放行请求,如果不需要再调用其他组件就返回false,既不放行请求
- postHandler:这个方法在业务处理器处理完成请求后调用,但是DispatcherServlet向客户端返回响应前被调用,在该方法中对用户请求request进行处理
- afterCompletion:这个方法在DispatcherServlet完全处理请求后被调用,可以在该方法中进行一些资源清理的操作
二、自定义拦截器
拷贝spring-mvc-ajax项目,并重命名为spring-mvc-handler,删除除了配置之外的类及文件。
拦截器的正常流程
新建一个HandlerInterceptorSamplerController,在该Controller中定义interceptor方法,测试自定义的拦截器,并返回success页面
代码语言:javascript复制@Controller
public class HandlerInterceptorSamplerController {
@RequestMapping("/interceptor")
public String interceptor(){
System.out.println("interceptor方法被调用");
return "success";
}
}
在index.jsp页面增加一个超链接
代码语言:javascript复制<a href="/interceptor">拦截该请求</a>
新增interceptor包,新建一个自定义的拦截器ZuluInterceptor,自定义拦截器必须实现HandlerInterceptor接口,在拦截器中的每个方法中添加了日志打印
代码语言:javascript复制public class ZuluInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(this.getClass().getName() " preHandler方法运行了");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println(this.getClass().getName() " postHandle方法运行了");
System.out.println(modelAndView.getViewName());
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println(this.getClass().getName() " afterCompletion方法运行了");
}
}
在Spring MVC 配置文件中注册拦截器,配置这个拦截器拦截哪些请求
代码语言:javascript复制<mvc:interceptors>
<!--第一种方式配置某个拦截器,默认是拦截所有请求的-->
<bean class="com.citi.interceptor.ZuluInterceptor"></bean>
</mvc:interceptors>
启动应用,点击首页的超链接
根据控制台的输出,自定义的拦截器被成功调用
因此拦截器的正常流程是:拦截器preHandler方法 -> 目标方法 -> 拦截器的postHandler方法 -> 页面渲染 -> 拦截器的afterCompletion方法
拦截器的异常流程
异常流程1 - preHandler返回false
在ZuluInterceptor拦截器的preHandler方法返回false,再次启动,点击首页的超链接
控制台只输出了preHandler方法的执行信息,因此只要preHandler返回false,既不放行就不会有以后的方法的执行。
异常流程2 - 其他异常
保持preHandler方法返回true,同时在Controller中的interceptor方法返回页面前增加异常代码
代码语言:javascript复制@RequestMapping("/interceptor")
public String interceptor(){
System.out.println("interceptor方法被调用");
// 异常代码
int i = 10 / 0;
return "success";
}
再次重新启动应用,点击页面的超链接
页面出现有异常代码导致的报错
此时控制台执行了afterCompletion方法
三、多个拦截器执行顺序
在interceptor包中拷贝ZuluInterceptor并重命名为DeltaInterceptor;在Spring MVC配置文件中注册新定义的拦截器
代码语言:javascript复制<mvc:interceptors>
<!--第一种方式配置某个拦截器,默认是拦截所有请求的-->
<bean class="com.citi.interceptor.ZuluInterceptor"></bean>
<bean class="com.citi.interceptor.DeltaInterceptor"></bean>
</mvc:interceptors>
将Controller中的interceptor方法中的异常代码注销,重新启动,点击页面的插连接
根据控制台的输出可以确定,限制性了Zulu拦截器中的preHandler方法,接着执行Delta拦截器的preHandler方法,再执行目标方法,接着调用Delta拦截器的postHandler,再执行Zulu拦截器的postHandler,再执行Delta拦截器的afterCompletion方法,最后再执行Zulu拦截器的afterCompletion方法
拦截顺序: 拦截器拦截顺序是按照配置的先后顺序,调整拦截器配置顺序
代码语言:javascript复制<mvc:interceptors>
<!--第一种方式配置某个拦截器,默认是拦截所有请求的-->
<bean class="com.citi.interceptor.DeltaInterceptor"></bean>
<bean class="com.citi.interceptor.ZuluInterceptor"></bean>
</mvc:interceptors>
再次启动,点击首页的超链接
根据控制台输出,配置文件中先配置的Delta拦截器最先执行了
多个拦截器的异常流程:
保持Spring MVC配置文件中Delta拦截器在前,Zulu拦截器在后的顺序。如果Delta拦截器不放行,也就没有后面所有的调用;如果Zulu拦截器不放行,会是什么结果?
在Zulu拦截器中返回false,重新启动应用,并点击首页的超链接
根据控制台的输出可以确定,即是Zulu拦截器不放行,但是Delta的afterCompletion方法还是会执行。
已放行了的拦截器的afterCompletion方法总会执行