首先,我们应该知道为什么要统一返回值格式。
如果不统一返回格式,你和前端开发人员联调接口时,她们就会很懵逼。
由于我们没有给他一个统一的格式,前端人员不知道如何处理返回值。
比如小张喜欢对结果进行封装,他使用了Result对象,小王也喜欢对结果进行包装,但是他却使用的是Response对象,当出现这种情况时我相信前端人员一定会抓狂的。
前端:“这返回数据啥意思???”(懵B中。。。)
所以我们项目中是需要定义一个统一的标准返回格式的。
一个标准的返回格式至少包含3部分(也可以是四部分):
- status/code 状态值:由后端统一定义各种返回结果的状态码,200?400?还是500?
- message 描述:本次接口调用的结果描述,是success还是fail?
- data 数据:本次返回的数据。
-
timestamp:记录接口调用时间。
例如,Postman返回数据:
{
"code": "200",
"message": "success",
"data": {
"id": 2,
"payNo": "paystring",
"orderNo": "abcasdfg",
"userId": 1,
"amount": 19.99,
"deleted": 0,
"createTime": "2024-04-10 19:31:18",
"updateTime": "2024-04-10 19:31:18"
},
"timestamp": 1712748873228
}
这样看上去是不是就层次分明,一眼就看出来数据有没有问题。
那么,我们应该怎么做呢?
时间格式问题 我们可以在相应的类的属性上使用@JsonFormat注解
/**
* 创建时间
*/
@Column(name = "create_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/**
* 更新时间
*/
@Column(name = "update_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
1.定义枚举类(ReturnCodeEnum)
基于HTTP请求返回的状态码
定义枚举状态码三步走:举值-构造-遍历(个人感觉很少改动,直接复制也能用。。)
package com.stay2003.cloud.resp;
import lombok.Getter;
import java.util.Arrays;
@Getter
public enum ReturnCodeEnum {
//举值-构造-遍历
//1.举值
/**操作失败**/
RC999("999","操作XXX失败"),
/**操作成功**/
RC200("200","success"),
/**服务降级**/
RC201("201","服务开启降级保护,请稍后再试!"),
/**热点参数限流**/
RC202("202","热点参数限流,请稍后再试!"),
/**系统规则不满足**/
RC203("203","系统规则不满足要求,请稍后再试!"),
/**授权规则不通过**/
RC204("204","授权规则不通过,请稍后再试!"),
/**access_denied**/
RC403("403","无访问权限,请联系管理员授予权限"),
/**access_denied**/
RC401("401","匿名用户访问无权限资源时的异常"),
RC404("404","404页面找不到的异常"),
/**服务异常**/
RC500("500","系统异常,请稍后重试"),
RC375("375","数学运算异常,请稍后重试"),
INVALID_TOKEN("2001","访问令牌不合法"),
ACCESS_DENIED("2003","没有权限访问该资源"),
CLIENT_AUTHENTICATION_FAILED("1001","客户端认证失败"),
USERNAME_OR_PASSWORD_ERROR("1002","用户名或密码错误"),
BUSINESS_ERROR("1004","业务逻辑异常"),
UNSUPPORTED_GRANT_TYPE("1003", "不支持的认证模式");
//2.构造
/**自定义状态码**/
private final String code;
/**自定义描述**/
private final String message;
ReturnCodeEnum(String code, String message){
this.code = code;
this.message = message;
}
//遍历枚举
public static ReturnCodeEnum getReturnCodeEnum(String code)
{
for (ReturnCodeEnum element : ReturnCodeEnum.values()) {
if(element.getCode().equalsIgnoreCase(code))
{
return element;
}
}
return null;
}
}
2.定义返回对象类(ResultData<T>)
package com.stay2003.cloud.resp;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class ResultData<T> {
private String code;
private String message;
private T data;
private Long timestamp;
public ResultData(){
this.timestamp = System.currentTimeMillis();
}
public static <T> ResultData<T> success(T data) {
ResultData<T> resultData = new ResultData<>();
resultData.setCode(ReturnCodeEnum.RC200.getCode());
resultData.setMessage(ReturnCodeEnum.RC200.getMessage());
resultData.setData(data);
return resultData;
}
public static <T> ResultData<T> fail(String code, String message) {
ResultData<T> resultData = new ResultData<>();
resultData.setCode(code);
resultData.setMessage(message);
return resultData;
}
}
这样就能调用ResultData.success(返回值)或者ResultData.fail(返回值)了
至于@Accessors注解,该字段共有三个属性,分别是 fluent,chain,prefix
fluent 属性
不写默认为false,当该值为 true 时,对应字段的 getter 方法前面就没有 get,setter 方法就不会有 set。
chain 属性
不写默认为false,当该值为 true 时,对应字段的 setter 方法调用后,会返回当前对象。
prefix 属性
该属性是一个字符串数组,当该数组有值时,表示忽略字段中对应的前缀,生成对应的 getter 和 setter 方法。
3.修改Controller
既然统一定义好了返回值类型,那我们一定不能忘了修改控制类
如图,是修改前后的对比:右边是修改前,左边是修改后
是不是返回值更加统一了,看上去非常的舒适。
至此,基本的统一返回值任务就完成了。