SpringBoot定义优雅全局统一Restful API 响应框架

kenx
• 阅读 433

假如现在有一个Java项目,老板让你做项目组长,定义项目基础框架,系统技术架构选型, 你应该如何设计一个规范的统一的Restful API 响应框架呢

思考

目前项目开发,都是基于前后端分离模式开发的,基于后端模板引擎那一套,可能已经不适用一些项目开发流程,和当下开发模式了,尤其在要写比较大型项目,前后端项目拆分,团队共同开发那是必不可少的

目前的前后端开发大部分数据的传输格式都是json,因此定义一个统一规范的数据格式有利于前后端的交互与UI的展示。

返回的统一接口形式应该包含这些内容

  1. 是否响应成功
  2. 响应状态码
  3. 状态码描述
  4. 响应数据
  5. 接口调用时间
  6. 其他标识符

按照这些我们可以定义统一的标准结果返回

响应枚举

前三者可以定义为 success,code,message

package cn.soboys.springbootrestfulapi.common.resp;

import lombok.Data;
import lombok.Getter;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * @author 公众号 程序员三时
 * @version 1.0
 * @date 2023/4/28 22:39
 * @webSite https://github.com/coder-amiao
 * 响应结果枚举
 */
@Getter
public enum ResultCodeEnum{
    SUCCESS(true, 200, "成功"),
    FAIL(false, 400, "请求失败"),

    NOT_FOUND(false, 404, "接口不存在"),
    FORBIDDEN(false, 403, "资源拒绝访问"),
    UNAUTHORIZED(false, 401, "未认证(签名错误)"),

    INTERNAL_SERVER_ERROR(false, 500, "服务器内部错误"),


    NULL_POINT(false, 200002, "空指针异常"),
    PARAM_ERROR(false, 200001, "参数错误");

    /**
     * 响应是否成功
     */
    private Boolean success;
    /**
     * 响应状态码
     */
    private Integer code;
    /**
     * 响应信息
     */
    private String message;


    ResultCodeEnum(Boolean success, Integer code, String message) {
        this.success = success;
        this.code = code;
        this.message = message;
    }
}

统一结果类

  • 外部返回调用类统一的结果方法 success,failure 因此构造器私有
  • 内置静态方法,直接返回对象
  • 便于自定义统一结果信息,使用链式编程,返回对象类本身 return this
  • 响应数据为json格式,可定义为JsonObjectMap形式
package cn.soboys.springbootrestfulapi.common.resp;

import lombok.Data;

import java.util.HashMap;
import java.util.Map;

/**
 * @author 公众号 程序员三时
 * @version 1.0
 * @date 2023/4/28 22:47
 * @webSite https://github.com/coder-amiao
 * 统一响应结果处理  使用链式编程 返回类本身
 */
@Data
public class R {

    private Boolean success;

    private Integer code;

    private String message;

    /**
     * 接口请求时间戳
     */
    private Long timestamp;

    private Map<String, Object> data = new HashMap<>();


    private R setSuccess(Boolean success) {
        this.success = success;
        return this;
    }


    private R setMessage(String message) {
        this.message = message;
        return this;
    }

    private R setData(Map<String, Object> data) {
        this.data = data;
        return this;
    }

    private R setCode(Integer code) {
        this.code = code;
        return this;
    }

    private R() {
    }

    private R(Long timestamp) {
        this.timestamp = timestamp;
    }


    /**
     * 通用返回成功
     *
     * @return
     */
    public static R success() {
        return new R(System.currentTimeMillis())
                .setSuccess(ResultCodeEnum.SUCCESS.getSuccess())
                .setCode(ResultCodeEnum.SUCCESS.getCode())
                .setMessage(ResultCodeEnum.SUCCESS.getMessage());

    }

    /**
     * 通用返回失败
     *
     * @return
     */
    public static R failure() {
        return new R(System.currentTimeMillis())
                .setSuccess(ResultCodeEnum.FAIL.getSuccess())
                .setCode(ResultCodeEnum.FAIL.getCode())
                .setMessage(ResultCodeEnum.FAIL.getMessage());

    }

    /**
     * 设置结果,形参为结果枚举
     *
     * @param result
     * @return
     */
    public static R setResult(ResultCodeEnum result) {
        return new R(System.currentTimeMillis())
                .setSuccess(result.getSuccess())
                .setCode(result.getCode())
                .setMessage(result.getMessage());

    }


    // 自定义返回数据
    public R data(Map<String, Object> map) {
        return this.setData(map);

    }

    // 通用设置data
    public R data(String key, Object value) {
        this.data.put(key, value);
        return this;
    }

    // 自定义状态信息
    public R message(String message) {
        return this.setMessage(message);

    }

    // 自定义状态码
    public R code(Integer code) {
        return this.setCode(code);

    }

    // 自定义返回结果
    public R success(Boolean success) {
        return this.setSuccess(success);

    }

}

控制层调用返回

package cn.soboys.springbootrestfulapi.controller;


