Java自定义业务异常需继承RuntimeException,携带code、message、args字段,Controller层直接抛出不捕获,通过@ExceptionHandler统一转换为标准响应体,并分级日志、脱敏敏感信息、适配HTTP状态码。

Java 中自定义业务异常要在全局异常处理器中统一转换,核心是“定义规范、捕获精准、响应一致”。关键不在于拦截器或手动 try-catch,而在于让异常从抛出到返回全程可识别、可控制、可扩展。
定义清晰的业务异常基类
继承 RuntimeException,避免强制 throws,同时携带业务必需字段:
- 错误码(code):建议用字符串(如 "USER_NOT_FOUND")或整数(如 4001),便于前端映射提示文案
- 错误消息(message):支持占位符(如 "用户 {0} 不存在"),配合 MessageSource 实现多语言
- 可选上下文参数(args):用于动态填充消息,比如 userId、orderId
- 不建议再继承 Exception(受检异常),否则业务方法签名冗长,且与 Spring 全局处理机制不自然对齐
在 Controller 层直接抛出,不捕获不包装
业务逻辑中遇到规则违反,就直接 throw 自定义异常,无需 try-catch:
- ✅ 正确示例:if (user == null) { throw new BizException("USER_NOT_FOUND", "用户 {0} 不存在", userId); }
- ❌ 错误做法:用 try-catch 包裹 service 调用,再转成新异常——这破坏了调用栈,丢失原始位置信息
- 保持异常源头干净,把“怎么响应”交给统一处理器,而非每个方法自己决定
用 @RestControllerAdvice + @ExceptionHandler 统一转换
这是 Spring Boot 官方推荐方式,自动生效于所有 @RestController 方法:
立即学习“Java免费学习笔记(深入)”;
- 标注 @RestControllerAdvice 的类会被 Spring 扫描为全局异常处理器
- 用 @ExceptionHandler(BizException.class) 精准匹配你的业务异常类型
- 返回标准响应体(如 Result<T>),code 和 msg 直接取自异常实例:return Result.fail(e.getCode(), e.getMessage(), e.getArgs());
- 可同时处理多种异常:比如再加一个 @ExceptionHandler(MethodArgumentNotValidException.class) 处理参数校验失败,全部归一为相同结构
补充细节提升健壮性
真正落地时,几个容易忽略但影响体验的点:
- 日志记录要分级:业务异常用 warn 级别(非 error),避免刷屏;系统异常(如 NPE)才用 error
- 敏感信息脱敏:异常 message 中若含手机号、身份证等,需在处理器中过滤,不直接返回给前端
- HTTP 状态码适配:BizException 默认对应 400,但也可按 code 字段映射不同状态码(如 "TOKEN_EXPIRED" → 401)
- 避免在 handler 中抛出新异常:否则会进入默认错误页或 500,破坏统一性


















