一、自定义拦截器
spring MVC也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器可以实现HandlerInterceptor接口,或者可以继承HandlerInterceptorAdapter 适配器类
-
- preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求 request 进行处理。如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true;如果程序员决定不需要再调用其他的组件去处理请求,则返回false。
- postHandle():这个方法在业务处理器处理完请求后,但是DispatcherServlet 向客户端返回响应前被调用,在该方法中对用户请求request进行处理。
- afterCompletion():这个方法在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
二、实验代码(单个拦截器)
public class FirstInterceptor implements HandlerInterceptor{ /** * 该方法在目标方法之前被调用. * 若返回值为 true, 则继续调用后续的拦截器和目标方法. * 若返回值为 false, 则不会再调用后续的拦截器和目标方法. * * 可以考虑做权限. 日志, 事务等. */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("[FirstInterceptor] preHandle"); return true; } /** * 调用目标方法之后, 但渲染视图之前. * 可以对请求域中的属性或视图做出修改. */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("[FirstInterceptor] postHandle"); } /** * 渲染视图之后被调用. 释放资源 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("[FirstInterceptor] afterCompletion"); } }
配置拦截器
<mvc:interceptors> <!-- 声明自定义拦截器 --> <bean id="firstHandlerInterceptor" class="com.atguigu.springmvc.interceptors.FirstHandlerInterceptor"></bean> </mvc:interceptors>
断点调试拦截器执行流程
拦截器方法执行顺序(小总结)
拦截器的配置
<mvc:interceptors> <!-- 配置拦截器(不)起作用的路径 --> <mvc:interceptor> <mvc:mapping path="/emps"/> <bean class="com.jdy.springmvc.interceptors.SecondInterceptor"></bean> </mvc:interceptor> </mvc:interceptors>
三、实验代码(多个拦截器)
自定义拦截器类(两个)
public class FirstHandlerInterceptor implements HandlerInterceptor { @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { System.out.println(this.getClass().getName() + " - afterCompletion"); } @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { System.out.println(this.getClass().getName() + " - postHandle"); } @Override public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { System.out.println(this.getClass().getName() + " - preHandle"); return true; } }
public class SecondHandlerInterceptor implements HandlerInterceptor { @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { System.out.println(this.getClass().getName() + " - afterCompletion"); } @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { System.out.println(this.getClass().getName() + " - postHandle"); } @Override public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { System.out.println(this.getClass().getName() + " - preHandle"); return true; } }
配置自定义拦截器
<mvc:interceptors> <!-- 声明自定义拦截器 --> <bean id="firstHandlerInterceptor" class="com.jdy.springmvc.interceptors.FirstHandlerInterceptor"></bean> <!-- 配置拦截器引用 --> <mvc:interceptor> <mvc:mapping path="/empList"/> <bean id="secondHandlerInterceptor" class="com.jdy.springmvc.interceptors.SecondHandlerInterceptor"></bean> </mvc:interceptor> </mvc:interceptors>
两个都是返回true :
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - preHandle
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - preHandle
************************************biz method*******************************
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - postHandle
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - postHandle
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - afterCompletion
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - afterCompletion
两个都是返回false:
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - preHandle
true,false
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - preHandle
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - preHandle
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - afterCompletion
false,true
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - preHandle
四、多个拦截方法的执行顺序
执行顺序图解
从源代码的执行角度分析流程
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { if (getInterceptors() != null) {
//升序 for (int i = 0; i < getInterceptors().length; i++) { HandlerInterceptor interceptor = getInterceptors()[i]; if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } } return true; }
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); } }
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); } } }
如果SecondHandlerInterceptor 的preHandle返回false,那么下面的实线就是两个拦截器的执行顺序。
结论:如果某一个拦截的preHandle执行完了,那么就一定要执行它的afterCompletion方法用于释放资源(例如FirstHandlerInterceptor),如果一个拦截器的preHandle返回false,那么它的afterCompletion方法不执行。
源码分析:分析interceptorIndex的值情况