企业级java api中应通过分层错误码枚举统一异常返回,结合全局异常处理器将bizexception等转换为标准响应体,确保90%异常路径仅需一次throw,实现类型安全、可维护、易扩展的错误处理体系。

在企业级 Java API 中,用自定义错误码统一异常返回,核心是把“异常类型 + 业务语义”映射为结构化的响应体(如 {"code": "USER_NOT_FOUND", "message": "用户不存在", "timestamp": ...}),而不是直接抛原始异常或拼接字符串。关键不在“怎么 throw”,而在“怎么捕获、识别、转换并标准化输出”。
定义分层错误码枚举
避免散落的字符串常量,用枚举集中管理,天然支持类型安全和 IDE 提示:
public enum BizErrorCode {
USER_NOT_FOUND("USER_NOT_FOUND", "用户不存在", HttpStatus.NOT_FOUND),
INVALID_PARAM("INVALID_PARAM", "参数校验失败", HttpStatus.BAD_REQUEST),
SYSTEM_ERROR("SYSTEM_ERROR", "系统繁忙,请稍后再试", HttpStatus.INTERNAL_SERVER_ERROR);
private final String code;
private final String message;
private final HttpStatus httpStatus;
BizErrorCode(String code, String message, HttpStatus httpStatus) {
this.code = code;
this.message = message;
this.httpStatus = httpStatus;
}
// 提供便捷构建方法
public ApiResponse<object> toResponse(Object data) {
return ApiResponse.fail(this, data);
}
}</object>
每个枚举项明确绑定:唯一错误码字符串、面向前端/日志的默认提示、对应的 HTTP 状态码。必要时可扩展字段(如 errorLevel、i18nKey)。
封装统一响应体与全局异常处理器
定义标准响应结构,并用 @ControllerAdvice 拦截所有控制器异常:
public class ApiResponse<t> {
private String code;
private String message;
private long timestamp = System.currentTimeMillis();
private T data;
public static <t> ApiResponse<t> fail(BizErrorCode errorCode, T data) {
ApiResponse<t> resp = new ApiResponse();
resp.code = errorCode.code();
resp.message = errorCode.message();
resp.data = data;
return resp;
}
}
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BizException.class)
@ResponseBody
public ResponseEntity<apiresponse>> handleBizException(BizException e) {
// 直接使用异常携带的错误码枚举
ApiResponse<object> response = e.getErrorCode().toResponse(e.getExtraData());
return ResponseEntity.status(e.getErrorCode().httpStatus()).body(response);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public ResponseEntity<apiresponse>> handleValidationException(MethodArgumentNotValidException e) {
String errorMsg = e.getBindingResult().getFieldErrors().stream()
.map(FieldError::getDefaultMessage).findFirst().orElse("参数校验失败");
ApiResponse<object> response = BizErrorCode.INVALID_PARAM.toResponse(errorMsg);
return ResponseEntity.badRequest().body(response);
}
// 兜底:未预期异常 → 统一转为 SYSTEM_ERROR
@ExceptionHandler(Exception.class)
@ResponseBody
public ResponseEntity<apiresponse>> handleUnexpected(Exception e) {
log.error("Uncaught exception", e);
ApiResponse<object> response = BizErrorCode.SYSTEM_ERROR.toResponse(null);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
}
}</object></apiresponse></object></apiresponse></object></apiresponse></t></t></t></t>
重点:业务异常(如用户不存在)应主动抛出自定义异常(BizException),而非直接 throw new RuntimeException("xxx");全局处理器只做“翻译”,不掺杂业务逻辑。
业务代码中精准抛出带上下文的异常
在 Service 层根据业务判断,选择合适错误码并附带必要信息(如 ID、字段名),方便前端定位或日志追踪:
- 不要写:
throw new BizException(BizErrorCode.USER_NOT_FOUND);(丢失关键上下文) - 推荐写:
throw new BizException(BizErrorCode.USER_NOT_FOUND, "userId=" + userId);
BizException 构造器中保存错误码枚举和额外数据(String / Map),全局处理器通过 e.getErrorCode() 和 e.getExtraData() 获取,注入到响应体或日志中。
配合 Spring Validation 和 AOP 做前置拦截
对 DTO 参数校验失败、重复提交、权限不足等通用场景,可进一步抽象:
- 用
@Valid+@NotBlank等注解,由上面的MethodArgumentNotValidException处理器统一转错 - 用 AOP 拦截特定注解(如
@RequireLogin),校验不通过时直接 throwBizException(BizErrorCode.UNAUTHORIZED) - 数据库唯一约束冲突,可捕获
DuplicateKeyException并转为BizErrorCode.DUPLICATE_RESOURCE
目标是:**90% 的异常路径,业务代码里只出现一次 throw new BizException(...),其余均由框架自动识别转换**。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











