告别乱七八糟的返回格式:手把手带你封装生产级 Result 实体

统一响应规范:业务与协议解耦

不要直接使用 HTTP 状态码(如 404, 500)表达业务逻辑。HTTP 状态码仅表示网络/协议层状态,而业务层需要独立的语义(如:余额不足、权限不足)。

一个标准响应体应包含以下三个核心字段:

字段 类型 说明 实战经验
code Integer 业务状态码 约定 0 为成功,非 0 为失败。避免使用复杂的 HTTP 状态码,降低心智负担。
message String 友好提示 给用户看的文案。严禁直接透传 SQL 异常或代码堆栈。
data T (泛型) 响应数据 核心载荷,前端获取数据的主要来源。

注意,某些接口实现中可能包含"消息类型"(如:info、error、warn、success),前端根据消息类型渲染对应的消息提示类型,这属于"展示展示层语义下沉到服务层"的反模式案例,不要这样实现!

代码落地

根据上面的描述,落地后的代码如下:

java 复制代码
public class Result<T> implements Serializable {

    private static final long serialVersionUID = 1L;

    private int code;

    /**
     * 响应消息
     */
    private String message;

    /**
     * 响应数据
     */
    private T data;
}

通用 code 定义

由于不同的 code 代表了不同的请求结果,为了方便统一管理,一些基础的 code 需要被定义出来,定义接口 ResultCode

java 复制代码
public interface ResultCode {

    /**
     * 获取状态码
     *
     * @return 状态码
     */
    int getCode();

    /**
     * 获取状态信息
     *
     * @return 状态信息
     */
    String getMessage();
}

实现:

java 复制代码
@Getter
@AllArgsConstructor
public enum CommonResultCode implements ResultCode {

    /**
     * 成功
     */
    SUCCESS(0, "success"),

    /**
     * 业务处理失败
     */
    BUSINESS_ERROR(1, "业务处理失败"),

    /**
     * 系统未知错误
     */
    SYSTEM_ERROR(500, "系统繁忙,请稍后重试"),

    /**
     * 参数错误
     */
    PARAM_ERROR(400, "参数错误"),

    /**
     * 接口不存在
     */
    NOT_FOUND(404, "接口不存在"),

    /**
     * 请求方法不支持
     */
    METHOD_NOT_ALLOWED(405, "请求方法不支持");

    private final int code;

    private final String message;
}

快速构建返回结果的能力

上述设计只是设定了"标准"的返回结构,如果通过new形式创建对象并设定对应的值,代码将变得非常啰嗦,下面是通过静态方法快速构建返回结果的封装:

java 复制代码
@Data
public class Result<T> implements Serializable {

   // .....

    /**
     * 成功响应(无数据)
     * <p>
     * 适用于不需要返回数据的成功场景(如删除成功、更新成功等)
     * </p>
     *
     * @return 成功响应结果(泛型为 Void)
     */
    public static Result<Void> success() {
        return success(CommonResultCode.SUCCESS.getCode(), null);
    }

    /**
     * 成功响应(默认成功码)
     *
     * @param data 响应数据
     * @param <T>  数据类型
     * @return 成功响应结果
     */
    public static <T> Result<T> success(T data) {
        return success(CommonResultCode.SUCCESS.getCode(), data);
    }

    /**
     * 成功响应(自定义状态码)
     * <p>
     * 适用于部分非 0 但仍代表业务成功的场景,如:需要前端做特殊处理的成功状态
     * </p>
     *
     * @param code 业务状态码
     * @param data 响应数据
     * @param <T>  数据类型
     * @return 成功响应结果
     */
    public static <T> Result<T> success(int code, T data) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setMessage(CommonResultCode.SUCCESS.getMessage());
        result.setData(data);
        return result;
    }

    /**
     * 失败响应(使用默认失败状态码)
     *
     * @param message 错误信息
     * @param <T>     数据类型
     * @return 失败响应结果
     */
    public static <T> Result<T> fail(String message) {
        return fail(CommonResultCode.BUSINESS_ERROR.getCode(), message, null);
    }

    /**
     * 失败响应(带数据,使用默认失败状态码)
     *
     * @param message 错误信息
     * @param data    响应数据
     * @param <T>     数据类型
     * @return 失败响应结果
     */
    public static <T> Result<T> fail(String message, T data) {
        return fail(CommonResultCode.BUSINESS_ERROR.getCode(), message, data);
    }

    /**
     * 失败响应(自定义状态码)
     *
     * @param code    错误码
     * @param message 错误信息
     * @param <T>     数据类型
     * @return 失败响应结果
     */
    public static <T> Result<T> fail(int code, String message) {
        return fail(code, message, null);
    }

    /**
     * 失败响应(带数据,自定义状态码)
     *
     * @param code    错误码
     * @param message 错误信息
     * @param data    响应数据
     * @param <T>     数据类型
     * @return 失败响应结果
     */
    public static <T> Result<T> fail(int code, String message, T data) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setMessage(message);
        result.setData(data);
        return result;
    }

    /**
     * 根据 ResultCode 构建结果
     *
     * @param resultCode 结果码
     * @param <T>        数据类型
     * @return Result
     */
    public static <T> Result<T> of(ResultCode resultCode) {
        return of(resultCode, null);
    }

    /**
     * 根据 ResultCode 和数据构建结果
     *
     * @param resultCode 结果码
     * @param data       数据
     * @param <T>        数据类型
     * @return Result
     */
    public static <T> Result<T> of(ResultCode resultCode, T data) {
        Result<T> result = new Result<>();
        result.setCode(resultCode.getCode());
        result.setMessage(resultCode.getMessage());
        result.setData(data);
        return result;
    }


   // .....
}

