Spring MVC也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器必须实现HandlerInterceptor接口
- preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求 request 进行处理。如果程序员决定该拦截器对 请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true;如果程序员决定不需要再调用其他的组件 去处理请求,则返回false。
- postHandle():这个方法在业务处理器处理完请求后,但是DispatcherServlet 向客户端返回响应前被调用,在该方法中对用户请求request进行处理。
- afterCompletion():这个方法在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
一、自定义拦截器
package com.nchu.mybatis.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Created by yangshijing on 2018/1/4 0004. */ public class HelloInterceptor implements HandlerInterceptor { /** * 该方法在目标方法之前被调用. * 若返回值为 true, 则继续调用后续的拦截器和目标方法. * 若返回值为 false, 则不会再调用后续的拦截器和目标方法. * * 可以考虑做权限. 日志, 事务等. */ @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { System.out.println("HelloInterceptor preHandle"); return false; } /** * 调用目标方法之后, 但渲染视图之前. * 可以对请求域中的属性或视图做出修改. */ @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { System.out.println("HelloInterceptor postHandle"); } /** * 渲染视图之后被调用. 释放资源 */ @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { System.out.println("HelloInterceptor afterCompletion"); } }
二、拦截器配置
<mvc:interceptors> <!--拦截所有资源--> <!--<bean class="com.nchu.mybatis.interceptor.HelloInterceptor"></bean>--> <mvc:interceptor> <!--拦截指定的资源--> <mvc:mapping path="/employee/*"/> <bean class="com.nchu.mybatis.interceptor.HelloInterceptor"></bean> </mvc:interceptor> </mvc:interceptors>
三、源码分析
- 分别在preHandle,postHandle,afterCompletion方法内部打上断点进行调试
- 启动服务器,客户端发送请求
- 进程首先停在preHandle内部断点,查看执行过的DispatcherServlet.class的doDispatcher方法
4.进入applyPreHandle方法
/** * Apply preHandle methods of registered interceptors. * @return {@code true} if the execution chain should proceed with the * next interceptor or the handler itself. Else, DispatcherServlet assumes * that this interceptor has already dealt with the response itself. */ 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; }
5.可以看到如果preHandle如果返回false,applyPreHandle方法也将返回false,DispatcherServlet.class的doDispatcher方法就会结束,将不会执行目标方法。