Spring Boot 统一响应

文章目录

  • Spring Boot 统一响应
  • 一. 前言
  • 二. 统一响应
  • 2.1 字段
  • 2.2 错误码
  • 2.3 统一响应类
  • 三. 调用测试
  • 3.1 接口层代码
  • 3.2 UT测试用例


一. 前言

前后端交互时,后端会提供RESTful API接口供前端调用,前端调用后,需要响应前端该接口是否调用成功:

  • 成功:数据回显到前端,并渲染给客户
  • 失败:失败的信息提示回显给前端,并给用户提示

但响应的同时,各个接口若返回的格式参次不一的话,前端会根据不同接口自定义其不同的回显,时间成本会显著提高,由此后端规范统一响应的重要性由之体现而来,统一响应返回信息如下:

  • 成功:状态码 + 数据
  • 失败:状态码 + 错误信息提示

标准的RESTful API定义中,更推荐使用HTTP响应状态码为标准,但由于其信息提示不满足于更多场景的业务需求,所以一般采取自定义个性所需的状态码

二. 统一响应

2.1 字段

字段

解析

code

自定义状态码

msg

自定义响应信息

data

自定义数据

2.2 错误码

📌GlobalErrorCOdeConstants

ErrorCode封装,自定义错误码 + 错误信息,方便错误响应时调用

/**
 * 错误码常量定义
 *
 * @author zhanghp
 * @date 2022-07-22 14:37
 */
public interface GlobalErrorCodeConstants {

    ErrorCode SUCCESS = new ErrorCode(0, "成功");

    ErrorCode BAD_REQUEST = new ErrorCode(400, "请求参数不正确");

    ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500, "请求过于频繁,请稍后再试");
}

📌ErrorCode

code:错误码

msg:错误信息

/**
 * 错误码
 *
 * @author zhanghp
 * @date 2022-07-22 14:37
 */
@Data
public class ErrorCode {
    private final Integer code;

    private final String msg;

    public ErrorCode(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}

2.3 统一响应类

⭐️字段

字段

解析

code

自定义状态码

msg

自定义响应信息

data

自定义数据

⭐️代码

统一响应方法中分为:

成功响应

  1. 状态码200 + 固定成功信息提示(’success‘)
  2. 状态码200 + 固定成功信息提示(’success‘)+ 自定义数据

失败响应

  1. 状态码500 + 固定错误信息提示(‘fail’)的失败响应
  2. 状态码500 + 自定义错误信息的失败响应
  3. 状态码自定义 + 错误信息自定义的失败响应
  4. 自定义错误类封装的失败响应
/**
 * 统一响应结果封装类
 *
 * @author zhanghp
 * @date 2022-07-21 9:54
 */
@Data
@Accessors(chain = true)
@SuppressWarnings("all")
public class R<T> {

    /**
     * 状态码
     */
    private Integer code;

    /**
     * 响应信息
     */
    private String msg;

    /**
     * 数据
     */
    private T data;

    /**
     * 状态码200 + 固定成功信息提示(’success‘)
     *
     * @return 实例R
     */
    public static R success() {
        return new R()
                .setCode(HttpStatus.OK.value())
                .setMsg("success");
    }

    /**
     * 状态码200 + 固定成功信息提示(’success‘)+ 自定义数据
     *
     * @param data 数据
     * @param <T>  回显数据泛型
     * @return 实例R
     */
    public static <T> R success(T data) {
        return success().setData(data);
    }

    /**
     * 状态码500 + 固定错误信息提示('fail')的失败响应
     *
     * @return 实例R
     */
    public static R fail() {
        return new R()
                .setCode(HttpStatus.INTERNAL_SERVER_ERROR.value())
                .setMsg("fail");
    }

    /**
     * 状态码500 + 自定义错误信息的失败响应
     *
     * @param msg  错误信息
     * @return 实例R
     */
    public static <T> R fail(String msg) {
        return new R()
                .setCode(HttpStatus.INTERNAL_SERVER_ERROR.value())
                .setMsg(msg);
    }

    /**
     * 状态码自定义 + 错误信息自定义的失败响应
     * {@link GlobalErrorCodeConstants}
     *
     * @param data 数据
     * @param msg  错误信息
     * @return 实例R
     */
    public static R fail(Integer errorCode, String msg) {
        return fail()
                .setCode(errorCode)
                .setMsg(msg);
    }

