基本思路

1、定义返回代码的枚举类。
2、定义一个公共方法控制器 BaseRestController ,实现 success / error 系列的方法,便于自定义 Exception 类和业务控制器中调用。
3、捕获全局异常,可以自定义业务异常类,在方法中调用公共方法控制器 BaseRestController 中的 error 方法返回返回代码枚举类中的元素。

文件目录结构

环境
image.png

1、定义返回码类

将返回码类分为枚举类和常规类,好处是自由度较高,可以随喜好选择不同的返回方式

1.1、枚举类

ResponseCodeEnum

  1. package com.example.boot.response;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Getter;
  4. @Getter
  5. @AllArgsConstructor
  6. public enum ResponseCodeEnum {
  7. /**
  8. * 通用
  9. */
  10. SUCCESS(1, "ok"),
  11. ERROR(0, "error"),
  12. /**
  13. * 系统错误
  14. */
  15. InternalError(50000, "系统内部错误"),
  16. /**
  17. * 客户端错误
  18. */
  19. ClientError(30000, "客户端错误"),
  20. /**
  21. * 其他错误
  22. */
  23. OtherError(30000, "其他错误"),
  24. ;
  25. private Integer code;
  26. private String msg;
  27. }

1.2、常规类

ResponseCode

  1. package com.example.boot.response;
  2. public class ResponseCode {
  3. /**
  4. * 成功
  5. */
  6. public static int SUCCESSED = 1;
  7. /**
  8. * 失败
  9. */
  10. public static int FAILED = 0;
  11. /**
  12. * 缺少请求参数异常
  13. */
  14. public static int missingServletRequestParameterException = 50000;
  15. /**
  16. * 参数类型不匹配错误
  17. */
  18. public static int methodArgumentTypeMismatchException = 50100;
  19. }

2、定义返回体类

SpringBoot 会将对象封装成 json 返回出去。所以,我们需要定义一个用来封装返回体的对象。例如:code/msg/data 等

  1. {
  2. "code": 0,
  3. "msg": "error",
  4. "data": null
  5. }

Response

  1. package com.example.boot.response;
  2. import com.fasterxml.jackson.annotation.JsonProperty;
  3. import com.fasterxml.jackson.annotation.JsonPropertyOrder;
  4. import lombok.AllArgsConstructor;
  5. import lombok.Data;
  6. import lombok.NoArgsConstructor;
  7. import lombok.ToString;
  8. import java.io.Serializable;
  9. @Data
  10. @AllArgsConstructor
  11. @NoArgsConstructor
  12. @ToString
  13. @JsonPropertyOrder(value = {"code", "msg", "data"})
  14. public class Response<T> implements Serializable {
  15. /**
  16. * 响应码
  17. */
  18. @JsonProperty("code")
  19. private Integer code;
  20. /**
  21. * 返回消息
  22. */
  23. @JsonProperty("msg")
  24. private String msg;
  25. /**
  26. * 返回结果集
  27. */
  28. @JsonProperty("data")
  29. private T data;
  30. }

3、定义控制器

3.1、定义公共方法控制器

BaseRestController

  1. package com.example.boot.controller;
  2. import com.example.boot.response.Response;
  3. import com.example.boot.response.ResponseCode;
  4. import com.example.boot.response.ResponseCodeEnum;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.springframework.web.bind.annotation.RestController;
  7. @RestController
  8. @Slf4j
  9. public class BaseRestController {
  10. public BaseRestController() {
  11. log.info("BaseRestController 构造函数被调用了");
  12. }
  13. /**
  14. * success 系列方法
  15. */
  16. public Response success() {
  17. Response response = new Response<>();
  18. response.setCode(ResponseCode.SUCCESSED);
  19. response.setData(null);
  20. response.setMsg("ok");
  21. return response;
  22. }
  23. public Response success(String msg) {
  24. Response response = new Response<>();
  25. response.setCode(ResponseCode.SUCCESSED);
  26. response.setData(null);
  27. response.setMsg(msg);
  28. return response;
  29. }
  30. public Response success(String msg, Object data) {
  31. Response response = new Response<>();
  32. response.setCode(ResponseCode.SUCCESSED);
  33. response.setData(data);
  34. response.setMsg(msg);
  35. return response;
  36. }
  37. public Response success(String msg, Integer code) {
  38. Response response = new Response<>();
  39. response.setCode(code);
  40. response.setData(null);
  41. response.setMsg(msg);
  42. return response;
  43. }
  44. public Response success(String msg, Object data, Integer code) {
  45. Response response = new Response<>();
  46. response.setCode(code);
  47. response.setData(data);
  48. response.setMsg(msg);
  49. return response;
  50. }
  51. public Response success(ResponseCodeEnum responseCodeEnum, Object data) {
  52. Response response = new Response<>();
  53. response.setCode(responseCodeEnum.getCode());
  54. response.setMsg(responseCodeEnum.getMsg());
  55. response.setData(data);
  56. return response;
  57. }
  58. public Response success(ResponseCodeEnum responseCodeEnum) {
  59. Response response = new Response<>();
  60. response.setCode(responseCodeEnum.getCode());
  61. response.setMsg(responseCodeEnum.getMsg());
  62. response.setData(null);
  63. return response;
  64. }
  65. /**
  66. * error 系列方法
  67. */
  68. public Response error() {
  69. Response response = new Response<>();
  70. response.setCode(ResponseCode.FAILED);
  71. response.setData(null);
  72. response.setMsg("ok");
  73. return response;
  74. }
  75. public Response error(String msg) {
  76. Response response = new Response<>();
  77. response.setCode(ResponseCode.FAILED);
  78. response.setData(null);
  79. response.setMsg(msg);
  80. return response;
  81. }
  82. public Response error(String msg, Object data) {
  83. Response response = new Response<>();
  84. response.setCode(ResponseCode.FAILED);
  85. response.setData(data);
  86. response.setMsg(msg);
  87. return response;
  88. }
  89. public Response error(String msg, Integer code) {
  90. Response response = new Response<>();
  91. response.setCode(code);
  92. response.setData(null);
  93. response.setMsg(msg);
  94. return response;
  95. }
  96. public Response error(String msg, Object data, Integer code) {
  97. Response response = new Response<>();
  98. response.setCode(code);
  99. response.setData(data);
  100. response.setMsg(msg);
  101. return response;
  102. }
  103. public Response error(ResponseCodeEnum responseCodeEnum, Object data) {
  104. Response response = new Response<>();
  105. response.setCode(responseCodeEnum.getCode());
  106. response.setMsg(responseCodeEnum.getMsg());
  107. response.setData(data);
  108. return response;
  109. }
  110. public Response error(ResponseCodeEnum responseCodeEnum) {
  111. Response response = new Response<>();
  112. response.setCode(responseCodeEnum.getCode());
  113. response.setMsg(responseCodeEnum.getMsg());
  114. response.setData(null);
  115. return response;
  116. }
  117. }

