全局异常规范落地关键在共识与流程:明确分层异常归属,强制统一响应结构,通过模板工程、CI检查、IDEA模板等机制嵌入开发流程,并配套Code Review、日志规范及异常码看板。

团队落地全局异常规范,关键不在技术实现,而在共识建立和流程嵌入。技术方案(如 @RestControllerAdvice)本身很成熟,难的是让所有人写业务时“下意识”按规范来,而不是上线后靠 Review 补救。
明确分层与异常归属
先统一什么是“该谁管的异常”,避免推诿或重复处理:
- 接口层(Controller)只负责 HTTP 相关异常:400 参数校验失败、401 Token 过期、404 接口不存在——这些由 Spring 自带的
ResponseEntityExceptionHandler或自定义拦截器捕获 - 业务层(Service)必须抛出业务异常:用
BusinessException及其子类(如OrderNotFoundException),禁止直接 throw new RuntimeException("订单没找到") - 数据层(DAO)异常不向上透传:MyBatis 抛出的
SQLSyntaxErrorException等应被封装为带明确业务语义的异常,比如“库存扣减失败”,而不是暴露数据库细节 - 系统级异常(NPE、OOM)全部由全局处理器兜底,日志必须记录完整堆栈 + 请求 ID + 关键参数,但响应体里只返回“500 服务器内部错误”
强制使用统一响应结构
所有接口返回类型必须是 Result(或你团队命名的等效类),不允许直接返回 POJO 或 String:
- 成功时:固定 code=200,message="操作成功",data 为实际内容
- 失败时:code 对应预定义枚举(如
ResultCode.ORDER_NOT_FOUND),message 是用户可读提示(如“订单不存在,请检查订单号”),绝不拼接运行时变量(如 "订单" + id + "不存在") - 新增错误码必须走评审:在共享文档中登记 code、message、触发场景、是否需告警,避免同义不同码(如“余额不足”出现 4001 和 4027 两个码)
把规范变成开发环境的一部分
靠自觉不如靠机制:
- 模板工程内置
GlobalExceptionHandler、BusinessException、Result和ResultCode枚举,新项目直接继承,不许自行重写 - CI 流水线加入静态检查:扫描所有
@PostMapping/@GetMapping方法,若返回类型不是Result或其泛型子类,构建失败 - IDEA Live Template 配置快捷代码段:输入
exb回车,自动补全throw new BusinessException(ResultCode.XXX); - Swagger 文档中每个接口的 200/400/500 响应体,必须引用
Result的 OpenAPI Schema,前端可据此自动生成错误处理逻辑
配套协作机制
技术规范需要协同规则支撑:
- Code Review 必查项:是否用了自定义业务异常?错误码是否已在枚举中定义?message 是否含敏感信息或动态拼接?
- 日志规范同步落地:每个
BusinessException构造时自动携带 traceId,全局处理器记录 ERROR 日志时必须包含请求路径、method、参数摘要(脱敏后)、异常码 - 建立异常码看板:实时展示各错误码近 24 小时调用量、Top3 触发接口、平均响应耗时,让高频异常自动浮出水面











