SpringBoot:统一接口封装

郎家岭伯爵 2023年03月31日 802次浏览

前言

接口统一封装、统一返回可以更规范地给出接口返回的状态码和信息。

实现

状态码封装

这里以常见的状态码为例,包含 responseCodedescription 两个属性。

如果还有其它业务状态码,也可以放到这个类中。

  1. package com.langjialing.helloworld.config.response;

  2. /**
  3. * @author 郎家岭伯爵
  4. * @time 2023/3/31 14:07
  5. */

  6. import lombok.AllArgsConstructor;
  7. import lombok.Getter;

  8. import java.util.Arrays;
  9. import java.util.Collections;
  10. import java.util.List;

  11. /**
  12. * @author pdai
  13. */
  14. @Getter
  15. @AllArgsConstructor
  16. public enum ResponseStatus {

  17. SUCCESS("200", "success"),
  18. FAIL("500", "failed"),

  19. HTTP_STATUS_200("200", "ok"),
  20. HTTP_STATUS_400("400", "request error"),
  21. HTTP_STATUS_401("401", "no authentication"),
  22. HTTP_STATUS_403("403", "no authorities"),
  23. HTTP_STATUS_500("500", "server error");

  24. public static final List<ResponseStatus> HTTP_STATUS_ALL = Collections.unmodifiableList(
  25. Arrays.asList(HTTP_STATUS_200, HTTP_STATUS_400, HTTP_STATUS_401, HTTP_STATUS_403, HTTP_STATUS_500
  26. ));

  27. /**
  28. * response code
  29. */
  30. private final String responseCode;

  31. /**
  32. * description.
  33. */
  34. private final String description;

  35. }

返回内容封装

包含公共的接口返回时间 timestamp,状态 status,消息 message, 以及数据 data

考虑到数据的序列化(比如在网络上传输),这里 data 有时候还会 extends Serializable

  1. package com.langjialing.helloworld.config.response;

  2. import lombok.Builder;
  3. import lombok.Data;

  4. import java.io.Serializable;

  5. /**
  6. * @author 郎家岭伯爵
  7. * @time 2023/3/31 14:09
  8. */
  9. @Data
  10. @Builder
  11. public class ResponseResult<T> {

  12. /**
  13. * response timestamp.
  14. */
  15. private long timestamp;

  16. /**
  17. * response code, 200 -> OK.
  18. */
  19. private String status;

  20. /**
  21. * response message.
  22. */
  23. private String message;

  24. /**
  25. * response data.
  26. */
  27. private T data;

  28. /**
  29. * response success result wrapper.
  30. *
  31. * @param <T> type of data class
  32. * @return response result
  33. */
  34. public static <T> ResponseResult<T> success() {
  35. return success(null);
  36. }

  37. /**
  38. * response success result wrapper.
  39. *
  40. * @param data response data
  41. * @param <T> type of data class
  42. * @return response result
  43. */
  44. public static <T> ResponseResult<T> success(T data) {
  45. return ResponseResult.<T>builder().data(data)
  46. .message(ResponseStatus.SUCCESS.getDescription())
  47. .status(ResponseStatus.SUCCESS.getResponseCode())
  48. .timestamp(System.currentTimeMillis())
  49. .build();
  50. }

  51. /**
  52. * response error result wrapper.
  53. *
  54. * @param message error message
  55. * @param <T> type of data class
  56. * @return response result
  57. */
  58. public static <T extends Serializable> ResponseResult<T> fail(String message) {
  59. return fail(null, message);
  60. }

  61. /**
  62. * response error result wrapper.
  63. *
  64. * @param data response data
  65. * @param message error message
  66. * @param <T> type of data class
  67. * @return response result
  68. */
  69. public static <T> ResponseResult<T> fail(T data, String message) {
  70. return ResponseResult.<T>builder().data(data)
  71. .message(message)
  72. .status(ResponseStatus.FAIL.getResponseCode())
  73. .timestamp(System.currentTimeMillis())
  74. .build();
  75. }

  76. }

接口返回时调用

在接口返回时调用, 以 user 接口为例:

  1. package com.langjialing.helloworld.controller;

  2. import com.langjialing.helloworld.config.response.ResponseResult;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.apache.commons.collections4.map.LRUMap;
  5. import org.springframework.web.bind.annotation.GetMapping;
  6. import org.springframework.web.bind.annotation.RequestParam;
  7. import org.springframework.web.bind.annotation.RestController;

  8. /**
  9. * @author 郎家岭伯爵
  10. * @time 2023/3/22 9:30
  11. */
  12. @RestController
  13. @Slf4j
  14. public class UserController {

  15. /**
  16. * 最大容量 100 个,根据 LRU 算法淘汰数据的 Map 集合
  17. */
  18. private LRUMap<String, Integer> reqCache = new LRUMap<>(100);

  19. @GetMapping("/add")
  20. public ResponseResult<String> addUser(@RequestParam String userId){

  21. // 非空判断(忽略)...
  22. synchronized (this.getClass()) {
  23. // 重复请求判断
  24. if (reqCache.containsKey(userId)) {
  25. // 重复请求
  26. log.info("请勿重复提交:{}", userId);
  27. return ResponseResult.fail("400","执行失败!");
  28. }
  29. // 存储请求 ID
  30. reqCache.put(userId, 1);
  31. }
  32. // 业务代码...
  33. log.info("成功添加用户:{}", userId);
  34. // return "执行成功!";
  35. return ResponseResult.success("执行成功!");
  36. }
  37. }

总结

接口统一封装在开发中是一种比较规范的做法,通常来说我们应该在自己的接口或者项目中封装统一的返回状态码和信息。