3.2、定义业务控制器

IndexController

  1. package com.example.boot.controller;
  2. import com.example.boot.response.Response;
  3. import com.example.boot.response.ResponseCodeEnum;
  4. import lombok.extern.slf4j.Slf4j;
  5. import org.springframework.web.bind.annotation.RequestMapping;
  6. import org.springframework.web.bind.annotation.RequestParam;
  7. import org.springframework.web.bind.annotation.RestController;
  8. @RestController
  9. @Slf4j
  10. public class IndexController extends BaseRestController {
  11. public IndexController() {
  12. log.info("IndexController 构造函数被调用了");
  13. }
  14. @RequestMapping(path = {
  15. "/",
  16. "/index"
  17. })
  18. public Response index() {
  19. return success();
  20. }
  21. @RequestMapping(path = {
  22. "/test"
  23. })
  24. public Response test(@RequestParam(name = "a") Integer a) {
  25. if (a.equals(0)) {
  26. // return error("a不能为0");
  27. // throw new CustomerException(201, "自定义错误");
  28. return error(ResponseCodeEnum.ArithmeticException);
  29. }
  30. int b = 10 / a;
  31. return success();
  32. }
  33. }

在 test 方法里,我注释掉了两行代码。

1)因为在公共方法控制器 BaseRestController 中,我已经默认实现了success / error 系列的方法,所以在业务 controller 中可以这样返回 msg:

  1. return error("a不能为0");

2)因为捕获了全局异常,所以可以在业务 controller 中直接 throw 我们自定义的异常类。

  1. throw new CustomerException(201, "自定义错误");

不过我还是比较推荐使用返回码枚举类的方式来返回错误信息:

  1. return error(ResponseCodeEnum.ArithmeticException);

4、定义异常类

4.1、定义一个处理全局异常的类。

GlobalExceptionHandler

  1. package com.example.boot.exception;
  2. import com.example.boot.controller.BaseRestController;
  3. import com.example.boot.response.Response;
  4. import com.example.boot.response.ResponseCode;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.springframework.web.bind.annotation.ExceptionHandler;
  7. import org.springframework.web.bind.annotation.RestControllerAdvice;
  8. import javax.servlet.http.HttpServletRequest;
  9. import java.util.HashMap;
  10. import java.util.Map;
  11. @RestControllerAdvice
  12. @Slf4j
  13. public class GlobalExceptionHandler extends BaseRestController {
  14. /**
  15. * 处理所有类型的异常
  16. */
  17. @ExceptionHandler({
  18. Exception.class,
  19. })
  20. public Response exceptionHandler(HttpServletRequest req, Exception e) {
  21. log.error("全局异常捕获:", e);
  22. Map<String, Object> detail = new HashMap<>();
  23. detail.put("exception", e.toString());
  24. return error("全局异常捕获", detail, ResponseCode.FAILED);
  25. }
  26. /**
  27. * 处理自定义的业务异常
  28. */
  29. @ExceptionHandler(value = CustomerException.class)
  30. public Response customerExceptionHandler(HttpServletRequest req, Exception e) {
  31. log.error("自定义业务异常:", e);
  32. Map<String, Object> detail = new HashMap<>();
  33. detail.put("exception", e.toString());
  34. return error("自定义异常", detail, ResponseCode.FAILED);
  35. }
  36. }

4.2、定义业务异常类

根据业务需求,定义自己需要的异常类。

CustomerException

  1. package com.example.boot.exception;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. @Data
  6. @AllArgsConstructor
  7. @NoArgsConstructor
  8. public class CustomerException extends RuntimeException {
  9. /**
  10. * 错误码
  11. */
  12. protected Integer errorCode;
  13. /**
  14. * 错误信息
  15. */
  16. protected String errorMsg;
  17. }

5、测试

5.1、正常请求

image.png

5.2、业务exception

image.png

5.3、全局异常捕获

image.png