SpringBoot解决方案之 统一接口封装

什么是 REST?

REST 是 REpresentational State Transfer 的首字母缩写,是****分布式超媒体系统的一种架构风格 。罗伊菲尔丁于 2000 年在他著名的 论文中首次提出它。

与其他架构风格一样,REST 有其指导原则和约束。如果需要将服务接口称为RESTful,则必须满足这些原则 。

面向资源是 REST 最明显的特征,对于同一个资源的一组不同的操作。资源是服务器上一个可命名的抽象概念,资源是以名词为核心来组织的,首先关注的是名词。REST 要求,必须通过统一的接口来对资源执行各种操作。对于每个资源只能执行一组有限的操作。

什么是 RESTful API?

符合 REST 设计标准的 API,即 RESTful API。REST 架构设计,遵循的各项标准和准则,就是 HTTP 协议的表现,换句话说,HTTP 协议就是属于 REST 架构的设计模式。比如,无状态,请求-响应。

为什么要统一封装接口

现在大多数项目采用前后分离的模式进行开发,统一返回方便前端进行开发和封装,以及出现时给出响应编码和信息。

以查询某个用户接口而言,如果没有封装, 返回结果如下

1
2
3
4
5
{
"userId": 101,
"userName": "czk"
}

如果封装了,返回正常的结果如下:

1
2
3
4
5
6
7
8
9
{
"timestamp": 123456789,
"status": 200,
"message": "success",
"data": {
"userId": 101,
"userName": "czk"
}
}

异常返回结果如下:

1
2
3
4
5
6
{
"timestamp": 123456789,
"status": 10001,
"message": "出错啦!",
"data": null
}

实现案例

如何实现上面的封装呢?

状态码封装

这里以常见的状态码为例,包含 code 和 description 两个属性。

如果还有其它业务状态码,也可以放到这个类中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@Getter
@AllArgsConstructor
@ToString
public enum ResponseEnum {
SUCCESS(0, "成功"),
ERROR(-1, "服务器内部错误"),
//-1xx 服务器错误
BAD_SQL_GRAMMAR_ERROR(-101, "sql语法错误"),
SERVLET_ERROR(-102, "servlet请求异常"), //-2xx 参数校验
UPLOAD_ERROR(-103, "文件上传错误"),
EXPORT_DATA_ERROR(104, "数据导出失败"),

//-2xx 参数校验
BORROW_AMOUNT_NULL_ERROR(-201, "借款额度不能为空"),
MOBILE_NULL_ERROR(-202, "手机号码不能为空"),
MOBILE_ERROR(-203, "手机号码不正确"),
PASSWORD_NULL_ERROR(204, "密码不能为空"),
CODE_NULL_ERROR(205, "验证码不能为空"),
CODE_ERROR(206, "验证码错误"),
MOBILE_EXIST_ERROR(207, "手机号已被注册"),
LOGIN_MOBILE_ERROR(208, "用户不存在"),
LOGIN_PASSWORD_ERROR(209, "密码错误"),
LOGIN_LOKED_ERROR(210, "用户被锁定"),
LOGIN_AUTH_ERROR(-211, "未登录"),
PARAM_NULL_ERROR(212, "参数不能为空"),


USER_BIND_IDCARD_EXIST_ERROR(-301, "身份证号码已绑定"),
USER_NO_BIND_ERROR(302, "用户未绑定"),
USER_NO_AMOUNT_ERROR(303, "用户信息未审核"),

PAY_UNIFIEDORDER_ERROR(401, "统一下单错误"),

ALIYUN_RESPONSE_FAIL(-501, "阿里云响应失败"),
ALIYUN_SMS_LIMIT_CONTROL_ERROR(-502, "短信发送过于频繁"),//业务限流
ALIYUN_SMS_ERROR(-503, "短信发送失败"),//其他失败

WEIXIN_CALLBACK_PARAM_ERROR(-601, "回调参数不正确"),
WEIXIN_FETCH_ACCESSTOKEN_ERROR(-602, "获取access_token失败"),
WEIXIN_FETCH_USERINFO_ERROR(-603, "获取用户信息失败"),

private Integer code;
private String message;
}

返回内容封装

包含公共的接口返回时间,状态 code, 消息message, 以及数据data。

考虑到数据的序列化(比如在网络上传输),这里 data 有时候还会extends Serializable 还可以采用泛型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
@Data
public class R {

private Integer code;

private String message;

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

private R(){};

/**
*成功结果
* @return
*/
public static R ok(){
R r = new R();
r.setCode(ResponseEnum.SUCCESS.getCode());
r.setMessage(ResponseEnum.SUCCESS.getMessage());
return r;
}

/**
* 失败结果
* @return
*/
public static R error(){
R r = new R();
r.setCode(ResponseEnum.ERROR.getCode());
r.setMessage(ResponseEnum.ERROR.getMessage());
return r;
}
/**
* 设置特定结果
*/
public static R setResult(ResponseEnum responseEnum){
R r = new R();
r.setCode(responseEnum.getCode());
r.setMessage(responseEnum.getMessage());
return r;
}

public R data(String key,Object value){
this.getData().put(key, value);
return this;
}

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

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

public R message(String msg){
this.setMessage(msg);
return this;
}
}