往期文章:
Spring 学习总结笔记【一、快速入门】
Spring 学习总结笔记【二、IoC-控制反转】
Spring 学习总结笔记【三、注解开发】
Spring 学习总结笔记【四、整合Junit】
Spring 学习总结笔记【五、配置数据源】
Spring 学习总结笔记【六、整合Mybatis】
Spring 学习总结笔记【七、AOP面向切面编程】
Spring 学习总结笔记【八、集成Web环境】
Spring 学习总结笔记【九、SpringMVC快速入门】
Spring 学习总结笔记【十、SpringMVC数据响应与请求】
一、拦截器概念
在系统中,经常需要在处理用户请求之前和之后执行一些行为,例如检测用户的权限,或者将请求的信息记录到日志中等等,所以需要一种机制,拦截用户的请求,在请求的前后添加处理逻辑。
Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(InterceptorChain)。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。
- 拦截器(Interceptor):是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行
- 作用:
① 在指定的方法调用前后执行预先设定的代码
② 阻止原始方法的执行
拦截器与过滤器区别:
- 归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
- 拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强
二、拦截器开发步骤
①创建拦截器类实现HandlerInterceptor接口
package com.tyt.controller.interceptor;
// 若基于注解开发,需要加 @Component 注解,否则不需要
@Component
public class ProjectInterceptor implements HandlerInterceptor {
/**
* 访问Controller某个方法之前执行
* @param request 可以在方法请求进来之前更改request中的属性值
* @param response
* @param handler 封装了当前处理方法的信息,可对其进行反射操作
* @return true 后续调用链是否执行; false 则中断后续执行
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle...");
// PreHandle方法若返回的false表示不放行,整个流程处于被拦截状态。
return true;
}
/**
* 视图被渲染之前(Controller方法调用之后)调用
* preHandle方法处理之后这个方法会被调用,如果控制器Controller出现了异常,则不会执行此方法
* @param request
* @param response 可以在方法执行后去更改response中的信息
* @param handler 封装了当前处理方法的信息
* @param modelAndView 封装了model和view,所以当请求结束后可以修改model中的数据或者新增model数据,也可以修改view的跳转
* @throws Exception9
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
}
/**
* 如果preHandle返回false则不会执行该方法
* 在视图渲染之后执行,相当于try catch finally 中finally,出现异常也一定会执行该方法
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
}
}
preHandle
:预处理回调方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;postHandle
:后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。afterCompletion
:整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中preHandle返回true的拦截器才会执行。
② 配置拦截器
- 基于XML配置
在Spring核心配置文件中配置拦截器
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 指定对哪些资源进行拦截操作 -->
<mvc:mapping path="/**"/>
<bean class="com.tyt.controller.interceptor"/>
</mvc:interceptor>
</mvc:interceptors>
- 基于注解开发
有两种方法
方法① :可定义一个类继承WebMvcConfigurationSupport
类并注册拦截器,之后SpringMvc核心配置类配置包扫描至该类所在包。
package com.tyt.config;
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Autowired
private ProjectInterceptor projectInterceptor;
@Override
protected void addInterceptors(InterceptorRegistry registry) {
// 添加拦截器并设定拦截的访问路径,路劲可以通过可变参数设置多个
registry.addInterceptor(projectInterceptor).addPathPatterns("/book", "/book/*");
}
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
// 添加对静态资源的访问
}
}
@ComponentScan({"com.tyt.controller", "com.tyt.config"})
@EnableWebMvc
public class SpringMvcConfig{
}
方法② :直接在SpringMVC核心配置类实现WebMvcConfigurer
接口并注册拦截器(此方法较方法①更加简化,当侵入式较强)
@ComponentScan({"com.tyt.controller"})
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {
@Autowired
private ProjectInterceptor projectInterceptor;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry){
// 添加对静态资源的访问
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 添加拦截器并设定拦截的访问路径,路劲可以通过可变参数设置多个
registry.addInterceptor(projectInterceptor).addPathPatterns("/book", "/book/*");
}
}
三、拦截器链
- 当配置多个拦截器时,形成拦截器链
- 拦截器链的运行顺序参照拦截器添加顺序为准
- 当拦截器中出现对原始处理的拦截,后面的拦截器均终止运行
- 当拦截器运行中断,仅运行配置在前面的拦截器的
afterCompletion
操作
假设现在有拦截器1、2、3,分别用pre1、post1、after1;pre2、post2、after2;pre3、post3、after3来描述各拦截器方法。
① 三个拦截器的preHandle均返回true
② 拦截器3的preHandle返回false
③ 拦截器2的preHandle返回false
④ 拦截器1的preHandle返回false
下期文章: