假如现在有一个Java项目,老板让你做项目组长,定义项目基础框架,系统技术架构选型, 你应该如何设计一个规范的统一的Restful API 响应框架呢
思考
目前项目开发,都是基于前后端分离模式开发的,基于后端模板引擎那一套,可能已经不适用一些项目开发流程,和当下开发模式了,尤其在要写比较大型项目,前后端项目拆分,团队共同开发那是必不可少的
目前的前后端开发大部分数据的传输格式都是json,因此定义一个统一规范的数据格式有利于前后端的交互与UI的展示。
返回的统一接口形式应该包含这些内容
- 是否响应成功
- 响应状态码
- 状态码描述
- 响应数据
- 接口调用时间
- 其他标识符
按照这些我们可以定义统一的标准结果返回
响应枚举
前三者可以定义为 success,code,message
1package cn.soboys.springbootrestfulapi.common.resp; 2 3import lombok.Data; 4import lombok.Getter; 5import org.springframework.web.bind.annotation.GetMapping; 6 7/** 8 * @author 公众号 程序员三时 9 * @version 1.0 10 * @date 2023/4/28 22:39 11 * @webSite https://github.com/coder-amiao 12 * 响应结果枚举 13 */ 14@Getter 15public enum ResultCodeEnum{ 16 SUCCESS(true, 200, "成功"), 17 FAIL(false, 400, "请求失败"), 18 19 NOT_FOUND(false, 404, "接口不存在"), 20 FORBIDDEN(false, 403, "资源拒绝访问"), 21 UNAUTHORIZED(false, 401, "未认证(签名错误)"), 22 23 INTERNAL_SERVER_ERROR(false, 500, "服务器内部错误"), 24 25 26 NULL_POINT(false, 200002, "空指针异常"), 27 PARAM_ERROR(false, 200001, "参数错误"); 28 29 /** 30 * 响应是否成功 31 */ 32 private Boolean success; 33 /** 34 * 响应状态码 35 */ 36 private Integer code; 37 /** 38 * 响应信息 39 */ 40 private String message; 41 42 43 ResultCodeEnum(Boolean success, Integer code, String message) { 44 this.success = success; 45 this.code = code; 46 this.message = message; 47 } 48} 49
统一结果类
- 外部返回调用类统一的结果方法
success,failure因此构造器私有 - 内置静态方法,直接返回对象
- 便于自定义统一结果信息,使用链式编程,返回对象类本身
return this - 响应数据为json格式,可定义为
JsonObject或Map形式
1package cn.soboys.springbootrestfulapi.common.resp; 2 3import lombok.Data; 4 5import java.util.HashMap; 6import java.util.Map; 7 8/** 9 * @author 公众号 程序员三时 10 * @version 1.0 11 * @date 2023/4/28 22:47 12 * @webSite https://github.com/coder-amiao 13 * 统一响应结果处理 使用链式编程 返回类本身 14 */ 15@Data 16public class R { 17 18 private Boolean success; 19 20 private Integer code; 21 22 private String message; 23 24 /** 25 * 接口请求时间戳 26 */ 27 private Long timestamp; 28 29 private Map<String, Object> data = new HashMap<>(); 30 31 32 private R setSuccess(Boolean success) { 33 this.success = success; 34 return this; 35 } 36 37 38 private R setMessage(String message) { 39 this.message = message; 40 return this; 41 } 42 43 private R setData(Map<String, Object> data) { 44 this.data = data; 45 return this; 46 } 47 48 private R setCode(Integer code) { 49 this.code = code; 50 return this; 51 } 52 53 private R() { 54 } 55 56 private R(Long timestamp) { 57 this.timestamp = timestamp; 58 } 59 60 61 /** 62 * 通用返回成功 63 * 64 * @return 65 */ 66 public static R success() { 67 return new R(System.currentTimeMillis()) 68 .setSuccess(ResultCodeEnum.SUCCESS.getSuccess()) 69 .setCode(ResultCodeEnum.SUCCESS.getCode()) 70 .setMessage(ResultCodeEnum.SUCCESS.getMessage()); 71 72 } 73 74 /** 75 * 通用返回失败 76 * 77 * @return 78 */ 79 public static R failure() { 80 return new R(System.currentTimeMillis()) 81 .setSuccess(ResultCodeEnum.FAIL.getSuccess()) 82 .setCode(ResultCodeEnum.FAIL.getCode()) 83 .setMessage(ResultCodeEnum.FAIL.getMessage()); 84 85 } 86 87 /** 88 * 设置结果,形参为结果枚举 89 * 90 * @param result 91 * @return 92 */ 93 public static R setResult(ResultCodeEnum result) { 94 return new R(System.currentTimeMillis()) 95 .setSuccess(result.getSuccess()) 96 .setCode(result.getCode()) 97 .setMessage(result.getMessage()); 98 99 } 100 101 102 // 自定义返回数据 103 public R data(Map<String, Object> map) { 104 return this.setData(map); 105 106 } 107 108 // 通用设置data 109 public R data(String key, Object value) { 110 this.data.put(key, value); 111 return this; 112 } 113 114 // 自定义状态信息 115 public R message(String message) { 116 return this.setMessage(message); 117 118 } 119 120 // 自定义状态码 121 public R code(Integer code) { 122 return this.setCode(code); 123 124 } 125 126 // 自定义返回结果 127 public R success(Boolean success) { 128 return this.setSuccess(success); 129 130 } 131 132} 133
控制层调用返回
1package cn.soboys.springbootrestfulapi.controller; 2 3 4import cn.soboys.springbootrestfulapi.common.resp.R; 5import org.springframework.web.bind.annotation.GetMapping; 6import org.springframework.web.bind.annotation.RestController; 7 8import java.util.HashMap; 9import java.util.Map; 10 11/** 12 * @author 公众号 程序员三时 13 * @version 1.0 14 * @date 2023/4/28 23:58 15 * @webSite https://github.com/coder-amiao 16 */ 17@RestController 18public class IndexController { 19 20 @GetMapping("/index") 21 public R index() { 22 Map m = new HashMap(); 23 m.put("name", "Tom"); 24 m.put("age", 25); 25 m.put("sex", "男"); 26 return R.success().data(m); 27 } 28 29 @GetMapping("/home") 30 public R home() { 31 32 Student s = new Student(); 33 s.setUserName("Tom"); 34 s.setBalance(2229891.0892); 35 return R.success().data("user", s).message("查询用户详情信息"); 36 } 37 38 /** 39 * 异常返回模拟 40 * 41 * @return 42 */ 43 @GetMapping("/exception") 44 public R exception() { 45 Map m = null; 46 m.put("name", "Jack"); 47 return R.success().data("user", m).message("查询用户详情信息"); 48 } 49} 50

统一结果类的使用参考了mybatis-plus中R对象的设计。
问题思考
使用统一返回结果时,还有一种情况,就是程序由于运行时异常导致的结果,有些异常我们可
能无法提前预知,不能正常走到我们return的R对象返回。
这个时候该如何处理

下一篇文章会继续分享,留下你的思考
准备从零做一套自己的开发脚手架模板 ,关注公众 程序员三时
