文章目录
1. 过去的方式(存在的问题)
- 之前统一封装返回值的时候,使用如下的格式:

- 如果数据直接用Object表示,那么在swagger中,就会变成这样:

接口文档无法解析存储在其中的数据。
2. 解决方案
为了正确返回数据,需要用泛型来声明这个data,而在真正返回时,再声明具体的类型。
2.1. 声明泛型

如上图所示,在类代码中使用【泛型T】来代替原来的【Object】
随后在使用时,具体声明它的类型

这样当swagger在解析这个Result类的时候,就能知道“T”的类型为Email类
那么在解析data这个属性时,便会认为data是Email类,就会按照Email对象的方式去解析

2.2. 注意细节

可以看到,在上面的返回值中使用了Result
而在下面的return代码中,返回的只用了Result<>
这里可以类比 Map<String,Object> map = new HashMap<>();
3. 统一的返回对象
3.1. ResultInformation.java:定义状态码和提示信息
- 在common包下创建ResultInformation.java

3.2. Result.java:统一的返回对象
- 在util包下创建Result.java,记得:在类代码和对应的data属性代码中加上泛型

- 针对controller的各种业务场景,声明五个不同的构造方法。此处讲解最复杂的构造方法:

- 这里的dataKey和dataVlue是从Controller中传入的,也就是手动传入,随后将这两个数据封装成map,赋给Result的data属性
- 这里的ResultInformation.SUCCESS是获取成功时候的状态码。换言之,如果传入的code不与成功的状态码相等,则说明是失败
- 此段代码的意思,其实是根据code,返回对应的中文信息。code和中文信息的对应关系,被保存在ResultInformation.messageMap中,因此用get(code)就能返回中文信息。
3.3. 新增:自定义异常和对异常的处理
有时会发生期望范围内的异常(如库存不足、输入的账号密码不符合规范等)
对于这些情况,不仅希望程序能将状态码、中文信息返回,还希望抛出异常,并使代码回滚,此时便引出该部分:
先定义自定义异常类CustomException.java

在统一返回对象Result.java中,创建构造方法对异常进行处理

