Spring Boot 统一响应

Spring Boot 统一响应

一. 前言

前后端交互时,后端会提供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://blog.csdn.net/IManiy/article/details/120833041
 * 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);
    }

}

⭐️源码https://gitee.com/zhp1221/ruoyi/tree/master/lab_01_web_module/lab_02_unified_handle

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
 课程目标:你将对研发框架的代码封装和开发规范制定的底层实现逻辑有所掌握,并形成自己的开发封装套路,告别CRUD课程简介:   1. 课程背景: 能帮你解决什么问题?企业中通常由架构师搭建好开发框架,里面包含了很多封装好的基础结构,日志规范以及响应的异常统一处理,还有相应的参数校验等。很多初中高级开发工程师没有机会接触这部分代码的逻辑,而这部分代码逻辑又是非线性的,单纯看代码逻辑是看不出来执行顺序的,需要大量调试总结。不像mvc代码结构,你知道从Controller层看到Service再到Dao层,而这样底层的基础性代码则像积木,不熟悉的前提下需要一块块的插入拔出,不断总结,而沿着本课程的顺序梳理与实战你将会豁然开朗。市面上的大多文章结构较散,并且处理不够全面,比如返回结构通常是 具体的正例与反例日志统一处理 统一异常处理及特殊的情况处理 参数优雅校验 1基础的校验 2. 自定义校验 3.分组校验最重要的是给大家捋顺了一个清晰的实现结构以上在我们后面章节Spring Boot HelloWorld的至少10个可扩展点里有更多的相关介绍,在核心章节里有更细致的讲解实现。理解框架升级底层逻辑: 全网首套基于Spring Boot 3.x+Java 17开发系列 SpringBoot3的升级背景和路线逻辑掌握代码重构及编码效率提升技巧学习基于最为前沿的Spring Boot 3.x 和 Java 17 开发代码依赖于Spring Boot 3.x Java 17环境开发穿插相应新版本的变化讲解可编写完成一个生产级开发规范框架的制定 包含不限于 统一响应结构统一异常处理基于ThreadLocal处理请求RequestId基于日志框架的MDC 统一记录日志统一状态码处理Filter中的异常及状态码处理,以及日志的完整性处理自定义优雅参数校验学习源码剖析方式方法等等 3. 课程规划1.  课程章节规划 2. 讲课方式代码实战为主+图文演示为辅例如说明后端校验的重要性 以一张图清晰明了的展示说明解答了为何前端有了前端校验还要后端校验的问题 3. 特别说明本课程所有代码使用版本会随着Spring Boot 3.x的开发进度而更新,直到Spring Boot 3.x的正式版本发布,可放心食用本课程的重点会侧重放在研发框架的基础规范编码上,并非专注于SpringBoot3.x和Java17的新特性上讲解。主要是两点原因,1课程的方向侧重点, 2. SpringBoot3.x 官方尚处于MileStone/Snapshot版并未Release,所以大家可关注本人编程燃风后续的产品课程。本课程代码同样适用于Spring Boot 1.x 2.x 只需微调API和相关库版本的即可(注意1.x已经归档不维护) 常见问题:问:是否讲解Java17和SpringBoot3新特性答:本课程的重点会侧重放在研发框架的基础规范编码上,并非专注于SpringBoot3.x和Java17的新特性上讲解。主要是两点原因,1课程的方向侧重点是框架基础规范编码实战 2. SpringBoot3.x 官方尚处于MileStone/Snapshot版并未Release,所以大家可关注本人编程燃风后续的讲解课程。问:代码仅限于SpringBoot3吗? SpringBoot2和SpringBoot1是否适用?答:本课程代码同样适用于Spring Boot 1.x 2.x 只需微调API和相关库版本的即可(注意1.x已经归档不维护)。另外本课程重点讲解代码封装和底层实现逻辑和具体API版本关联不大,只是基于最新的SpringBoot3和Java17实现而已,请放心使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值