目录
Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。
所有 HandlerMapping 的实现都支持 handler 拦截器,当你想对某些请求应用特定的功能时,这些拦截器是非常有用的—例如,检查一个 principal。拦截器必须实现 org.springframework.web.servlet 包中的 HandlerInterceptor,它有三个方法,应该可以提供足够的灵活性来进行各种预处理和后处理:
preHandle(..): 在实际 handler 运行之前
postHandle(..): handler 运行后
afterCompletion(..): 在整个请求完成后
preHandle(..) 方法返回一个boolean值。你可以使用这个方法来中断或继续执行链的处理。当这个方法返回 true 时,handler 执行链继续进行。当它返回 false 时, DispatcherServlet 认为拦截器本身已经处理了请求(例如,渲染了一个适当的视图),并且不继续执行其他拦截器和执行链中的实际 handler。
postHandle 方法在 @ResponseBody 和 ResponseEntity 方法中用处不大,因为这些方法的响应是在 HandlerAdapter 中和 postHandle 之前写入和提交的。这意味着对响应进行任何修改都太晚了,比如添加一个额外的 header。
在Java配置中,你可以注册拦截器来应用于传入的请求,如下例所示:
- @Configuration
- @EnableWebMvc
- public class WebConfig implements WebMvcConfigurer {
-
- @Override
- public void addInterceptors(InterceptorRegistry registry) {
- registry.addInterceptor(new LocaleChangeInterceptor());
- registry.addInterceptor(new ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
- }
- }
-
下面的例子显示了如何在XML中实现同样的配置:
- <mvc:interceptors>
- <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
- <mvc:interceptor>
- <mvc:mapping path="/**"/>
- <mvc:exclude-mapping path="/admin/**"/>
- <bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
- </mvc:interceptor>
- </mvc:interceptors>
映射的拦截器并不适合作为安全层,因为它有可能与注解的控制器路径匹配不匹配,它也可以透明地匹配尾部斜线和路径扩展,以及其他路径匹配选项。这些选项中的许多已经被废弃,但错配的可能性仍然存在。一般来说,我们推荐使用Spring Security,它包括一个专门的 MvcRequestMatcher,与Spring MVC的路径匹配保持一致,同时还有一个安全防火墙(security firewall),可以阻止URL路径中许多不需要的字符。
- package com.doker.interceptor;
-
- public class MyInterceptor implements HandlerInterceptor {
-
- /** * 预处理,controller 方法执行前 * 应用:用于身份认证、身份授权 * return true 放行,执行下一个拦截器,如果没有,执行 controller 中的方法 * return false 不放行,即不向下执行 */
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
-
- System.out.println("preHandle");
- return true;
- }
- /** * 后处理方法,controller 方法执行后,方法跳转 success.jsp 执行之前 * 应用:从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图 */
- public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
-
- System.out.println("postHandle");
- }
- /** * success.jsp 页面执行后,该方法会执行 * 应用:统一异常处理,统一日志处理 */
- public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
-
- System.out.println("afterCompletion");
- }
- }
- <mvc:interceptors>
- <mvc:interceptor>
- <!--拦截的资源URI-->
- <mvc:mapping path="/**"/>
- <!--不拦截哪些-->
- <!--<mvc:exclude-mapping path="" />-->
- <bean id="handlerInterceptorDemo1"
- class="com.doker.interceptor.MyInterceptor">
- </bean>
- </mvc:interceptor>
-
- <mvc:interceptor>
- <mvc:mapping path="/**"/>
- <bean id="handlerInterceptorDemo2"
- class="com.doker.interceptor.MyInterceptor1">
- </bean>
- </mvc:interceptor>
- </mvc:interceptors>
所以,多个拦截器是按照配置的顺序决定的:handlerInterceptorDemo1—>handlerInterceptorDemo2。