目录
拦截器概念
SpringMVC拦截器(Interceptor)是一种用于动态拦截请求处理流程的机制。它允许开发者在请求到达控制器(Controller)之前或响应返回给客户端之后,对请求和响应进行预处理和后处理。拦截器是AOP(面向切面编程)思想在Spring MVC中的具体实现之一。
作用
拦截器主要用于在请求处理流程中的特定点执行自定义逻辑,其作用包括但不限于:
- 权限验证:检查用户是否拥有访问某个资源的权限。
- 日志记录:记录请求和响应的详细信息,便于问题追踪。
- 请求预处理:在请求到达控制器之前对请求数据进行修改或补充。
- 响应后处理:在响应返回给客户端之前对响应数据进行修改或添加额外的头信息。
拦截器和过滤器的区别
归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
拦截内容不同:Filter对所有访问进行增强,Interceptor仅对SpringMVC的访问进行增强
入门拦截器
在controller包下新建Interceptor包,在里面编写一个类,实现HandlerInterceptor接口,重写里面的三个方法。
import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Spring MVC拦截器,用于在请求处理的不同阶段执行特定操作。 * 本拦截器通过实现HandlerInterceptor接口,提供了请求前处理、请求后处理以及请求完成后的回调方法。 * 使用@Component注解声明为Spring管理的组件,会自动被Spring容器检测并注册为拦截器。 */ @Component public class ProjectInterceptor implements HandlerInterceptor { /** * 在请求处理之前执行(Controller方法调用之前) * @param request HTTP请求对象 * @param response HTTP响应对象 * @param handler 被调用的处理器对象 * @return boolean 返回true表示继续流程,返回false则中断流程 * @throws Exception 可能抛出的异常 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("perHandle..."); return true; } /** * 在整个请求处理完成后执行(视图渲染结束后) * 主要用于资源清理、统计信息收集等收尾工作 * @param request HTTP请求对象 * @param response HTTP响应对象 * @param handler 被调用的处理器对象 * @param ex 处理过程中抛出的异常(如果有) * @throws Exception 可能抛出的异常 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion..."); } /** * 在请求处理之后,视图渲染之前执行(Controller方法调用之后) * @param request HTTP请求对象 * @param response HTTP响应对象 * @param handler 被调用的处理器对象 * @param modelAndView 模型和视图对象,可用于修改模型数据或视图(可为null) * @throws Exception 可能抛出的异常 */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle"); } }
在配置包下创建类,继承WebMvcConfigurationSupport,重写addResourceHandlers
和addInterceptors:
import com.cc.controller.interception.ProjectInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; /** * Spring MVC 配置类,用于自定义Web配置 * 继承WebMvcConfigurationSupport类可覆盖默认的MVC配置 * 注意:在Spring Boot项目中,更推荐实现WebMvcConfigurer接口替代继承此类 */ @Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { @Autowired private ProjectInterceptor projectInterceptor; //注入拦截器 /** * 配置静态资源处理 * 将/pages/**路径的请求映射到类路径下的/pages目录 * @param registry 资源处理器注册器,用于管理静态资源路径映射 */ @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { //过滤访问静态资源 // 注册projectInterceptor拦截器,并设置拦截路径 registry.addResourceHandler("/pages/**").addResourceLocations("/pages"); } /** * 注册自定义拦截器并配置拦截规则 * @param registry 拦截器注册器,用于管理请求拦截规则 */ @Override protected void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(projectInterceptor).addPathPatterns("/users","/users/*"); } }
接下来尝试发送请求:
说明拦截器可以在方法的前和后增强方法。
再次发送请求
并没有被拦截,原因是:
添加拦截路径即可:
简化写法
前面新建了SpringMVC配置类,继承的是WebMvcConfigurationSupport,该部分可以直接写在SpringMVC配置类中,实现WebMvcConfigurer接口,重写addInterceptor方法。
@Configuration
@ComponentScan({"com.cc.controller"}) //不加载SpringMvcSupport
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {
@Autowired
private ProjectInterceptor projectInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(projectInterceptor).addPathPatterns("/users","/users/*");
}
}
拦截器的执行流程
多拦截器
当配置多个拦截器时,会形成拦截器链。
直接复制前面写的拦截器,修改,并对它进行配置:
重新发送请求,就可以观察到拦截器的执行顺序:
由此可得拦截器的执行顺序:
- 拦截器的运行顺序参照拦截器的添加顺序为准
- 执行了controller后执行的顺序相反
- 当拦截器出现对原始数据的拦截,后面的拦截器均会终止运行
- 当拦截器运行中断,仅运行配置在前面的拦截器的afterCompletion操作