Java返回结构案例怎么统一

wen java案例 33

本文目录导读:

Java返回结构案例怎么统一

  1. 核心设计思路
  2. 完整代码实现
  3. 使用示例
  4. 高级进阶(可选增强)
  5. 最佳实践总结
  6. 扩展:如果是微服务或RPC调用

在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 的枚举值,这个方案在公司项目中经过大量验证,非常稳定和好用。

抱歉,评论功能暂时关闭!