本文目录导读:

在Java开发中,统一返回结构(Response Structure) 是为了让前端、API调用者或服务间通信能有一致的契约,方便解析和错误处理,下面给你一个标准、通用的统一返回结构案例。
核心设计思路
一个通用的返回结构通常包含以下几个核心字段:
| 字段名 | 类型 | 含义 | 是否必须 |
|---|---|---|---|
code |
int | 业务状态码(非HTTP状态码) | 是 |
message |
String | 提示信息 | 是 |
data |
T (泛型) | 返回的实际数据 | 否 |
success |
boolean | 是否成功(可选) | 建议有 |
完整代码实现
1 定义响应状态码枚举
public enum ResponseCode {
SUCCESS(200, "操作成功"),
FAIL(500, "操作失败"),
// 参数校验
PARAM_ERROR(400, "参数错误"),
PARAM_MISSING(400, "缺少必要参数"),
// 权限
UNAUTHORIZED(401, "未登录或 token 过期"),
FORBIDDEN(403, "没有操作权限"),
// 业务
NOT_FOUND(404, "资源不存在"),
BIZ_ERROR(500, "业务逻辑错误"),
// 服务
SERVER_ERROR(500, "服务器内部错误");
private final int code;
private final String message;
ResponseCode(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() { return code; }
public String getMessage() { return message; }
}
2 定义统一返回类(泛型)
import java.io.Serializable;
public class ApiResult<T> implements Serializable {
private static final long serialVersionUID = 1L;
private int code;
private String message;
private T data;
private boolean success;
// 私有构造器,禁止直接new
private ApiResult() {}
// ========== 静态工厂方法 ==========
// 成功(无数据)
public static <T> ApiResult<T> success() {
return success(null);
}
// 成功(带数据)
public static <T> ApiResult<T> success(T data) {
ApiResult<T> result = new ApiResult<>();
result.code = ResponseCode.SUCCESS.getCode();
result.message = ResponseCode.SUCCESS.getMessage();
result.data = data;
result.success = true;
return result;
}
// 成功(自定义消息)
public static <T> ApiResult<T> success(String message, T data) {
ApiResult<T> result = new ApiResult<>();
result.code = ResponseCode.SUCCESS.getCode();
result.message = message;
result.data = data;
result.success = true;
return result;
}
// 失败(默认)
public static <T> ApiResult<T> error() {
return error(ResponseCode.FAIL);
}
// 失败(使用状态码枚举)
public static <T> ApiResult<T> error(ResponseCode responseCode) {
ApiResult<T> result = new ApiResult<>();
result.code = responseCode.getCode();
result.message = responseCode.getMessage();
result.data = null;
result.success = false;
return result;
}
// 失败(自定义消息)
public static <T> ApiResult<T> error(int code, String message) {
ApiResult<T> result = new ApiResult<>();
result.code = code;
result.message = message;
result.data = null;
result.success = false;
return result;
}
// 失败(自定义消息 + 数据)
public static <T> ApiResult<T> error(String message, T data) {
ApiResult<T> result = new ApiResult<>();
result.code = ResponseCode.FAIL.getCode();
result.message = message;
result.data = data;
result.success = false;
return result;
}
// ========== getter/setter ==========
public int getCode() { return code; }
public String getMessage() { return message; }
public T getData() { return data; }
public boolean isSuccess() { return success; }
@Override
public String toString() {
return "ApiResult{" +
"code=" + code +
", message='" + message + '\'' +
", data=" + data +
", success=" + success +
'}';
}
}
使用示例
1 在Controller中使用
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/{id}")
public ApiResult<User> getUser(@PathVariable Long id) {
// 查不到
if (id == null || id <= 0) {
return ApiResult.error(ResponseCode.PARAM_ERROR);
}
User user = userService.getUserById(id);
if (user == null) {
return ApiResult.error(ResponseCode.NOT_FOUND);
}
return ApiResult.success(user);
}
@PostMapping
public ApiResult<Long> createUser(@RequestBody @Valid UserCreateReq req) {
// 参数校验由 @Valid 处理
Long userId = userService.createUser(req);
return ApiResult.success("创建成功", userId);
}
@PutMapping("/{id}")
public ApiResult<Void> updateUser(@PathVariable Long id, @RequestBody UserUpdateReq req) {
try {
userService.updateUser(id, req);
return ApiResult.success();
} catch (BizException e) {
// 业务异常:捕获并返回通用错误
return ApiResult.error(e.getCode(), e.getMessage());
}
}
}
2 前端期望的JSON示例
成功:
{
"code": 200,
"message": "操作成功",
"data": {
"userId": 123,
"name": "张三",
"email": "zhangsan@example.com"
},
"success": true
}
失败(参数错误):
{
"code": 400,
"message": "缺少必要参数",
"data": null,
"success": false
}
失败(业务异常):
{
"code": 500,
"message": "用户余额不足",
"data": {
"currentBalance": 10.5,
"requiredBalance": 100.0
},
"success": false
}
高级进阶(可选增强)
1 结合全局异常处理器
使用 @ControllerAdvice 自动捕获异常并统一返回:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ApiResult<Void> handleValidationExceptions(MethodArgumentNotValidException ex) {
String errorMessage = ex.getBindingResult().getAllErrors().stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.joining(", "));
return ApiResult.error(ResponseCode.PARAM_ERROR.getCode(), errorMessage);
}
@ExceptionHandler(BizException.class)
public ApiResult<Void> handleBizException(BizException ex) {
return ApiResult.error(ex.getCode(), ex.getMessage());
}
@ExceptionHandler(Exception.class)
public ApiResult<Void> handleAllExceptions(Exception ex) {
// 生产环境建议记日志,返回模糊信息
log.error("系统异常", ex);
return ApiResult.error(ResponseCode.SERVER_ERROR);
}
}
2 加入时间戳或请求ID(可选)
public class ApiResult<T> implements Serializable {
private int code;
private String message;
private T data;
private boolean success;
private long timestamp; // 时间戳
private String requestId; // 请求ID(可用于追踪)
// 在生产方法中自动填充
public static <T> ApiResult<T> success(T data) {
ApiResult<T> result = new ApiResult<>();
result.code = ResponseCode.SUCCESS.getCode();
result.message = ResponseCode.SUCCESS.getMessage();
result.data = data;
result.success = true;
result.timestamp = System.currentTimeMillis();
result.requestId = TraceIdUtil.getTraceId(); // 从MDC或请求头获取
return result;
}
}
最佳实践总结
| 实践点 | 说明 |
|---|---|
| 统一状态码 | 不要直接用HTTP状态码,定义自己的业务状态码枚举 |
| 泛型支持 | 使用 <T> 让 data 字段能接受任何类型 |
| 静态工厂方法 | 禁止外部直接 new,通过 success()、error() 创建 |
| 前后端协商 | 提前约定好字段名、类型、错误码范围 |
| 不透露敏感信息 | 生产环境错误消息不要暴露堆栈细节 |
| 日志记录 | 在 error() 或异常处理器中记录完整错误日志 |
| 序列化兼容 | 实现 Serializable 并定义 serialVersionUID |
扩展:如果是微服务或RPC调用
可以使用 统一响应对象 + 统一错误码枚举 + 全局异常处理 组合方案,保证所有微服务对外返回格式完全一致。
核心代码与上面完全一致,只需注意:
- RPC 调用时,
ApiResult需要实现Serializable - 不同服务的错误码范围需要规划好(50001-59999 为服务A,60000-69999 为服务B)
你可以直接复制上面的 ApiResult 类和 ResponseCode 枚举到你的项目中,并根据业务扩展 ResponseCode 的枚举值,这个方案在公司项目中经过大量验证,非常稳定和好用。