现状:我们知道后端接口返回体可以是任意形式,可以是一个自定义对象,一个List对象,一个Map对象,也可以是一个null对象等。
如下代码案例:
@PostMapping("/test1")
public SysUser test1() {
return new SysUser();
}
@PostMapping("/test2")
public List<String> test2() {
List<String> list = Arrays.asList("1", "2", "3");
return list;
}
@PostMapping("/test3")
public Map<String, String> test3() {
Map<String, String> map = new HashMap<>(4);
map.put("name", "rufeng");
return map;
}
@PostMapping("/test4")
public Object test4() {
return null;
}
但如果一个系统一开始返回形式都是上述这样杂乱无章的,后续该系统的开发也都会是这样乱,就没有一个好的底子在那里来规范后续人员的开发,那么这个系统就是失败的,而且前端调用者处理返回结构体可能不知道是成功返回还是失败返回,会多写很多代码适配成功失败情况。那么怎样去解决这个问题呢,就需要一个统一返回结构体,不管是正常返回,还是异常返回,它的返回结构体形式都是一样。
第一步:需要自定义一个结构返回体类
结构返回体类可以包含如下成员变量:
int类型的错误码code
String类型的提示用语message
Object类型的数据对象data(Object类型可用泛型表示)
代码如下:
@Data
@ApiModel(value = "返回结构体")
public class ResultBody<T> {
@ApiModelProperty(value = "返回码")
private Integer code;
@ApiModelProperty(value = "提示消息")
private String message;
@ApiModelProperty(value = "数据结构体")
private T data;
public ResultBody() {
}
}
第二步:设置一个错误码枚举类ErrorCode
作用一:将所有返回提示写在一个文件中,方便管理。
作用二:提示信息包含中英文,可根据请求头语言自动切换,减少i18n国际化处理。
作用三:设置不同的错误码,可根据错误码分类知道是哪个子系统抛出的异常。
作用四:提示信息中可设置占位符,给用户更友好提示
错误码ErrorCode成员属性如下:
int类型的返回错误码code
String类型的中文提示message
String类型的英文提示enMessage
代码如下:
@Getter
public enum ErrorCode {
SUCCESS(200, "成功", "success"),
FAIL(-1, "失败", "fail"),
SYSTEM_ERROR_401(401, "请求访问:%s,认证失败,无法访问系统资源.", "Request to access: %s, authentication failed, unable to access system resources."),
SYSTEM_ERROR_404(404, "接口%s不存在.", "Interface %s Not Found."),
SYSTEM_ERROR_500(500, "接口%s内部错误,请与管理员联系.", "Interface %s internal error, please contact the administrator."),
/**
* WEB端提示,错误码1xxxx表示
*/
WEB_PARAMER_ERROR(10000, "参数%s错误.", "Parameter %s error.")
;
/**
* 错误码
*/
private Integer code;
/**
* 中文提示
*/
private String message;
/**
* 英文提示
*/
private String enMessage;
ErrorCode(Integer code, String message, String enMessage) {
this.code = code;
this.message = message;
this.enMessage = enMessage;
}
}
第三步:将ResultBody类与ErrorCode枚举类组合使用
ResultBody类与ErrorCode枚举类成员对应关系:
ErrorCode的错误码code对应ResultBody的返回码code
ErrorCode的中文提示message或英文提示enMessage对应ResultBody的提示信息message(此处ErrorCode中英文提示会根据设置的请求头语言自动切换)
实现如下:
@Data
@ApiModel(value = "返回结构体")
public class ResultBody<T> {
@ApiModelProperty(value = "返回码")
private Integer code;
@ApiModelProperty(value = "提示消息")
private String message;
@ApiModelProperty(value = "数据结构体")
private T data;
public ResultBody() {
}
/**
* 可认为成功返回的处理,数据体有返回
* @param errorCode
* @param data
* @author rufeng
* @date 2023/12/11 11:05
*/
public ResultBody(ErrorCode errorCode, T data) {
this.code = errorCode.getCode();
this.message = BaseConstant.LANG_ZH_CN.equals(ServletUtils.getLanguage()) ? errorCode.getMessage() : errorCode.getEnMessage();
this.data = data;
}
/**
* 根据错误码枚举对象为返回结构体成员赋值,若提示语存在占位符可直接赋值处理
* @param errorCode 枚举类对象
* @param ds 占位符的值
* @author rufeng
* @date 2023/12/11 11:12
*/
public ResultBody(ErrorCode errorCode, Object... ds) {
this.code = errorCode.getCode();
this.message = String.format(BaseConstant.LANG_ZH_CN.equals(ServletUtils.getLanguage()) ? errorCode.getMessage() : errorCode.getEnMessage(), ds);
}
}
此处的语言信息是根据请求头lanuage获取的,默认是中文提示
getRequest().getHeader(lanuage);
第四步:设置一个返回结构体工具类,封装返回结构体方便使用
返回结构体工具类是用于封装ResultBody并将ErrorCode
结合起来一起使用,那么返回有成功返回或失败返回,实现如下:
public class ResultBodyUtils<T> {
/**
* 成功返回结构报文
*
* @param data
* @param <T>
* @return
* @author rufeng
* @date 2023/12/11 11:30
*/
public static <T> ResultBody success(T data) {
return new ResultBody(ErrorCode.SUCCESS, data);
}
/**
* 成功返回,没有data结构报文
*
* @return
* @author rufeng
* @date 2023/12/11 11:35
*/
public static ResultBody success() {
return new ResultBody(ErrorCode.SUCCESS);
}
/**
* 失败返回,宽泛提示
*
* @return
* @author rufeng
* @date 2023/12/11 11:32
*/
public static ResultBody fail() {
return new ResultBody(ErrorCode.FAIL);
}
/**
* 失败返回,具体提示或占位符处理
*
* @param errorCode
* @param ds
* @return
* @author rufeng
* @date 2023/12/11 11:40
*/
public static ResultBody fail(ErrorCode errorCode, Object... ds) {
return new ResultBody(errorCode, ds);
}
}
第五步:实践并使用
案例一:成功返回
@PostMapping("/list")
public ResultBody<List<SysUser>> list(@RequestBody SysUser user) {
return ResultBodyUtils.success(userService.selectUserList(user));
}
案例二:失败返回并使用使用占位符处理(此处只是一个例子,更精简不会这样写)
@PostMapping("/del")
public ResultBody del(@RequestBody SysUser user) {
if (user.getUserId() < 1) {
return ResultBodyUtils.fail(ErrorCode.WEB_PARAMER_ERROR, "userId");
}
return userService.del(user) > 0 ? ResultBodyUtils.success() : ResultBodyUtils.fail();
}