统一响应规范:业务与协议解耦
不要直接使用 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();
}
}