文章目录
大家实现的java web项目返回给前端的结果类,结构基本相同,但又各有不同。通过学习,发现以下几点关注点:
- 错误代码枚举类真的有必要那么繁杂吗?
- 错误代码实用还是文字信息实用?
- 返回数据统一定义为Object,直观吗?便于类型检查吗?
- 返回数据为Map类型时,怎样使用才方便?
- 高频使用的分页查询列表的满足记录总数,实际记录数为什么不能固定在返回数据中?
对应解决:
- 错误代码没有文字信息直观(对于程序员同样),基本代码仅四类足够日常使用(正常、用户输入错误,系统错误、其他错误)。善于利用标准定义的web状态码枚举类(
org.springframework.http.HttpStatus
) - 使用泛型绑定返回数据data类型,利于编码规范化。
- 泛型绑定为Map时,使用链式编程方式,灵活添加不同Map元素
- 为返回数据data,定义count(计数器),total(满足查询条件的记录总数)
- 自动属性success,使前端使用时不必要判断状态码分类
package com.muyi.common.core.domain;
import com.muyi.common.enums.StatusCode;
import io.swagger.annotations.ApiModel;
import org.springframework.http.HttpStatus;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* 通用处理结果
* <pre>
* 1 默认成功状态,msg=""
* 2 data为空时,可使用实例链式编程put(String,Object)添加Map集合
* </pre>
*
* @author MuYi
* @version 1.0
* @date 2022/4/2 13:43
**/
@ApiModel(value = "类Result", description = "通用处理结果")
public class Result<T> implements Serializable {
private static final int OK_CODE_VALUE = HttpStatus.OK.value();
private static final int FIRST_ERR_CODE_VALUE = HttpStatus.BAD_REQUEST.value();
/**
* 是否成功、只读
*/
private boolean success;
/**
* 状态码
* <pre>
* 以HttpStatus为主架构,原有定义不得乱用。
* 正常返回代码为200,即HttpStatus.OK.value()
*
* 用户自定义错误代码需大于1000
* </pre>
*
* @see org.springframework.http.HttpStatus
*/
private int code = HttpStatus.OK.value();
/**
* 当data为null时为0;为Map、list、Array时,获取其长度;其他类型为1
*/
private int count = 0;
/**
* 信息
*/
private String msg;
/**
* 结果数据
*/
private T data;
/**
* 满足查询条件的记录总数
*/
private long total = 0;
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
this.success = code >= OK_CODE_VALUE && code < FIRST_ERR_CODE_VALUE;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
count = obtainDataCount(data);
}
/**
* 根据code判断是否成功
* <pre>
* code大于等于200 小于400
* </pre>
*
* @return 是否
* @see #error(String)
*/
public boolean isSuccess() {
return this.success;
}
/**
* 根据code判断是否成功
* <pre>
* code大于等于200 小于400
* </pre>
*
* @return 是否
* @see #error(String)
*/
public boolean getSuccess() {
return this.success;
}
public int getCount() {
return count;
}
/**
* 构造
*
* @param code 状态码
* @param data 结果数据
* @param msg 信息。为空且处理成功时,前台不显示
*/
private Result(Integer code, T data, String msg) {
init(code, data, msg);
}
/**
* 构造
*
* @param code 状态码
* @param data 结果数据
* @param msg 信息。为空且处理成功时,前台不显示
*/
private Result(StatusCode code, T data, String msg) {
init(code.getValue(), data, msg);
}
/**
* 构造
*
* @param code 状态码
* @param data 结果数据
* @param msg 信息。为空且处理成功时,前台不显示
*/
private Result(HttpStatus code, T data, String msg) {
init(code.value(), data, msg);
}
private void init(Integer code, T data, String msg) {
setCode(code);
setMsg(msg);
setData(data);
}
/**
* 初始化成功/失败新实例
*
* @param code 代码200、300系列一般为成功;400、500系列为失败
* @param data 处理结果
* @param msg 信息。为空且且处理成功时,前台可不显示
* @return 新实例
*/
public static <T> Result<T> build(Integer code, T data, String msg) {
if (!isSuccessCode(code)) code = OK_CODE_VALUE;
return new Result<T>(code, data, msg);
}
/**
* 初始化成功/失败新实例
*
* @param code 代码
* @param data 处理结果
* @param msg 信息。为空且处理成功时,前台不显示
* @return 新实例
*/
public static <T> Result<T> build(StatusCode code, T data, String msg) {
return build(code.getValue(), data, msg);
}
/**
* 初始化成功/失败新实例
*
* @param code 代码200、300系列一般为成功;400、500系列为失败
* @param data 处理结果
* @param msg 信息。为空且且处理成功时,前台可不显示
* @return 新实例
*/
public static <T> Result<T> build(HttpStatus code, T data, String msg) {
return build(code.value(), data, msg);
}
/**
* 初始化成功新实例
* <pre>
* Result.<Map<String, Object>>success(),可随后使用链式编程.put添加Map数据
* </pre>
*
* @param msg 信息。为空且处理成功时,前台不显示
* @return 新实例
*/
public static <T> Result<T> success(String msg) {
return build(OK_CODE_VALUE, null, msg);
}
/**
* 初始化成功新实例
* <pre>
* Result.<Map<String, Object>>success(),可随后使用链式编程.put添加Map数据
* </pre>
*
* @return 新实例
*/
public static <T> Result<T> success() {
return build(OK_CODE_VALUE, null, "");
}
/**
* 初始化成功新实例
*
* @param data 处理结果
* @param msg 信息。为空且处理成功时,前台不显示
* @return 新实例
*/
public static <T> Result<T> success(T data, String msg) {
return build(StatusCode.OK.getValue(), data, msg);
}
/**
* 初始化成功新实例
*
* @param data 处理结果
* @return 新实例
*/
public static <T> Result<T> success(T data) {
return build(StatusCode.OK.getValue(), data, "");
}
/**
* 初始化失败新实例
*
* @param code 代码非200、300系列时自动设置为400 BAD_REQUEST
* @param data 处理结果
* @param msg 信息。为空且处理成功时,前台不显示
* @return 新实例
*/
public static <T> Result<T> error(Integer code, T data, String msg) {
if (!isSuccessCode(code)) code = FIRST_ERR_CODE_VALUE;
return new Result<T>(code, data, msg);
}
/**
* 初始化失败新实例
*
* @param code 代码为非200、300系列
* @param msg 信息。为空且处理成功时,前台不显示
* @return 新实例
*/
public static <T> Result<T> error(HttpStatus code, String msg) {
return build(code, null, msg);
}
/**
* 初始化失败新实例
*
* @param code 代码为非OK
* @param msg 信息。为空且处理成功时,前台不显示
* @return 新实例
*/
public static <T> Result<T> error(StatusCode code, String msg) {
return build(code, null, msg);
}
/**
* 初始化失败新实例
* <pre>code=StatusCode.SYSTEM_ERR</pre>
*
* @param msg 信息。为空且处理成功时,前台不显示
* @return 新实例
*/
public static <T> Result<T> error(String msg) {
return build(StatusCode.SYSTEM_ERR, null, msg);
}
/**
* 初始化失败新实例
* <pre>msg由代码定义获得</pre>
*
* @param code 代码应为非OK
* @return 新实例
*/
public static <T> Result<T> error(StatusCode code) {
return build(code, null, code.getDesc());
}
/**
* 初始化失败新实例
* <pre>msg由代码定义获得</pre>
*
* @param code 代码应为非200、300系列
* @return 新实例
*/
public static <T> Result<T> error(HttpStatus code) {
return build(code, null, code.getReasonPhrase());
}
/**
* 判断状态是否为成功代码
* <pre>
* code大于等于200 小于400
* </pre>
*
* @param code 状态码
* @return 是否
*/
public static boolean isSuccessCode(Integer code) {
if (code == null) return false;
return code >= OK_CODE_VALUE && code < FIRST_ERR_CODE_VALUE;
}
/**
* 如果data为Collection、Map计算data长度。否则返回0或1
* <pre>
* data为null返回0,
* </pre>
*
* @param data 输入
* @return 长度
*/
public static int obtainDataCount(Object data) {
if (data == null) return 0;
if (data instanceof Map) return ((Map<?,?>) data).size();
else if (data instanceof Collection) return ((Collection<?>) data).size();
else return 1;
}
/**
* 向data添加键值对
* <pre>
* 如果本实例的data不为空且不是Map<String,Object>直接返回本实例,添加无效
* </pre>
*
* @param key 键名 为空直接返回本实例,否则,存在则覆盖,不存在新建
* @param value 值
* @return 本实例
*/
public Result<T> put(String key, Object value) {
if (this.data == null) this.data = (T) new HashMap<String, Object>();
((Map<String, Object>) this.data).put(key, value);
count = obtainDataCount(data);
return this;
}
/**
* 向data添加键值对
* <pre>
* 如果本实例的data不为空且不是Map<String,Object>直接返回本实例,添加无效
* </pre>
*
* @param map 值
* @return 本实例
*/
public Result<T> put(Map<String, Object> map) {
if (this.data == null) this.data = (T) new HashMap<String, Object>();
((Map<String, Object>) this.data).putAll(map);
count = obtainDataCount(data);
return this;
}
}
自定义代码枚举
package com.muyi.common.enums;
import io.swagger.annotations.ApiModel;
import java.util.ArrayList;
import java.util.List;
/**
* 枚举:处理返回状态码
* <pre>
* 以HttpStatus为主架构,原有定义不得乱用。
* 正常返回代码为200,即HttpStatus.OK.value()
*
* 用户自定义错误代码需大于1000
* </pre>
*
* @author MuYi
* @version 1.0
* @date 2022/4/2 13:58
* @see org.springframework.http.HttpStatus
**/
@ApiModel(value = "接口StatusCode", description = "枚举:")
public enum StatusCode {
/**
* 处理成功
*/
OK(200, "处理成功"),
/**
* 用户输入或请求错误
*/
REQUEST_ERR(400, "用户输入或请求错误"),
/**
* 系统异常
*/
SYSTEM_ERR(500, "系统异常"),
/**
* 未知异常
*/
OTHER_ERR(1000, "未知异常");
private final Integer value;
private final String desc;
StatusCode(Integer value, String desc) {
this.desc = desc;
this.value = value;
}
/**
* 获得所有中文描述
*
* @return 中文描述字符串数组
*/
public static String[] getAllDesc() {
List<String> result = new ArrayList<>();
for (ExchangeScopeType item : ExchangeScopeType.values()) {
result.add(item.getDesc());
}
return result.toArray(new String[0]);
}
public Integer getValue() {
return this.value;
}
public String getDesc() {
return this.desc;
}
/**
* 将数值或枚举名转换为枚举值
* <pre>
* 输入无效返回OTHER_ERR
* </pre>
*
* @param valueOrName 枚举对应的数值value(Integer类型)或枚举项名称name(String类型)
* @return 枚举值或或OTHER_ERR。
*/
public static StatusCode parse(Object valueOrName) {
if (valueOrName == null) return OTHER_ERR;
if (valueOrName instanceof Integer) {
for (StatusCode item : StatusCode.values()) {
if (item.getValue() == valueOrName) return item;
}
} else if (valueOrName instanceof String) {
for (StatusCode item : StatusCode.values()) {
if (item.name().equals(valueOrName)) return item;
}
}
return OTHER_ERR;
}
public boolean isError() {
return this != OK;
}
}
调用片段
@GetMapping("/list")
@ModelViewExceptionProcess
public Result<List<SysConfig>> list(SysConfig config) {
PageUtils.startPage();
Result<List<SysConfig>> result = configService.selectByCondition(config);
PageUtils.setTotal(result);
return result;
}
@Override
public Result<Boolean> configKeyIsUnique(String configKey, Long id) {
if (StringUtils.isBlank(configKey))
return Result.build(StatusCode.REQUEST_ERR,false,"输入的参数键名称为空字符串");
Long existingId = baseMapper.selectIdByKey(configKey);
return Result.success(existingId == null || existingId.equals(id));
}
SysUser user=new SysUser();
Result<Map<String, Object>> result = Result.<Map<String, Object>>success()
.put("key1", 1)
.put("key2", 2)
.put("key3","111")
.put("user",user);