SpringBoot统一接口返回的标准格式R.java
文章目录
01、分析
在后续我们会项目实战,项目实战一种前后端分离的开发方式。我们会通过swagger来进行接口测试。这个时候就会出现一个问题?
一个小团队:1~11人
大的开发团队:20+
- 每个开发者,对自己的代码都有一套自己的逻辑和哲学,返回值就千变万化。
- 带来的问题很明显,接口的调用者,就开始尝试一个错觉或者不明确的想象。
怎么办?
统一返回处理
格式如下
# 成功的状态
{
code:200,
data:{id:"1",name:"yykkk"},
message:"success"
}
# 失败
{
code:401,
data:"",
message:"用户名和账号有误"
}
{
code:500,
data:"",
message:"服务器出错!!"
}
02、封装统一返回的R类-基础封装认识
在企业中,有些公司命名:R.java、Result.java 、 ServerResponse 等。其实都是一个意思。
封装如下:
import lombok.Data;
/**
* # 成功的状态
* {
* code:200,
* data:{id:"1",name:"yykkk"},
* message:"success"
* }
*/
@Data
public class R {
// 返回的编号
private Integer code;
// 返回的数据,数据类型N中,
private Object data;
// 返回的信息
private String message;
}
使用如下:
@RestController
@Slf4j
public class RegController {
@Autowired
private RegService regService;
/**
* @Author xuke
* @Description 用户注册
* @Date 20:11 2021/6/23
* @Param []
* @return java.lang.String
**/
@GetMapping("/reg")
public R reguser(){
// 1: 注册用户 10ms
log.info("新用户注册");
//userService.save(user);
// 2: 发送短信 5s
log.info("发送短信");
regService.sendMsg();
// 3: 添加积分 5s
log.info("添加积分");
regService.addScore();
R r = new R();
r.setCode(200);
r.setData("ok");
r.setMessage("注册成功!");
return r;
}
}
启动
访问:http://localhost:9999/reg,结果如下:
{"code":200,"data":"ok","message":"注册成功!"}
问题:
频繁的创建R类,是不是有点不妥呢,第一会增加:内存开销,第二:代码臃肿和冗余。
03、封装统一返回的R类-静态方法封装
优化思考:
用静态方法方法去优化和封装,
开始优化
记住:在开发中成功只有一种情况,失败有N中情况。所有成功封装的逻辑是如下:
/**
* # 成功的状态
* {
* code:200,
* data:{id:"1",name:"yykkk"},
* message:"success"
* }
**/
@Data
public class R {
// 返回的编号
private Integer code;
// 返回的数据,数据类型N中,
private Object data;
// 返回的信息
private String message;
/**
* @return com.kuangstudy.common.R
* @Author xuke
* @Description 成功返回
* @Date 21:55 2021/6/23
* @Param []
**/
public static R success(Object data, String message) {
R r = new R();
r.setCode(200);
r.setData(data);
r.setMessage(message);
return r;
}
/**
* @return com.kuangstudy.common.R
* @Author xuke
* @Description 成功返回
* @Date 21:55 2021/6/23
* @Param []
**/
public static R success(Object data) {
return success(data, "");
}
}
启动
访问:http://localhost:9999/reg,结果如下:
{"code":200,"data":"ok","message":"注册成功!"}
解决的问题:
代码臃肿和冗余。
04、封装统一返回的R类-失败的封装
记住:在开发中成功只有一种情况,失败有N中情况。所有成功封装的逻辑是如下:
/**
* # 失败
* {
* code:401,
* data:"",
* message:"用户名和账号有误"
* }
**/
@Data
public class R {
// 返回的编号
private Integer code;
// 返回的数据,数据类型N中,
private Object data;
// 返回的信息
private String message;
/**
* @return com.kuangstudy.common.R
* @Author xuke
* @Description 成功返回
* @Date 21:55 2021/6/23
* @Param []
**/
public static R success(Object data, String message) {
R r = new R();
r.setCode(200);
r.setData(data);
r.setMessage(message);
return r;
}
/**
* @return com.kuangstudy.common.R
* @Author xuke
* @Description 成功返回
* @Date 21:55 2021/6/23
* @Param []
**/
public static R success(Object data) {
return success(data, "");
}
/**
* @return com.kuangstudy.common.R
* @Author xuke
* @Description
* @Date 22:03 2021/6/23
* @Param [code 失败的状态, message 失败的原因]
**/
public static R fail(Integer code, String message) {
R r = new R();
r.setCode(code);
r.setData(null);
r.setMessage(message);
return r;
}
}
测试如下:
@GetMapping("/reg2")
public R reguser2(Integer flag) {
if (flag.equals(1)) {
return R.fail(401, "用户名和密码错误!!!");
}
if (flag.equals(2)) {
return R.fail(402, "密码和确认密码不一致!!!");
}
// 1: 注册用户 10ms
log.info("新用户注册");
//userService.save(user);
// 2: 发送短信 5s
log.info("发送短信");
regService.sendMsg();
// 3: 添加积分 5s
log.info("添加积分");
regService.addScore();
return R.success("ok");
}
测试结果:
http://localhost:9999/reg2?flag=0 正常返回
{"code":200,"data":"ok","message":""}
http://localhost:9999/reg2?flag=1 失败返回
{"code":401,"data":null,"message":"用户名和密码错误!!!"}
http://localhost:9999/reg2?flag=2 正常返回
{"code":402,"data":null,"message":"密码和确认密码不一致!!!"}
05、封装统一返回的R类-把构造函数私有化
为什么要要构造函数私有化呢?
答案:当调用的过程变得单一,只允许用用类去调用方法,不允许用new去调用。
@Data
public class R {
// 返回的编号
private Integer code;
// 返回的数据,数据类型N中,
private Object data;
// 返回的信息
private String message;
private R (){
}
/**
* @return com.kuangstudy.common.R
* @Author xuke
* @Description 成功返回
* @Date 21:55 2021/6/23
* @Param []
**/
public static R success(Object data, String message) {
R r = new R();
r.setCode(200);
r.setData(data);
r.setMessage(message);
return r;
}
/**
* @return com.kuangstudy.common.R
* @Author xuke
* @Description 成功返回
* @Date 21:55 2021/6/23
* @Param []
**/
public static R success(Object data) {
return success(data, "");
}
/**
* @return com.kuangstudy.common.R
* @Author xuke
* @Description
* @Date 22:03 2021/6/23
* @Param [code 失败的状态, message 失败的原因]
**/
public static R fail(Integer code, String message) {
R r = new R();
r.setCode(code);
r.setData(null);
r.setMessage(message);
return r;
}
}
06、封装统一返回的R类-统一返回状态的维护和message的维护问题
如下代码,如果在实际的开发和生产中,这样的编写的话,肯定是会技术leader骂死的,一般早期可以为了完成任务或者业务,可能这样写是没问题。但是随着团队和业务越来越复杂。下面这个就一定要进行统一处理。(集中管理)
if (flag.equals(1)) {
return R.fail(401, "用户名和密码错误!!!");
}
if (flag.equals(2)) {
return R.fail(402, "密码和确认密码不一致!!!");
}
集中管理的解决方案
1:用接口或者常量类:比如
public class RConstants {
// 用户名和密码错误信息和状态
public static final Integer USER_REG_USER_PASSWORD_CODE = 401;
public static final String USER_REG_USER_PASSWORD_ERROR = "用户名和密码错误!";
// 密码和确认密码错误信息和状态
public static final Integer USER_REG_USER_PASSWORD_CONFIRM_CODE = 402;
public static final String USER_REG_USER_PASSWORD_CONFIRM_ERROR = "密码和确认密码不一致!";
}
if (flag.equals(1)) {
return R.fail(RConstants.USER_REG_USER_PASSWORD_CODE,RConstants.USER_REG_USER_PASSWORD_ERROR);
}
if (flag.equals(2)) {
return R.fail(RConstants.USER_REG_USER_PASSWORD_CONFIRM_CODE,RConstants.USER_REG_USER_PASSWORD_CONFIRM_ERROR);
}
通过常量类:其实并不明确,当我们的错误状态和信息越来越多的时候,这个它的可维护就出现很多问题。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KLiweuFl-1653404158205)(assets/1624457916519.png)]
2:使用枚举
/**
* @description: 统一返回的常量类
* 对内修改开放,对外修改关闭---枚举
* @author: xuke
* @time: 2021/6/23 22:12
*/
public enum ResponseEnum {
USER_REG_USER_PASSWORD_CODE(401,"用户名和密码错误"),
USER_REG_USER_PASSWORD_CONFIRM(402,"密码和确认密码不一致");
private Integer code;
private String message;
ResponseEnum(Integer code,String mesage){
this.code = code;
this.message =mesage;
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
}
修改如下:
if (flag.equals(1)) {
return R.fail(ResponseEnum.USER_REG_USER_PASSWORD_CODE.getCode(),
ResponseEnum.USER_REG_USER_PASSWORD_CODE.getMessage());
}
if (flag.equals(2)) {
return R.fail(ResponseEnum.USER_REG_USER_PASSWORD_CONFIRM.getCode(),
ResponseEnum.USER_REG_USER_PASSWORD_CONFIRM.getMessage());
}
07、封装统一返回的R类-统一枚举的最终方案
@Data
public class R {
// 返回的编号
private Integer code;
// 返回的数据,数据类型N中,
private Object data;
// 返回的信息
private String message;
private R() {
}
/**
* @return com.kuangstudy.common.R
* @Author xuke
* @Description 成功返回
* @Date 21:55 2021/6/23
* @Param []
**/
public static R success(Object data, String message) {
R r = new R();
r.setCode(ResponseEnum.SUCCESS.getCode());
r.setData(data);
r.setMessage(message == null ? ResponseEnum.SUCCESS.getMessage() : message);
return r;
}
/**
* @return com.kuangstudy.common.R
* @Author xuke
* @Description 成功返回
* @Date 21:55 2021/6/23
* @Param []
**/
public static R success(Object data) {
return success(data, null);
}
/**
* @return com.kuangstudy.common.R
* @Author xuke
* @Description
* @Date 22:03 2021/6/23
* @Param [code 失败的状态, message 失败的原因]
**/
public static R fail(Integer code, String message) {
R r = new R();
r.setCode(code);
r.setData(null);
r.setMessage(message);
return r;
}
/**
* @return com.kuangstudy.common.R
* @Author xuke
* @Description
* @Date 22:03 2021/6/23
* @Param [code 失败的状态, message 失败的原因]
**/
public static R fail(ResponseEnum responseEnum) {
R r = new R();
r.setCode(responseEnum.getCode());
r.setData(null);
r.setMessage(responseEnum.getMessage());
return r;
}
}
传递枚举引用
package com.kuangstudy.common;
/**
* @description: 统一返回的常量类
* 对内修改开放,对外修改关闭---枚举
* @author: xuke
* @time: 2021/6/23 22:12
*/
public enum ResponseEnum {
SUCCESS(200,"成功!"),
USER_REG_USER_PASSWORD_CODE(401,"用户名和密码错误"),
USER_REG_USER_PASSWORD_CONFIRM(402,"密码和确认密码不一致"),
ORDER_FAIL(601,"订单失败"),
ORDER_MESSAGE_FAIL(602,"订单发送消息失败") ;
private Integer code;
private String message;
ResponseEnum(Integer code,String mesage){
this.code = code;
this.message =mesage;
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
}
调用
/**
* @return java.lang.String
* @Author xuke
* @Description 用户注册
* @Date 20:11 2021/6/23
* @Param []
**/
@GetMapping("/reg2")
public R reguser2(Integer flag) {
if (flag.equals(1)) {
return R.fail(ResponseEnum.USER_REG_USER_PASSWORD_CODE);
}
if (flag.equals(2)) {
return R.fail(ResponseEnum.USER_REG_USER_PASSWORD_CONFIRM);
}
// 1: 注册用户 10ms
log.info("新用户注册");
//userService.save(user);
// 2: 发送短信 5s
log.info("发送短信");
regService.sendMsg();
// 3: 添加积分 5s
log.info("添加积分");
regService.addScore();
return R.success("ok");
}
08、统一返回的参考来源
参考:
1、mybatis-plus–R类
2、springmvc中有一个:ResponseEntity和HttpStatus一个枚举类,如下:
@GetMapping("/reg2")
public ResponseEntity reguser2(Integer flag) {
// 1: 注册用户 10ms
log.info("新用户注册");
//userService.save(user);
// 2: 发送短信 5s
log.info("发送短信");
regService.sendMsg();
// 3: 添加积分 5s
log.info("添加积分");
regService.addScore();
// 这是失败的
//return ResponseEntity.status(HttpStatus.BAD_GATEWAY);
// 这是成功
return ResponseEntity.ok("success");
}
为什么在开发中,我们不使用springMvc提供好的,还多此一举自己的去定义和实现一个R和一个枚举呢?
答案:
-
因为springmvc这些满足不了我们的业务开发需求
-
还有里面的状态的控制和返回,都和业务可能没有什么太大匹配关系。不明确