• 代码优雅之道——Springboot统一返回结果


    1、为什么要统一返回结果

    前后端分离模式开始后,后端只返回给前端json数据,在实际开发中,为了降低开发人员之间的沟通成本,一般返回结果会定义成一个统一格式,具体的格式根据实际开发业务不同有所区别。从前端的角度思考,调用后端接口后如果成功了则拿到想要的数据或者对应的信息提示,如果不成功也应该有相应的信息提示。从这个角度出发,我们将返回结果设计为:

    • code:响应状态码,根据状态码判断是否成功
    • msg:提示信息,根据调用的接口自定义
    • data:返回的数据

    2、返回结果类

    1. import com.example.assertdemo.constant.ResultCodeEnum;
    2. import lombok.Data;
    3. import java.io.Serializable;
    4. /**
    5. * @author LoneWalker
    6. */
    7. @Data
    8. public class ApiResult implements Serializable {
    9. private static final long serialVersionUID = 411731814484355577L;
    10. /**
    11. * 状态码
    12. */
    13. private int code;
    14. /**
    15. * 提示信息
    16. */
    17. private String msg;
    18. /**
    19. * 相关数据
    20. */
    21. private T data;
    22. public String toString() {
    23. return "ApiResult(code=" + this.getCode() + ", msg=" + this.getMsg() + ", data=" + this.getData() + ")";
    24. }
    25. /**
    26. * 构造器 自定义响应码与提示信息
    27. * @param code 响应码
    28. * @param message 提示信息
    29. */
    30. private ApiResult(int code,String message){
    31. this.code = code;
    32. this.msg = message;
    33. }
    34. /**
    35. * 构造器 自定义响应码、提示信息、数据
    36. * @param code 响应码
    37. * @param message 提示信息
    38. * @param data 返回数据
    39. */
    40. private ApiResult(int code,String message,T data){
    41. this(code,message);
    42. this.data = data;
    43. }
    44. /**
    45. * 成功构造器 无返回数据
    46. */
    47. public static ApiResult success(){
    48. return new ApiResult<>(ResultCodeEnum.SUCCESS.getCode(), ResultCodeEnum.SUCCESS.getMessage());
    49. }
    50. /**
    51. * 成功构造器 自定义提示信息 无返回数据
    52. * @param message 提示信息
    53. */
    54. public static ApiResult success(String message){
    55. return new ApiResult<>(ResultCodeEnum.SUCCESS.getCode(), message);
    56. }
    57. /**
    58. * 成功构造器 有返回数据
    59. */
    60. public static ApiResult success(T data){
    61. return new ApiResult<>(ResultCodeEnum.SUCCESS.getCode(), ResultCodeEnum.SUCCESS.getMessage(),data);
    62. }
    63. /**
    64. * 失败构造器 无返回数据
    65. */
    66. public static ApiResult fail(){
    67. return new ApiResult<>(ResultCodeEnum.FAIL.getCode(), ResultCodeEnum.FAIL.getMessage());
    68. }
    69. /**
    70. * 失败构造器 自定义提示信息 无返回数据
    71. * @param message 提示信息
    72. */
    73. public static ApiResult fail(String message){
    74. return new ApiResult<>(ResultCodeEnum.FAIL.getCode(), message);
    75. }
    76. /**
    77. * 失败构造器 有返回数据
    78. */
    79. public static ApiResult fail(T data){
    80. return new ApiResult<>(ResultCodeEnum.FAIL.getCode(), ResultCodeEnum.FAIL.getMessage(),data);
    81. }
    82. }

    3、状态码及提示信息枚举

    除去基础的操作成功或失败,可以将状态码归类,例如请求参数问题归纳到1001-1999之间。

    1. import lombok.Getter;
    2. /**
    3. * @author LoneWalker
    4. */
    5. @Getter
    6. public enum ResultCodeEnum{
    7. /**
    8. * success
    9. */
    10. SUCCESS(0,"操作成功"),
    11. /**
    12. * fail
    13. */
    14. FAIL(-1,"操作失败"),
    15. /**
    16. * 参数错误:1001-1999
    17. */
    18. PARAM_IS_INVALID(1001,"参数无效"),
    19. PARAM_TYPE_ERROR(1002,"参数类型错误"),
    20. ;
    21. /**
    22. * 状态码
    23. */
    24. private final int code;
    25. /**
    26. * 提示信息
    27. */
    28. private final String message;
    29. ResultCodeEnum(Integer code, String message){
    30. this.code = code;
    31. this.message = message;
    32. }
    33. }

    4、使用与测试

    controller

    1. import com.example.assertdemo.common.ApiResult;
    2. import com.example.assertdemo.entity.Contract;
    3. import com.example.assertdemo.req.AddContractReq;
    4. import com.example.assertdemo.req.QueryContractReq;
    5. import com.example.assertdemo.service.ContractService;
    6. import org.springframework.beans.factory.annotation.Autowired;
    7. import org.springframework.web.bind.annotation.PostMapping;
    8. import org.springframework.web.bind.annotation.RequestBody;
    9. import org.springframework.web.bind.annotation.RequestMapping;
    10. import org.springframework.web.bind.annotation.RestController;
    11. import java.util.List;
    12. @RestController
    13. @RequestMapping("/contract/")
    14. public class ContractController {
    15. @Autowired
    16. private ContractService contractService;
    17. @PostMapping("add")
    18. public ApiResult addContract(@RequestBody AddContractReq request) {
    19. return contractService.addContract(request);
    20. }
    21. @PostMapping("list")
    22. public ApiResult> listContract(@RequestBody QueryContractReq request) {
    23. return contractService.listContract(request);
    24. }
    25. }

    新增或查询参数类

    1. import lombok.Data;
    2. /**
    3. * @author LoneWalker
    4. * @date 2022/8/28
    5. * @description
    6. */
    7. @Data
    8. public class AddContractReq {
    9. /**
    10. * 合同编号
    11. */
    12. private String code;
    13. /**
    14. * 合同名称
    15. */
    16. private String name;
    17. /**
    18. * 客户名称
    19. */
    20. private String customer;
    21. }
    1. import lombok.Data;
    2. /**
    3. * @author LoneWalker
    4. * @date 2022/8/28
    5. * @description
    6. */
    7. @Data
    8. public class QueryContractReq {
    9. /**
    10. * 合同名称
    11. */
    12. private String contractName;
    13. /**
    14. * 客户名称
    15. */
    16. private String customer;
    17. }

    Service

    1. import com.example.assertdemo.common.ApiResult;
    2. import com.example.assertdemo.entity.Contract;
    3. import com.example.assertdemo.req.AddContractReq;
    4. import com.example.assertdemo.req.QueryContractReq;
    5. import java.util.List;
    6. public interface ContractService {
    7. /**
    8. * 添加合同信息
    9. * @param request
    10. * @return
    11. */
    12. ApiResult addContract(AddContractReq request);
    13. /**
    14. * 合同列表数据
    15. * @param request 查询参数
    16. * @return
    17. */
    18. ApiResult> listContract(QueryContractReq request);
    19. }

    impl

    1. import com.example.assertdemo.common.ApiResult;
    2. import com.example.assertdemo.entity.Contract;
    3. import com.example.assertdemo.req.AddContractReq;
    4. import com.example.assertdemo.req.QueryContractReq;
    5. import com.example.assertdemo.service.ContractService;
    6. import org.springframework.stereotype.Service;
    7. import java.util.ArrayList;
    8. import java.util.List;
    9. @Service("contractService")
    10. public class ContractServiceImpl implements ContractService {
    11. @Override
    12. public ApiResult addContract(AddContractReq request) {
    13. //存入数据库
    14. return ApiResult.success();
    15. }
    16. @Override
    17. public ApiResult> listContract(QueryContractReq request) {
    18. //模拟数据
    19. List list = new ArrayList<>();
    20. Contract contractOne = new Contract(1L, "HT082801", "临床试验一期合同", "省立医院");
    21. Contract contractTwo = new Contract(2L, "HT082802", "临床试验二期合同", "省立医院");
    22. Contract contractThree = new Contract(3L, "HT082803", "临床试验三期合同", "省立医院");
    23. list.add(contractOne);
    24. list.add(contractTwo);
    25. list.add(contractThree);
    26. return ApiResult.success(list);
    27. }
    28. }

    启动项目,新增一条数据

    查询数据

    5、问题

    以上都是接口调用成功的情况,当业务出现异常,按照我们的初衷,需要将业务异常结果组装成统一的信息返回给前端进行提示。

    下一篇 代码优雅之道——断言 + Springboot统一异常处理

  • 相关阅读:
    加速汽车行业转型,云计算到底扮演了什么角色?
    Leetcode 349.两个数组的交集
    Seata设计核心原理
    C语言--文件操作详解(2)(文本文件和二进制文件,文件读取结束的判定,用函数进行文件的拷贝,文件缓冲区)
    设计模式之桥接模式
    SQL获取正数第N个或倒数第N个数据
    如何画架构图?
    CDGA|交通行业做好数字化转型的核心是什么?
    运营商IMS网间互联互通组网关键技术研究
    会声会影2024(Corel VideoStudio)正式版安装下载步骤教程
  • 原文地址:https://blog.csdn.net/QingXu1234/article/details/126590649