1 拦截器
1.1 简介
Spring MVC
的拦截器 Interceptor
类似于 Servlet
中的过滤器 Filter
,用于对处理器进行预处理和后处理.
1.2 实现原理
拦截器 Interceptor
的拦截功能是基于 Java
的动态代理来实现的.
1.3 应用场景
日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等.
权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面.
性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录).
通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现.
OpenSessionInView:如Hibernate,在进入处理器打开Session,在完成后关闭Session。
拦截器的本质也是AOP(面向切面编程), 也就是说符合横切关注点的所有功能都可以放入拦截器实现.
2 Spring MVC 提供的拦截器接口和类
Spring MVC 提供了一个拦截器接口 HandlerInterceptor
和一个拦截器适配器抽象类 HandlerInterceptorAdapter
.
2.1 HandlerInterceptor
接口
package org.springframework.web.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface HandlerInterceptor {
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;
void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;
}
在 HandlerInterceptor
接口中,定义了 3 个方法,分别为 preHandle()
、 postHandle()
和 afterCompletion()
,自定义拦截器需要实现这个接口并且要全部实现这三个方法.
preHandle(HttpServletRequest request, HttpServletResponse response, Object handle)
方法,该方法在请求处理之前进行调用。SpringMVC 中的 Interceptor 是链式调用的,在一个应用中或者说是在一个请求中可以同时存在多个 Interceptor 。每个 Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是 Interceptor 中的 preHandle 方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求做一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值 Boolean 类型的,当它返回为 false 时,表示请求结束,后续的 Interceptor 和 Controller 都不会再执行;当返回值为 true 时,就会继续调用下一个 Interceptor 的 preHandle 方法,如果已经是最后一个 Interceptor 的时候,就会是调用当前请求的 Controller 中的方法。postHandle(HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView)
方法,通过 preHandle 方法的解释咱们知道这个方法包括后面要说到的 afterCompletion 方法都只能在当前所属的 Interceptor 的 preHandle 方法的返回值为 true 的时候,才能被调用。postHandle 方法在当前请求进行处理之后,也就是在 Controller 中的方法调用之后执行,但是它会在 DispatcherServlet 进行视图返回渲染之前被调用,所以咱们可以在这个方法中对 Controller 处理之后的 ModelAn