SpringBoot之统一返回格式与统一异常处理

本文最后更新于:2023年11月9日 晚上

SpringBoot之统一返回格式与统一异常处理

在任何接口返回数据时,正确的返回格式:
code:状态码 data:数据 message:接口响应信息,一般接口需要的就是这三个数据。

1
2
3
4
5
{
"code": 200,
"data": "success",
"message": "成功"
}

但是如果在每一个接口都这样写一个Map返回,或者一个工具类返回,但是这样代码的重复量太复杂。
统一返回的好处:接口返回的东西直接返回,接口的中不用管状态码和响应信息

导入Jar包

1
2
3
4
5
6
7
8
9
10
11
12
13
<!--Lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>

<!--JSON-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.9</version>
</dependency>
  • 统一返回结果工具类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/**
* @Author 阿波
* @Description 统一返回结果工具类
* @Date 2021-10-25 10:52
* @Version 1.0
**/
@Data
public class ResultUtil implements Serializable {

private Integer code;

private String message;

private Object data;

private ResultUtil() {

}

public ResultUtil(ResultCode resultCode, Object data) {
this.code = resultCode.code();
this.message = resultCode.message();
this.data = data;
}

private void setResultCode(ResultCode resultCode) {
this.code = resultCode.code();
this.message = resultCode.message();
}

// 返回成功
public static ResultUtil success() {
ResultUtil result = new ResultUtil();
result.setResultCode(ResultCode.SUCCESS);
return result;
}

// 返回成功
public static ResultUtil success(Object data) {
ResultUtil result = new ResultUtil();
result.setResultCode(ResultCode.SUCCESS);
result.setData(data);
return result;
}

// 返回失败
public static ResultUtil fail(Integer code, String message) {
ResultUtil result = new ResultUtil();
result.setCode(code);
result.setMessage(message);
return result;
}

// 返回失败
public static ResultUtil fail(ResultCode resultCode) {
ResultUtil result = new ResultUtil();
result.setResultCode(resultCode);
return result;
}
}
  • 状态枚举类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* @Author 阿波
* @Description 返回状态码枚举
* @Date 2021-10-25 11:08
* @Version 1.0
**/
public enum ResultCode {

/* 成功状态码 */
SUCCESS(200, "成功"),
/* 错误状态码 */
PARAM_IS_INVALID(201, "参数无效"),
PARAM_IS_BLANK(202, "参数为空"),
PARAM_TYPE_BIND_ERROR(401, "参数类型错误"),
PARAM_NOT_COMPLETE(402, "参数缺失"),
USER_NOTLOGGED_IN(501, "用户未登录"),
USER_LOGIN_ERROR(502, "账号不存在或密码错误"),
SYSTEM_ERROR(500, "系统异常,请稍后重试");

private Integer code;
private String message;

private ResultCode(Integer code, String message) {
this.code = code;
this.message = message;
}

public Integer code() {
return this.code;
}

public String message() {
return this.message;
}
}

配置统一结果返回

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* @Author 阿波
* @Description 统一返回结果处理
* @Date 2021-10-25 10:15
* @Version 1.0
**/
//只对com.demo.controller包下的接口生效
@RestControllerAdvice(basePackages = {"com.demo.controller"})
public class ResultResponseAdvice implements ResponseBodyAdvice {

@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
return true;
}


@Override
public Object beforeBodyWrite(Object returnValue, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
ResultUtil result;
//获取返回值类型
String returnClassType = returnType.getParameterType().getSimpleName();

//如果返回值类型为void,则默认返回成功
if ("void".equals(returnClassType)) {
result = ResultUtil.success();
} else if ("Result".equals(returnClassType)) {
result = (ResultUtil) returnValue;
} else if ("String".equals(returnClassType)) {
//json的转换会出问题
result = ResultUtil.success(returnValue);
return JSON.toJSONString(result);
} else {
if (Objects.isNull(returnValue)) {
result = ResultUtil.success();
} else {
result = ResultUtil.success(returnValue);
}
}
//一定要转换为String,否则会报错
return result;
}
}
  • 排除NULL字段:在返回时字段为null则不返回 application.yaml文件中
1
2
3
spring:
jackson:
default-property-inclusion: NON_NULL

配置全局异常处理

@ExceptionHandler 的参数可以是数组,可以有多个异常类。
注:处理异常是会判断异常的继承关系。
比如是 Exception.class 那么就会处理全部的异常,可以把全部异常统一在一个方法处理,也可以分开单独处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* @Author 阿波
* @Description 统一异常处理
* @Date 2021-10-26 10:45
* @Version 1.0
**/
//只对com.demo.controller包下的接口生效
@RestControllerAdvice(basePackages = {"com.demo.controller"})
public class MyExceptionHandler {

@ExceptionHandler({ArithmeticException.class})
private ResultUtil handlerNullPointException() {
return ResultUtil.fail(500, " / by zero");
}

}

效果测试

  • 定义测试接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* @Author 阿波
* @Description Controller
* @Date 2021-10-15 9:20
* @Version 1.0
**/
@RestController
public class TestController {

@RequestMapping(path = "/test")
public String test() {
return "success";
}

@RequestMapping(path = "/testError")
public String error() {

/*产生一个 / by zero 异常*/
int x = 5 / 0;

return "error";
}
}
  • 统一返回的封装

  • 异常的处理

自责要短暂,不过要长久铭记。

SpringBoot之统一返回格式与统一异常处理
http://example.com/2021/10/26/SpringBoot之统一返回格式与统一异常处理/
作者
阿波~
发布于
2021年10月26日
更新于
2023年11月9日
许可协议