增加状态检查

如果 Result 类用于微服务之间的调用(Feign),我们可以扩展状态检查来判断响应是否成功或者失败:

shell 复制代码
@Data
public class Result<T> implements Serializable {
    // .....

     /**
     * 判断是否成功
     *
     * @return true 成功,false 失败
     */
    @JsonIgnore // 避免序列化到前端,保持报文精简,前端可直接判断 code
    public boolean isSuccess() {
        return this.code == CommonResultCode.SUCCESS.getCode();
    }

    /**
     * 判断是否失败
     *
     * @return true 失败,false 成功
     */
    @JsonIgnore
    public boolean isFail() {
        return !isSuccess();
    }
}

最终实战(完整类)

java 复制代码
@Data
public class Result<T> implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 成功状态码
     */
    public static final int SUCCESS_CODE = 0;

    /**
     * 默认失败状态码
     */
    public static final int FAIL_CODE = 1;

    /**
     * 业务状态码 (0 表示成功,非 0 表示失败)
     */
    private int code;

    /**
     * 响应消息
     */
    private String message;

    /**
     * 响应数据
     */
    private T data;

    // =================================================================================================================
    // 静态工程方法,快速构建返回实体
    // =================================================================================================================

    /**
     * 成功响应(无数据)
     * <p>
     * 适用于不需要返回数据的成功场景(如删除成功、更新成功等)
     * </p>
     *
     * @return 成功响应结果(泛型为 Void)
     */
    public static Result<Void> success() {
        return success(CommonResultCode.SUCCESS.getCode(), null);
    }

    /**
     * 成功响应(默认成功码)
     *
     * @param data 响应数据
     * @param <T>  数据类型
     * @return 成功响应结果
     */
    public static <T> Result<T> success(T data) {
        return success(CommonResultCode.SUCCESS.getCode(), data);
    }

    /**
     * 成功响应(自定义状态码)
     * <p>
     * 适用于部分非 0 但仍代表业务成功的场景,如:需要前端做特殊处理的成功状态
     * </p>
     *
     * @param code 业务状态码
     * @param data 响应数据
     * @param <T>  数据类型
     * @return 成功响应结果
     */
    public static <T> Result<T> success(int code, T data) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setMessage(CommonResultCode.SUCCESS.getMessage());
        result.setData(data);
        return result;
    }

    /**
     * 失败响应(使用默认失败状态码)
     *
     * @param message 错误信息
     * @param <T>     数据类型
     * @return 失败响应结果
     */
    public static <T> Result<T> fail(String message) {
        return fail(CommonResultCode.BUSINESS_ERROR.getCode(), message, null);
    }

    /**
     * 失败响应(带数据,使用默认失败状态码)
     *
     * @param message 错误信息
     * @param data    响应数据
     * @param <T>     数据类型
     * @return 失败响应结果
     */
    public static <T> Result<T> fail(String message, T data) {
        return fail(CommonResultCode.BUSINESS_ERROR.getCode(), message, data);
    }

    /**
     * 失败响应(自定义状态码)
     *
     * @param code    错误码
     * @param message 错误信息
     * @param <T>     数据类型
     * @return 失败响应结果
     */
    public static <T> Result<T> fail(int code, String message) {
        return fail(code, message, null);
    }

    /**
     * 失败响应(带数据,自定义状态码)
     *
     * @param code    错误码
     * @param message 错误信息
     * @param data    响应数据
     * @param <T>     数据类型
     * @return 失败响应结果
     */
    public static <T> Result<T> fail(int code, String message, T data) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setMessage(message);
        result.setData(data);
        return result;
    }

    /**
     * 根据 ResultCode 构建结果
     *
     * @param resultCode 结果码
     * @param <T>        数据类型
     * @return Result
     */
    public static <T> Result<T> of(ResultCode resultCode) {
        return of(resultCode, null);
    }

    /**
     * 根据 ResultCode 和数据构建结果
     *
     * @param resultCode 结果码
     * @param data       数据
     * @param <T>        数据类型
     * @return Result
     */
    public static <T> Result<T> of(ResultCode resultCode, T data) {
        Result<T> result = new Result<>();
        result.setCode(resultCode.getCode());
        result.setMessage(resultCode.getMessage());
        result.setData(data);
        return result;
    }

    // =================================================================================================================
    // 状态检查
    // =================================================================================================================

    /**
     * 判断是否成功
     *
     * @return true 成功,false 失败
     */
    @JsonIgnore // 避免序列化到前端,保持报文精简,前端可直接判断 code
    public boolean isSuccess() {
        return this.code == CommonResultCode.SUCCESS.getCode();
    }

    /**
     * 判断是否失败
     *
     * @return true 失败,false 成功
     */
    @JsonIgnore
    public boolean isFail() {
        return !isSuccess();
    }
}
相关推荐
tonydf2 小时前
在Blazor Server中集成docx-preview.js实现高保真Word预览
后端
W***r262 小时前
SpringBoot整合easy-es
spring boot·后端·elasticsearch
5***84642 小时前
Spring Boot的项目结构
java·spring boot·后端
SimonKing2 小时前
基于Netty的TCP协议的Socket客户端
java·后端·程序员
骑着bug的coder2 小时前
第11讲:主从复制与读写分离架构
后端·mysql
love_summer2 小时前
代码中的“留白”艺术:Python空语句pass的设计哲学与最佳实践
后端
6***83052 小时前
SpringBoot教程(三十二) SpringBoot集成Skywalking链路跟踪
spring boot·后端·skywalking
有追求的开发者2 小时前
2025 年终总结:一个 Python DevOps 的成长之路
后端