在做前后端分离的项目时,后端通常都会拆分成多个独立的微服务,这时候就会涉及每个服务返回给前端的数据格式问题了
在项目中,应该对响应给前端的 JSON 数据的格式进行统一的规定,在很多响应结构中,一般会包含 code、message、data 三个属性。
code 代表状态码,这个不是 HTTP 的响应状态码,而是后端系统的业务状态码,代表了后端响应给前端的业务状态。
message 代表了后端给前端的响应信息,如果发生异常,或者系统错误,会将错误信息存储在 message 中,响应给前端。
data 代表了后端响应给前端的数据,如果请求获取了数据,会将数据放入 data 域中。
一般返回的数据格式会包括4个部分:
第一部分:请求处理是否成功,
第二部分:服务处理结果编码 code,
第三部分:编码对应的文本信息 message,
第四部分:返回值 date
{
"result": true,
"code": 1000,
"message": "SUCCESS",
"data": {
"lantian": 17,
"qingfen": 16,
"baiyun": 18
}
}
对于异常处理情况,我们也需要统一成上面的格式。如果我们在controller中通过try catch来处理异常的话,会出现一个问题就是每个函数里都加一个Try catch,代码会变的很乱。下面我们就通过spring boot的注解来省略掉controller中的try-catch 帮助我们来封装异常信息并返回给前端,这样用户也不会得到一些奇奇怪怪的错误提示。
{
"result": false,
"code": 3000,
"message": "THIS IS AN UNKNOW EXCEPTION",
"data": null
}
统一响应结构体我的做法是这样子的:
1.定义返回结构体和异常
@NoArgsConstructor @Slf4j @Data public class ResponseDataimplements Serializable { //1.自定义返回值结构信息 private int code; private String msg; private Long timestamp; private T data; //2.定义返回值和对应code的信息(code的信息在I18nConstants) public ResponseData(int code, String msg, T data) { this.code = code; this.msg = msg; //currentTimeMillis()以毫秒为单位返回当前时间 this.timestamp = System.currentTimeMillis(); this.data = data; } //3.自定义异常 public static ResponseData ok() { return ok(null); } public static ResponseData ok(T data) { return new ResponseData<>(I18nConstants.OK, I18nConstants.OK_MESSAGE, data); } public static ResponseData failed() { return failed(null); } public static ResponseData failed(T data) { return new ResponseData<>(I18nConstants.FAIL, I18nConstants.FAIL_MESSAGE, data); } public static ResponseData failed(int code, String message) { return failed(code, message, null); } public static ResponseData failed(int code, String message, T data) { return new ResponseData<>(code, message, data); } }
2.定义code信息
public interface I18nConstants {
int OK = 200;
int FAIL = 500;
int CTRL_ERROR = 501;
int ARGUMENT_ERROR = 503;
String OK_MESSAGE = "成功";
String FAIL_MESSAGE = "服务异常";
String ARGUMENT_ERROR_MESSAGE = "请求参数异常";
}
测试
@RestController
@RequestMapping("/inner/errorTranslate")
@Slf4j
@RequiredArgsConstructor
public class InnerErrorTranslateController {
private final ErrorTranslateService errorTranslateService;
@GetMapping("/selectList")
public ResponseData> selectList(ErrorTranslateQuery query) {
return ResponseData.ok(errorTranslateService.selectList(query));
}
}
测试结果(OK)
{
"code": 200,
"msg": "成功",
"timestamp": 1641280641936,
"data": [
{
"code": "cn",
"name": "中文",
"gmtCreated": 1640293629000
},
{
"code": "en",
"name": "英文",
"gmtCreated": 1640293640000
}
]
}
一般我们都进行全局异常处理,免得每次使用都要写一遍ResponseData请求体对象
3.全局异常处理
@RestControllerAdvice @Slf4j @RequiredArgsConstructor public class ResultHandlerResolver implements ResponseBodyAdvice
有了全局异常处理后,我们就可以专注写自己的业务代码了
@RestController
@RequestMapping("/inner/errorTranslate")
@Slf4j
@RequiredArgsConstructor
public class InnerErrorTranslateController {
private final ErrorTranslateService errorTranslateService;
@GetMapping("/selectList")
public List selectList(ErrorTranslateQuery query) {
return errorTranslateService.selectList(query);
}
}
测试结果(FAIL)
{
"code": 500,
"msg": "语言编码已存在",
"timestamp": 1641283519114,
"data": null
}



