SpringBoot 拦截器基于Spring MVC Interceptor,用于请求前置/后置处理、登录校验、权限控制、日志记录等,下面分基础实现、多拦截器、常见配置一步步讲解。
一、核心流程
- 自定义拦截器类,实现
HandlerInterceptor接口 - 创建Web 配置类,实现
WebMvcConfigurer注册拦截器 - 配置拦截路径、放行路径
- 测试验证
二、版本环境
SpringBoot 2.x / 3.x 通用写法(SpringBoot3 仅依赖包无变化)
1. 依赖(常规Web项目即可)
<!-- pom.xml --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>三、第一步:自定义拦截器
实现HandlerInterceptor,包含 3 个核心方法:
- preHandle:控制器执行之前执行,返回
true放行,false拦截 - postHandle:控制器执行后、视图渲染前执行
- afterCompletion:请求完全结束(视图渲染完毕)后执行,多用于资源释放
importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.web.servlet.HandlerInterceptor;importorg.springframework.web.servlet.ModelAndView;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;/** * 自定义登录拦截器 */publicclassLoginInterceptorimplementsHandlerInterceptor{privatestaticfinalLoggerlog=LoggerFactory.getLogger(LoginInterceptor.class);// 控制器执行前@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{log.info("【拦截器】请求进入 preHandle,地址:{}",request.getRequestURI());// 示例:登录校验(从session获取登录用户)Objectuser=request.getSession().getAttribute("loginUser");if(user==null){log.info("【拦截器】未登录,拦截请求");// 重定向到登录页 / 前后端分离则返回JSONresponse.sendRedirect("/login");returnfalse;// 拦截请求}returntrue;// 放行}// 控制器执行后,视图渲染前@OverridepublicvoidpostHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,ModelAndViewmodelAndView)throwsException{log.info("【拦截器】执行 postHandle");}// 整个请求完成后(最后执行)@OverridepublicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,Exceptionex)throwsException{log.info("【拦截器】请求结束 afterCompletion");}}四、第二步:注册拦截器(核心配置)
新建配置类,实现 WebMvcConfigurer,重写addInterceptors方法注册拦截器。
关键配置说明
addPathPatterns():要拦截的路径/**拦截所有请求/api/**拦截 api 下所有接口
excludePathPatterns():放行路径(登录、静态资源、验证码等)
importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.InterceptorRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;/** * Web 全局配置类,注册拦截器 */@ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){registry.addInterceptor(newLoginInterceptor())// 1. 拦截所有请求.addPathPatterns("/**")// 2. 放行路径:登录接口、静态资源、首页等.excludePathPatterns("/login").excludePathPatterns("/static/**").excludePathPatterns("/error");// 放行全局异常页}}注意:不要加 @EnableWebMvc,加了会覆盖 SpringBoot 默认 Web 配置,导致静态资源、日期格式化等失效。
五、第三步:编写测试接口/页面
1. 登录控制器(模拟登录)
importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjavax.servlet.http.HttpSession;@RestControllerpublicclassTestController{// 登录接口(放行)@GetMapping("/login")publicStringlogin(HttpSessionsession){// 模拟登录成功,存入sessionsession.setAttribute("loginUser","admin");return"登录成功";}// 需拦截的接口@GetMapping("/index")publicStringindex(){return"首页内容";}}六、测试效果
- 访问
http://localhost:8080/index- 未登录 → 被拦截,重定向到
/login
- 未登录 → 被拦截,重定向到
- 先访问
http://localhost:8080/login(登录) - 再次访问
/index→ 正常放行,控制台打印拦截器日志
七、进阶用法
1. 多个拦截器(执行顺序)
注册多个拦截器,先注册先执行(preHandle 顺序:注册顺序;afterCompletion 逆序)
@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){// 拦截器1 先执行registry.addInterceptor(newInterceptor1()).addPathPatterns("/**");// 拦截器2 后执行registry.addInterceptor(newInterceptor2()).addPathPatterns("/**");}2. 前后端分离场景(返回JSON而非重定向)
替换preHandle中未登录逻辑,返回 JSON 提示:
if(user==null){response.setContentType("application/json;charset=utf-8");response.getWriter().write("{\"code\":401,\"msg\":\"请先登录\"}");returnfalse;}3. 排除静态资源
SpringBoot 默认静态资源目录:/static、/public、/resources、/META-INF/resources
统一放行:
.excludePathPatterns("/static/**","/public/**")4. 拦截指定 Controller/接口
只拦截/api/user/**下接口:
.addPathPatterns("/api/user/**")八、常见问题
拦截器不生效
- 检查配置类是否加
@Configuration - 确认没写
@EnableWebMvc - 路径匹配是否正确(
/**和/*区别:/*只拦截一级路径)
- 检查配置类是否加
404 页面被拦截
- 手动放行
/error路径
- 手动放行
拦截器无法获取 @RequestBody 参数
- 原因:流只能读取一次,需配合请求体包装器解决。
补充:SpringBoot3 额外说明
SpringBoot3 基于 Spring6,API 完全兼容以上代码,仅部分包路径变化(javax.servlet→jakarta.servlet):
// SpringBoot3 导入包importjakarta.servlet.http.HttpServletRequest;importjakarta.servlet.http.HttpServletResponse;其余逻辑、注册方式完全不变。