跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

Spring 拦截器与统一响应异常处理实战

Spring 拦截器用于统一请求校验,避免重复逻辑;通过 @ControllerAdvice 结合 ResponseBodyAdvice 实现数据格式统一封装,解决 String 类型序列化问题;配合 @ExceptionHandler 捕获全局异常并返回标准 Result 对象。三者协同确保接口安全、规范且易维护。

Eee_123发布于 2026/3/28更新于 2026/6/916 浏览
Spring 拦截器与统一响应异常处理实战

一、拦截器基础

在开发中,我们常遇到需要强制登录校验的场景。如果直接在每个 Controller 方法里写 Session 判断,不仅代码冗余,一旦逻辑变更,所有接口都得改,前端也得跟着调整。有没有更优雅的方式?答案是:拦截器。

拦截器是 Spring 提供的非侵入式组件,能在请求抵达目标逻辑前或后自动执行通用处理(如鉴权、日志)。它就像业务流程中的关卡,无需修改业务代码即可控制请求流向。

文章配图

没有拦截器时,请求直接进 Controller;有了拦截器,流程变为:请求 → 拦截器前置 → Controller → Service → 拦截器后置 → 完成 → 响应。

1.1 核心生命周期

实现 HandlerInterceptor 接口并重写三个关键方法:

@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    
    // 目标方法执行前,返回 true 放行,false 中断
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("LoginInterceptor 目标方法执行前执行..");
        return true;
    }

    // Controller 执行后,视图渲染前
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("LoginInterceptor 目标方法执行后执行");
    }

    // 整个请求完成后,无论是否异常
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("LoginInterceptor 视图渲染完毕后执行,最后执行");
    }
}
方法名执行时机返回值 / 核心行为
preHandleController 执行前返回 true 继续,false 终止
postHandleController 执行后无返回值,仅做逻辑处理
afterCompletion响应返回后无返回值,清理资源或记录日志

1.2 注册配置

定义好拦截器后,需通过 WebMvcConfigurer 进行注册。这里要注意路径匹配规则,避免误伤静态资源。

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**") // 拦截所有路径
                .excludePathPatterns("/user/login", "/html/**", "/css/**", "/js/**"); // 排除登录页和静态资源
    }
}
路径匹配说明
  • /*:一级路径,如 /user 匹配,但 /user/login 不匹配。
  • /**:任意级路径,匹配所有子路径。
  • /book/*:/book 下的一级路径。
  • /book/**:/book 下的所有子路径。

1.3 实战:登录校验

结合 Session 实现具体的登录拦截逻辑。注意,这里只需关注 preHandle,因为后续步骤通常不需要阻断。

@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
        UserInfo userInfo = (UserInfo) session.getAttribute("SESSION_USER_KEY");
        
        if (userInfo != null) {
            log.info("登录成功");
            return true; // 放行
        }
        
        // 未登录,设置状态码并拦截
        response.setStatus(401);
        return false;
    }
}

二、统一数据返回格式

除了拦截,后端还常需要统一返回给前端的 JSON 结构(例如统一的 Result<T> 对象)。手动在每个 Controller 返回时封装很繁琐,Spring Boot 提供了 @ControllerAdvice + ResponseBodyAdvice 组合拳。

2.1 快速上手

添加注解并实现接口,重点处理 String 类型的序列化问题。

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice<Object> {
    
    @Autowired
    private ObjectMapper objectMapper;

    // 判断是否处理该方法的返回值
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    // 写入响应体之前调用
    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        // 如果已经是 Result 类型,直接返回,避免重复封装
        if (body instanceof Result<?>) {
            return body;
        }
        
        // String 类型需要特殊处理,否则会被当作普通字符串而非 JSON
        if (body instanceof String) {
            return objectMapper.writeValueAsString(Result.success(body));
        }
        
        // 其他类型统一包装
        return Result.success(body);
    }
}

注意: 当返回类型为 String 时,必须手动序列化,否则前端收到的可能是一个包裹了引号的字符串,而不是 JSON 对象。

三、统一异常处理

业务逻辑难免出错,与其让浏览器显示堆栈信息,不如统一捕获异常并返回友好的错误提示。使用 @ControllerAdvice 配合 @ExceptionHandler 即可。

@ControllerAdvice
@ResponseBody
public class ErrorAdvice {
    
    // 捕获所有 Exception
    @ExceptionHandler(Exception.class)
    public Object handleException(Exception e) {
        return Result.fail(e.getMessage());
    }

    // 针对特定异常自定义处理
    @ExceptionHandler(NullPointerException.class)
    public Object handleNPE(NullPointerException e) {
        return Result.fail("发生空指针异常:" + e.getMessage());
    }
}

3.1 执行顺序关键点

理解这三者的执行顺序对调试至关重要:

  1. 请求进入:先经过拦截器的 preHandle。
  2. 业务执行:Controller 方法运行。若抛出异常,直接进入异常处理阶段;若正常,返回数据。
  3. 异常捕获:@ExceptionHandler 优先于 ResponseBodyAdvice 捕获异常。如果 Controller 内部已 try-catch 处理,则不会触发全局异常处理器。
  4. 数据封装:无论是正常返回的数据,还是异常处理器返回的 Result 对象,都会进入 ResponseBodyAdvice.beforeBodyWrite。因此,我们在 beforeBodyWrite 中要判断是否已是 Result 类型,防止二次封装。

这样一套组合下来,既保证了接口的安全性,又确保了前后端交互格式的规范性。

目录

  1. 一、拦截器基础
  2. 1.1 核心生命周期
  3. 1.2 注册配置
  4. 路径匹配说明
  5. 1.3 实战:登录校验
  6. 二、统一数据返回格式
  7. 2.1 快速上手
  8. 三、统一异常处理
  9. 3.1 执行顺序关键点
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • AI 编程工具 Claude Code 实战
  • Python 入门实战:从零编写你的第一个网络爬虫
  • 无线联邦学习:保护隐私的无线网络 AI 协同进化
  • 单链表核心操作全实现与指针思维精讲
  • C++ STL set 与 map 底层封装原理详解
  • Linux 基础命令大全
  • 前端 IndexedDB 实战:使用 Dexie.js 实现数据持久化
  • Python 基础考试题库与解析
  • 宇树机器人核心技术架构解析
  • Agent AI 探索多模态交互前沿领域综述(一)
  • C++ 观察者设计模式核心原理与代码实现
  • AI 智能写作工具:自动生成万字长篇小说实践
  • 基于小米 9 的天马 G 前端掌机搭建指南
  • 算法题精讲:双指针法解决移动零与复写零
  • C++ 模拟实现二叉搜索树
  • Llama-2-7B 在昇腾 NPU 上的性能测评与部署方案
  • 人工智能、机器学习与深度学习的本质区别
  • C++ 从零实现 TCP Socket 网络通信工具
  • RAG(检索增强生成) 核心概念与架构解析
  • Git 分支管理基础与策略

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online