4. 源码
2021.04.06修订:
- 为ResultInformation新增successMap属性,该属性使得可以有多个状态码使Result判定返回状态为“成功”
- 为Result新增toString方法,用junit进行单元测试时返回值更加直观
2021.08.16修订:
- 业务中较少用到Result中的success属性,通常只要code和message便足矣,因此删去boolean类型属性success,同时删去ResultImformation中的successMap属性
- 新增对异常的处理和手动的事务回滚,相关说明已在3.3中呈现
- Result更名为ResultUtil,ResultInformation更名为ResultConstant
4.1. ResultConstant.java(在constant包下)
package com.eshang.my.basket.background.constant;
import java.util.HashMap;
public class ResultConstant {
public static HashMap<Integer, String> messageMap = new HashMap<>();
//成功或失败,状态码都是1开头
public static int SUCCESS = 10000;
public static int FAILED = 10001;
//交互
public static int LIKE_SUCCESS = 10011;
public static int COLLECT_SUCCESS = 10012;
public static int LIKE_CANCEL = 10013;
public static int COLLECT_CANCEL = 10014;
public static int IS_LIKE = 10015;
public static int IS_NOT_LIKE = 10016;
public static int IS_COLLECT = 10017;
public static int IS_NOT_COLLECT = 10018;
//用户
public static int USER_NAME_IS_NULL = 10021;
public static int USER_PASSWORD_IS_NULL = 10022;
public static int USER_NICKNAME_IS_NULL = 10023;
public static int CONFIRM_PASSWORD_IS_NULL = 10024;
public static int CONFIRM_PASSWORD_IS_WRONG = 10025;
public static int USER_PHONE_IS_NULL = 10026;
//异常:20000
public static int ERROR = 20000;
static {
//成功或失败
messageMap.put(10000, "成功");
messageMap.put(10001, "失败");
//交互
messageMap.put(10011, "点赞成功");
messageMap.put(10012, "收藏成功");
messageMap.put(10013, "成功取消点赞");
messageMap.put(10014, "成功取消收藏");
messageMap.put(10015, "已点赞");
messageMap.put(10016, "未点赞");
messageMap.put(10017, "已收藏");
messageMap.put(10018, "未收藏");
//用户
messageMap.put(10021, "未输入账号");
messageMap.put(10022, "未输入密码");
messageMap.put(10023, "未输入昵称");
messageMap.put(10024, "未确认密码");
messageMap.put(10025, "两次密码不同");
messageMap.put(10026, "未输入联系方式");
//异常
messageMap.put(20000, "系统异常");
}
}
4.2. ResultUtil.java(在util包下)
package com.eshang.my.basket.background.util;
import com.eshang.my.basket.background.constant.ResultConstant;
import com.eshang.my.basket.background.exception.CustomException;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.transaction.NoTransactionException;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import java.util.HashMap;
import java.util.Map;
/**
* @author xyx-Eshang
*/
public class ResultUtil<T> {
@ApiModelProperty(value = "状态码", example = "200")
private Integer code;
@ApiModelProperty(value = "提示信息", example = "成功")
private String message;
@ApiModelProperty(value = "返回数据")
private Map<String, T> data;
/**
* 01 空参构造:成功
*/
public ResultUtil() {
this.code = ResultConstant.SUCCESS;
this.message = ResultConstant.messageMap.get(code);
}
/**
* 02. 只有状态码的构造方法
*
* @param code
*/
public ResultUtil(Integer code) {
this.code = code;
this.message = ResultConstant.messageMap.get(code);
}
/**
* 03. 有key、有value的构造方法
*
* @param dataKey
* @param dataValue
*/
public ResultUtil(String dataKey, T dataValue) {
this.code = ResultConstant.SUCCESS;
this.message = ResultConstant.messageMap.get(code);
Map<String, T> dataMap = new HashMap<>();
dataMap.put(dataKey, dataValue);
this.data = dataMap;
}
/**
* 04. 有code,有key,有value的构造方法
*
* @param code
* @param dataKey
* @param dataValue
*/
public ResultUtil(Integer code, String dataKey, T dataValue) {
this.code = code;
this.message = ResultConstant.messageMap.get(code);
Map<String, T> dataMap = new HashMap<>();
dataMap.put(dataKey, dataValue);
this.data = dataMap;
}
/**
* 05. 异常时:回滚
*
* @param exception
*/
public ResultUtil(Exception exception) {
try {
//手动回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
} catch (NoTransactionException e) {
//如果方法没有开启事务,那么这里会抛出异常。不处理即可
}
if (exception.getClass().getSimpleName().contentEquals(CustomException.class.getSimpleName())) {
CustomException e = (CustomException) exception;
this.code = e.getCode();
this.message = e.getMessage();
System.out.println("===发生自定义异常:" + this.message + "===");
} else {
exception.printStackTrace();
this.code = 40000;
this.message = "系统异常";
}
this.data = null;
}
@Override
public String toString() {
return "●\t该方法的返回值结果如下:\n" +
"●\tcode:" + code + '\n' +
"●\tmessage:" + message + '\n' +
"●\tdata:\n" + data;
}
public Integer getCode() {
return code;
}
public ResultUtil<T> setCode(Integer code) {
this.code = code;
return this;
}
public String getMessage() {
return message;
}
public ResultUtil<T> setMessage(String message) {
this.message = message;
return this;
}
public Map<String, T> getData() {
return data;
}
public ResultUtil<T> setData(Map<String, T> data) {
this.data = data;
return this;
}
}
4.3. CustomException(在exception包下)
package com.eshang.my.basket.background.exception;
import edu.gdut.oec.constant.ResultConstant;
/**
* @author xyx-Eshang
*/
public class CustomException extends Exception {
/**
* 状态码
*/
private Integer code;
/**
* 异常信息
*/
private String message;
public CustomException() {
super();
}
public CustomException(Integer code) {
this.code = code;
this.message = ResultConstant.messageMap.get(code);
}
public CustomException(String methodSignature, String parameterName) {
this.code = 40001;
this.message = "执行方法 " + methodSignature + " 时,传入的参数 " + parameterName + " 为空";
}
@Override
public String toString() {
return "CustomException{" +
"code=" + code +
", message='" + message + '\'' +
'}';
}
public Integer getCode() {
return code;
}
public CustomException setCode(Integer code) {
this.code = code;
return this;
}
@Override
public String getMessage() {
return message;
}
public CustomException setMessage(String message) {
this.message = message;
return this;
}
}
版权声明:本文为xyxyxyxyxyxyx原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。