统一异常处理需用@RestControllerAdvice拦截+自定义BusinessException+泛型Result<T>响应体,code/message/data字段清晰,业务异常返回HTTP 200,日志记录requestId,Filter/Interceptor异常需单独处理。

Java 异常拦截统一输出标准 JSON 格式,关键不是“把异常转成 JSON”,而是建立一套分层明确、可扩展、不暴露内部细节的响应契约。核心在于用 @RestControllerAdvice 拦截 + 自定义异常类 + 统一响应体三者配合,让所有接口(无论成功或失败)返回结构一致的 JSON。
定义统一响应体 Result
所有接口返回类型应统一为泛型 Result<T>,字段精简且语义清晰:
- code:整型业务错误码(如 200 表示成功,40001 表示参数校验失败)
- message:面向前端/用户的提示文案,不带堆栈、不暴露敏感路径
- data:泛型数据体,成功时填充,失败时为 null
- timestamp(可选):便于排查时序问题
用 @JsonInclude(JsonInclude.Include.NON_NULL) 注解避免返回空 data 字段;搭配 Lombok 的 @Data 减少模板代码。
封装业务异常 BusinessException
禁止直接 throw new RuntimeException("xxx")。所有业务异常必须继承自自定义运行时异常:
立即学习“Java免费学习笔记(深入)”;
详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
- 含
code和message字段,构造时强制传入枚举类(如ErrorCode.PARAM_INVALID) - 可额外携带
requestId,用于日志链路追踪 - 只在 Service 或 Controller 层抛出,DTO 层不做校验逻辑
例如:throw new BusinessException(ErrorCode.USER_NOT_FOUND);
用 @RestControllerAdvice 集中拦截并格式化
写一个独立配置类,标注 @RestControllerAdvice(比 @ControllerAdvice + @ResponseBody 更简洁),按异常类型分层处理:
- 捕获
BusinessException:返回 HTTP 200 +Result.error(),保证前端始终能解析 JSON - 捕获
MethodArgumentNotValidException:提取@Valid校验失败信息,转为统一错误码(如 40001)和提示 - 捕获
Exception(兜底):记录 warn 日志(含 requestId)、返回通用错误码(如 50000),生产环境禁用堆栈输出
每个 @ExceptionHandler 方法返回 Result<?>,Spring Boot 会自动序列化为 JSON。
补充细节提升健壮性
光有 JSON 结构还不够,几个易忽略但关键的点:
- 日志必须打
warn级别,且包含requestId和异常简要信息,方便关联请求与错误 - HTTP 状态码不依赖业务错误码:业务异常统一用 200,系统级异常(如 NPE)可用 500,避免前端用状态码做业务判断
- Filter / Interceptor 中抛出的异常不会被
@RestControllerAdvice拦截,需单独处理或提前转为 Controller 可见异常 - 事务方法内若 catch 了异常又没 re-throw,会导致事务不回滚,务必确保异常上抛到 Web 层

















