Spring MVC 拦截器的使用
拦截器简介
Spring MVC 中的拦截器(Interceptor)类似于 Servler 中的过滤器(Filter)。用于对处理器进行预处理和后处理。常用于日志记录、权限管理、性能监控、通用行为等。
拦截器的实现
Spring MVC 中的拦截器需要我们手动实现和配置。拦截器可以通过以下两种方式定义
- 实现
HandleInterceptor
接口,或者继承该接口的实现类如HandleInterceptorAdapter
来定义一个拦截器; - 实现
WebRequestInterceptor
接口来定义一个拦截器;
HandleInterceptor 接口
我们主要讲解下实现 HandleInterceptor
接口来创建拦截器。HandleInterceptor
接口定义了三个方法,分别为 preHandle()
, postHandle()
, afterCompletion()
,我们需要重写这三个方法,从而来实现我们定义拦截器的目的。
preHandle(HttpServletRequest request, HttpServletResponse response, Object handle)
:该方法在请求处理前调用。Spring MVC 中的拦截器是链式调用的,一个请求可以被多个拦截器拦截,但是 Interceptor 会根据被声明的次序依次被调用执行,而不会同时去拦截。而且所有 Interceptor 中的preHandle
函数都会最先被调用,所以这个方法中可以进行一些前置初始化操作或者是对当前请求的预处理,或者设置一些判断来决定该请求是否执行下去。该方法的返回值是布尔值,当它返回true
时,之后的 Interceptor 和 controller 都不会执行下去了;当它返回false
时,就会继续调用下一个 Interceptor 的preHandle
方法或者处理当前请求的Controller
。postHandle(HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView)
:该方法只有在perHandle
方法返回值为true
时,在 Controller 执行完当前请求后才会执行。咋一看好像和之后要介绍的 afterCompletion 方法没有不同,但是这个方法会在DispatcherServlet
进行视图渲染之前被调用,所以咱们可以在这个方法中对 Controller 处理之后的ModelAndView
对象进行操作。afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)
:该方法在整个请求结束后,也就是DispatcherServlet
渲染了对应视图之后执行,这个方法的主要作用是用于进行资源清理的工作。
假设我们现在定义了两个拦截器,xml 配置文件中配置顺序如下内容如下:
<!-- 拦截器1 -->
<mvc:interceptor>
<!--配置拦截器的作用路径-->
<mvc:mapping path="/**"/>
<bean class="com.jojo.test.interceptor.Intercptor1"/>
</mvc:interceptor>
<!--拦截器2-->
<mvc:interceptor>
<mvc:mapping path="/hello"/>
<bean class="com.jojo.test.interceptor.Interceptor2"/>
</mvc:interceptor>
那么这两个拦截器中的处理方法和请求的处理方法的顺序如下图:
实际应用举例
实现开发中,我们会要求一些页面需要登录后才能访问。未登录状态是无法得到访问权限的。这一小功能我们可以直接通过安全框架,类似 Spring Security 或者 shiro 来实现,不过我们现在利用 Spring MVC 这一功能来实现一下:
public class LoginInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
User user = (User) httpServletRequest.getSession().getAttribute("user");
if (user == null) {
// 用户未登录,重定向到登录页
httpServletResponse.sendRedirect("/login");
return false;
}
return true;
}
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
}
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
我们还需要在 spring-mvc
中配置拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/static/**"/>
<mvc:exclude-mapping path="/login"/>
<bean class="com.jojo.test.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
相关配置说明:
mvc:interceptor
:定义一个拦截器mvc:mapping
:定义需要被拦截的路径mvc:exclude-mapping
:定义需要排除拦截的请求路径bean class
:指定拦截器对象