import cn.soboys.springbootrestfulapi.common.resp.R;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
 * @author 公众号 程序员三时
 * @version 1.0
 * @date 2023/4/28 23:58
 * @webSite https://github.com/coder-amiao
 */
@RestController
public class IndexController {

    @GetMapping("/index")
    public R index() {
        Map m = new HashMap();
        m.put("name", "Tom");
        m.put("age", 25);
        m.put("sex", "男");
        return R.success().data(m);
    }

    @GetMapping("/home")
    public R home() {

        Student s = new Student();
        s.setUserName("Tom");
        s.setBalance(2229891.0892);
        return R.success().data("user", s).message("查询用户详情信息");
    }

    /**
     * 异常返回模拟
     *
     * @return
     */
    @GetMapping("/exception")
    public R exception() {
        Map m = null;
        m.put("name", "Jack");
        return R.success().data("user", m).message("查询用户详情信息");
    }
}

SpringBoot定义优雅全局统一Restful API 响应框架

统一结果类的使用参考了mybatis-plus中R对象的设计。

问题思考

使用统一返回结果时,还有一种情况,就是程序由于运行时异常导致的结果,有些异常我们可

能无法提前预知,不能正常走到我们return的R对象返回。

这个时候该如何处理

SpringBoot定义优雅全局统一Restful API 响应框架

下一篇文章会继续分享,留下你的思考

准备从零做一套自己的开发脚手架模板 ,关注公众 程序员三时

点赞
收藏
评论区
推荐文章
kenx kenx
3年前
个人博客开发之技术选型规划
项目技术1.SpringBoot2.4.7技术栈2.MybatisPlus3.4.xORM框架3.Mysql8.0数据库4.IDEA2021开发工具5.Macpro电脑6.Redis缓存7.Thymeleaf模版引擎项目架构1.打算用现在最流行的架构模式,前后端分离,采用RESTfulAPI规范风格jsonapi
kenx kenx
3年前
Spring Boot 无侵入式 实现RESTful API接口统一JSON格式返回
前言现在我们做项目基本上中大型项目都是选择前后端分离,前后端分离已经成了一个趋势了,所以总这样·我们就要和前端约定统一的api接口返回json格式,这样我们需要封装一个统一通用全局模版api返回格式,下次再写项目时候直接拿来用就可以了约定JSON格式一般我们和前端约定json格式是这样的json"code":200,"message
kenx kenx
1年前
SpringBoot定义优雅全局统一Restful API 响应框架二
这里解决之前留下来的问题,当程序没有正常返回时候就是程序由于运行时异常导致的结果,有些异常我们可,能无法提前预知,不能正常走到我们return的R对象返回。这个时候该如何处理在SpringBoot中,可以使用@ControllerAdvice注解来启用全局
kenx kenx
1年前
SpringBoot定义优雅全局统一Restful API 响应框架三
我们目前已经设计出了,包含全局响应,异常错误响应进行了统一返回。但是错误内容我们设计的比较模糊统一,还可以进行细化这样更有利于定位错误当我们需要调用Http接口时,无论是在Web端还是移动端,都有可能遇到各种错误,例如参数缺失、类型错误、系统错误等。为了规
Stella981 Stella981
3年前
JeecgBoot 2.4 微服务正式版发布,基于SpringBoot的低代码平台
项目介绍JeecgBoot是一款基于代码生成器的低代码平台!前后端分离架构SpringBoot2.x,SpringCloud,AntDesign&Vue,Mybatisplus,Shiro,JWT支持微服务。强大的代码生成器让前后端代码一键生成,实现低代码开发!JeecgBoot引领新的低代码开发模式(OnlineCoding
liam liam
2年前
为什么越来越多的开发者放弃使用Postman,而选择Apifox
一、API调试常用解决方案1、PostmanSwaggerMockJMeter作为一个后端开发,我做的大部分项目一般都是基于Swagger来管理API文档,基于Postman来做接口调试,基于JMeter来做接口性能测试,基于RAP等工具MockAPI数据。\2、存在的问题(1)多系统数据不互通API设计者、前
kenx kenx
1年前
SpringBoot定义优雅全局统一Restful API 响应框架四
好代码是优化出来的,不是写出来的!!如果没看前面文章,可以先看前面几篇SpringBoot定义优雅全局统一RestfulAPI响应框架
kenx kenx
1年前
SpringBoot定义优雅全局统一Restful API 响应框架五
闲话不多说,继续优化全局统一RestfulAPI响应框架做到项目通用接口可扩展。如果没有看前面几篇文章请先看前面几篇这里解决上一篇留下问题如何实现接口错误国际化。还有上一篇错误提示也不是很友好我们可以在进一步抽象出通用异常接口。异常信息应由固定异常编码信息
kenx kenx
1年前
SpringBoot定义优雅全局统一Restful API 响应框架六
闲话不多说,继续优化全局统一RestfulAPI响应框架做到项目通用接口可扩展。如果没有看前面几篇文章请先看前面几篇这里讲一讲最后的版本和需要修复的一些问题java@PostMapping("/add/UserApiCombo")publicRaddApi