    /**
     * 自定义错误类封装的失败响应
     *
     * @param error 自定义错误类
     * @return 实例R
     * @see ErrorCode
     */
    public static R fail(ErrorCode error) {
        return fail()
                .setCode(error.getCode())
                .setMsg(error.getMsg());
    }
}

三. 调用测试

3.1 接口层代码

/**
 * 统一响应实体类封装controller
 *
 * @author zhanghp
 * @date 2022-07-21 10:03
 */
@RestController
@SuppressWarnings({"rawtypes"})
public class UnifiedResponseController {

    /**
     * 状态码200 + 固定成功信息提示(’success‘)
     *
     * @return R
     */
    @GetMapping("/success")
    public R successNoArgs(){
        return success();
    }

    /**
     * 状态码200 + 固定成功信息提示(’success‘)+ 自定义数据
     *
     * @return R
     */
    @GetMapping(value = "/success2", produces = "application/json; charset=utf-8")
    public R successWithArgs(){
        return success("响应成功");
    }

    /**
     * 状态码500 + 固定错误信息提示('fail')的失败响应
     *
     * @return R
     */
    @GetMapping("/fail")
    public R failNoArgs(){
        return fail();
    }

    /**
     * 状态码500 + 自定义错误信息的失败响应
     *
     * @return R
     */
    @GetMapping(value = "/fail2", produces = "application/json; charset=utf-8")
    public R<String> failWithArgs(){
        return fail("响应失败");
    }
    
    /**
     * 状态码500 + 自定义错误信息的失败响应
     *
     * @return R
     */
    @GetMapping(value = "/fail3", produces = "application/json; charset=utf-8")
    public R<String> failCustom(){
        return fail("响应失败");
    }

    /**
     * 自定义错误类封装的失败响应
     *
     * @return R
     */
    @GetMapping(value = "/fail4", produces = "application/json; charset=utf-8")
    public R<String> failCustom2(){
        return fail(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR);
    }

}

3.2 UT测试用例

采用Spring boot test的单元测试

mockMvc类用法

/**
 * 统一响应UT
 * 
 * https://www.iocoder.cn/Spring-Boot/SpringMVC/?yudao
 */
@SpringBootTest
@AutoConfigureMockMvc
class UnifiedResponseTests {

    @Autowired
    private static MockMvc mockMvc;

    @BeforeAll
    static void init(){
        // 初始化mockMvc
        mockMvc = MockMvcBuilders.standaloneSetup(new UnifiedResponseController()).build();
    }

    @Test
    void successNoArgs() throws Exception {
        // 请求
        ResultActions perform = mockMvc.perform(MockMvcRequestBuilders.get("/success"));
        // 响应
        String contentAsString = perform.andReturn().getResponse().getContentAsString();
        // 打印
        System.out.println(contentAsString);
    }

    @Test
    void successWithArgs() throws Exception {
        // 请求
        ResultActions perform = mockMvc.perform(MockMvcRequestBuilders.get("/success2"));
        // 响应
        String contentAsString = perform.andReturn().getResponse().getContentAsString();
        // 打印
        System.out.println(contentAsString);
    }

    @Test
    void failNoArgs() throws Exception {
        // 请求
        ResultActions perform = mockMvc.perform(MockMvcRequestBuilders.get("/fail"));
        // 响应
        String contentAsString = perform.andReturn().getResponse().getContentAsString();
        // 打印
        System.out.println(contentAsString);
    }

    @Test
    void failWithArgs() throws Exception {
        // 请求
        ResultActions perform = mockMvc.perform(MockMvcRequestBuilders.get("/fail2"));
        // 响应
        String contentAsString = perform.andReturn().getResponse().getContentAsString();
        // 打印
        System.out.println(contentAsString);
    }

    @Test
    void failCustom() throws Exception {
        // 请求
        ResultActions perform = mockMvc.perform(MockMvcRequestBuilders.get("/fail3"));
        // 响应
        String contentAsString = perform.andReturn().getResponse().getContentAsString();
        // 打印
        System.out.println(contentAsString);
    }

    @Test
    void failCustom2() throws Exception {
        // 请求
        ResultActions perform = mockMvc.perform(MockMvcRequestBuilders.get("/fail4"));
        // 响应
        String contentAsString = perform.andReturn().getResponse().getContentAsString();
        // 打印
        System.out.println(contentAsString);
    }

}