Spring MVC也可以使用拦截器对请求进行拦截处理,用户 可以自定义拦截器来实现特定的功能,自定义的拦截器必 须实现HandlerInterceptor接口。
preHandle():这个方法在业务处理器处理请求之前被调用,在该 方法中对用户请求 request 进行处理。如果程序员决定该拦截器对 请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去 进行处理,则返回true;如果程序员决定不需要再调用其他的组件 去处理请求,则返回false。
postHandle():这个方法在业务处理器处理完请求后,但是DispatcherServlet 向客户端返回响应前被调用,在该方法中对 用户请求request进行处理。
afterCompletion():这个方法在 DispatcherServlet 完全处理完请 求后被调用,可以在该方法中进行一些资源清理的操作。
自定义拦截器大白话:
1、首先新建一个拦截器类
就是 implements HandlerInterceptor
实现接口类就行。
public class FirstIntercept implements HandlerInterceptor{ /** * 该方法在目标方法之前被调用. * 若返回值为 true, 则继续调用后续的拦截器和目标方法. * 若返回值为 false, 则不会再调用后续的拦截器和目标方法. * * 可以考虑做权限. 日志, 事务等. */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // TODO Auto-generated method stub System.out.println("[FirstIntercept] preHandle"); return true; } /** * 调用目标方法之后, 但渲染视图之前. * 可以对请求域中的属性或视图做出修改. */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // TODO Auto-generated method stub System.out.println("[FirstIntercept] postHandle"); } /** * 渲染视图之后被调用. 释放资源 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // TODO Auto-generated method stub System.out.println("[FirstIntercept] afterCompletion"); } }
2、编辑转发配置文件
<mvc:interceptors> <!-- 配置自定义拦截器 --> <bean class="com.test.springmvc.test.FirstIntercept"></bean> <!-- 配置 带参数的 自定义拦截器,SencondIntercept和FirstIntercept 代码一样的只是改了名字,这里就不写了 --> <mvc:interceptor> <!-- 拦截器只作用在 /emps 请求域中,一定要记得“/”,否则没有效果 --> <mvc:mapping path="/emps"/> <bean class="com.test.springmvc.test.SecondIntercept"></bean> </mvc:interceptor> </mvc:interceptors>
3、拦截器执行顺序:
(1)如果只配置了FirstIntercept
,且里面的 preHandle方法返回true,且没有 配置 带参数的 自定义拦截器(即SencondIntercept
)
那么url请求,控制台输出结果:
[FirstIntercept] preHandle [FirstIntercept] postHandle [FirstIntercept] afterCompletion
(2)如果上面的FirstIntercept
里面的preHandle方法返回false。且没有 配置 带参数的 自定义拦截器(即SencondIntercept
)
那么url请求,控制台输出结果:
[FirstIntercept] preHandle
(3)如果配置了FirstIntercept
和SecondIntercept
,且两者里面的preHandle方法都返回true,且请求域是emps
控制台输出结果:
[FirstIntercept] preHandle [SecondIntercept] preHandle [SecondIntercept] postHandle [FirstIntercept] postHandle [SecondIntercept] afterCompletion [FirstIntercept] afterCompletion
(4)如果配置了FirstIntercept
和SecondIntercept
请求域是emps
而FirstIntercept
的preHandle方法返回true,SecondIntercept
的preHandle方法返回false,控制台输出结果:
[FirstIntercept] preHandle [SecondIntercept] preHandle [FirstIntercept] afterCompletion
备注:下图中的虚线不是执行过程,实线才是真正的执行过程。
特别提醒:当初在改项目代码时,因为代码是热更新的,但是测试结果来看,热更新后,Intercept 的测试输出 有bug ,因为多输出了 一遍 下面的:
[FirstIntercept] preHandle
[FirstIntercept] postHandle
[FirstIntercept] afterCompletion
所以,测试代码时最好还是重启一下服务器,这样就不会出现意想不到的bug。
4、拦截器顺序与异常
当自定义拦截器的preHandle方法返回true,遇到springmvc出现异常时:
1、DefaultHandlerExceptionResolver 系统默认自带异常处理器。
里面实现了很多异常 ,如:handleHttpRequestMethodNotSupported
我测试控制器规定了请求方法只能是post,当我get请求时,出异常了。
@RequestMapping(value="/testDefaultHandlerExceptionResolver",method=RequestMethod.POST) public String testDefaultHandlerExceptionResolver(){ System.out.println("testDefaultHandlerExceptionResolver..."); return "success"; }
控制台打印的是:(看出来,自定义拦截器根本没有调用到)
org.springframework.web.servlet.PageNotFound handleHttpRequestMethodNotSupported WARNING: Request method 'GET' not supported
网页显示:
HTTP Status 405 - Request method 'GET' not supported type Status report message Request method 'GET' not supported description The specified HTTP method is not allowed for the requested resource. Apache Tomcat/8.0.36
2、其他 遇到下面的异常捕获器:
@ResponseStatus (优先级第一)
@ExceptionHandler,@ControllerAdvice(优先级第二)
SimpleMappingExceptionResolver (优先级第三)
控制台结果显示:(自定义拦截器调用了方法一和方法三)
[FirstIntercept] preHandle [FirstIntercept] afterCompletion