前言
在移动互联网,分布式、微服务盛行的今天,现在项目绝大部分都采用的微服务框架,前后端分离方式,前后端的工作职责越来越明确。前端和后端进行交互,前端按照约定请求URL路径,并传入相关参数,后端服务器接收请求,进行业务处理,返回数据给前端。
API 接口设计
项目开发中,一般情况下都会对数据返回的格式做一个统一的要求,一般会包括状态码、信息及数据三部分。定义通用返回对象可以在原返回的数据基础上封装一层,将状态码等信息包含进来。后端返回给前端我们一般用JSON体方式,定义如下:
public class AjaxResult {
// 是否响应成功
private Boolean success;
// 响应状态码
private Integer code;
// 提示信息
private String msg;
// 响应数据
private Object data;
// 其他标识符(服务器当前时间、访问url、错误类型、错误的堆栈轨迹)
private Map<String,Object> extraInfo;
}
2.1 自定义返回状态码
我们可以参考HTTP请求返回的状态码这样的设计,这样的好处就把错误类型归类到某个区间内,前端开发人员在得到返回值后,根据状态码就可以知道,大概什么错误,再根据message相关的信息描述,可以快速定位。
@Getter
@AllArgsConstructor
public enum ResultCode {
/** 成功状态码 */
SUCCESS(200, "操作成功"),
/** 失败状态码 */
FAILURE(500, "操作失败"),
/**
* 参数错误:10001-19999
*/
PARAM_IS_INVALID(10001, "参数无效"),
PARAM_IS_BLANK(10002, "参数为空"),
PARAM_TYPE_BIND_ERROR(10003, "参数类型错误"),
PARAM_NOT_COMPLETE(10004, "参数缺失"),
/**
* 用户错误:20001-29999
*/
USER_NOT_LOGGED_IN(20001, "用户未登录,访问的路径需要验证,请登录"),
USER_LOGIN_ERROR(20002, "账号不存在或密码错误"),
USER_ACCOUNT_FORBIDDEN(20003, "账号已被禁用"),
USER_NOT_EXIST(20004, "用户不存在"), USER_HAS_EXISTED(20005, "用户已存在"),
/**
* 业务错误:30001-39999
*/
SPECIFIED_QUESTIONED_USER_NOT_EXIST(30001, "某业务出现问题"),
/**
* 系统错误:40001-49999
*/
SYSTEM_INNER_ERROR(40001, "系统繁忙,请稍后重试"),
UNKNOWN_ERROR(40002,"未知错误"),
/**
* 数据错误:50001-599999
*/
RESULE_DATA_NONE(50001, "数据未找到"),
DATA_IS_WRONG(50002, "数据有误"),
DATA_ALREADY_EXISTED(50003, "数据已存在"),
/**
* 接口错误:60001-69999
*/
INTERFACE_INNER_INVOKE_ERROR(60001, "内部系统接口调用异常"),
INTERFACE_OUTTER_INVOKE_ERROR(60002, "外部系统接口调用异常"),
INTERFACE_FORBID_VISIT(60003, "该接口禁止访问"),
INTERFACE_ADDRESS_INVALID(60004, "接口地址无效"),
INTERFACE_REQUEST_TIMEOUT(60005, "接口请求超时"),
INTERFACE_EXCEED_LOAD(60006, "接口负载过高"),
/**
* 权限错误:70001-79999
*/
PERMISSION_NO_ACCESS(70001, "无访问权限");
private Integer code;
private String message;
public Integer getCode(String name) {
for (ResultCode item : ResultCode.values()) {
if (item.name().equals(name)) {
return item.code;
}
}
return null;
}
public String getMessage(String name) {
for (ResultCode item : ResultCode.values()) {
if (item.name().equals(name)) {
return item.message;
}
}
return name;
}
}
public interface ResultCode {
/** 请求t成功 */
public static Integer SUCCESS = 200;
/** 请求table成功 */
public static Integer TABLE_SUCCESS = 0;
/** 请求失败 */
public static Integer ERROR = 201;
/** 请求已经被接受 */
public static final Integer ACCEPTED = 202;
/** 操作已经执行成功,但是没有返回数据 */
public static final Integer NO_CONTENT = 204;
/** 资源已被移除 */
public static final Integer MOVED_PERM = 301;
/** 重定向 */
public static final Integer SEE_OTHER = 303;
/** 资源没有被修改 */
public static final Integer NOT_MODIFIED = 304;
/** 参数列表错误(缺少,格式不匹配)*/
public static final Integer BAD_REQUEST = 400;
/** 未授权 */
public static final Integer UNAUTHORIZED = 401;
/** 访问受限,授权过期 */
public static final Integer FORBIDDEN = 403;
/** 资源,服务未找到 */
public static final Integer NOT_FOUND = 404;
/** 不允许的http方法 */
public static final Integer BAD_METHOD = 405;
/** 资源冲突,或者资源被锁 */
public static final Integer CONFLICT = 409;
/** 不支持的数据,媒体类型 */
public static final Integer UNSUPPORTED_TYPE = 415;
/** 接口未实现 */
public static final Integer NOT_IMPLEMENTED = 501;
}
2.2 返回的结果封装类
注意:
- 外接只可以调用统一返回类的方法,不可以直接创建,因此构造器私有。
- 内置静态方法,返回对象。
- 为便于自定义统一结果的信息,建议使用链式编程,将返回对象设类本身,即return this。
- 响应数据由于为json格式,可定义为JsonObject或Map形式。
import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public final class RestResult implements Serializable {
private static final long serialVersionUID = 2201399824548851402L;
/** 服务器当前时间(添加该字段的原因是便于查找定位请求时间,因为实际开发过程中服务器时间可能跟本地时间不一致,加上这个时间戳便于日后定位) */
private String currentTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now());
/** 返回结果编码 */
private Integer resultCode = ResultCode.SUCCESS.getCode();
/** 返回的数据息 */
private Object data;
/** 请求返回的提示信息,给前端进行页面展示的信息 */
private String message = "操作成功";
/** 额外参数,不使用Map<String, Object>防止JSON解析时过于复杂 */
private Map<String, Object> extraInfo = new HashMap<String, Object>();
/**
* 构造器私有
*/
private RestResult() {
super();
}
/**
* 构造器私有
*/
private RestResult(ResultCode resultCode) {
super();
this.resultCode = resultCode.getCode();
this.message = resultCode.getMessage();
}
/**
* 构造器私有
*/
public RestResult(String message, Object data, Map<String, Object> extraInfo) {
super();
this.message = message;
this.data = data;
this.extraInfo = extraInfo;
}
/**
* @方法描述: 添加返回数据
*
* @param key
* @param value
*/
public void setData(String key, Object value) {
extraInfo.put(key, value);
}
/**
* @方法描述: 可以连接追加调用此方法,添加返回数据
*
* @param key
* @param value
* @return
*/
public RestResult add(String key, Object value) {
extraInfo.put(key, value);
return this;
}
/**
* @方法描述: 返回执行成功,不返回数据直接返回成功信息
* @return
*/
public static RestResult success() {
return new RestResult();
}
/**
* @方法描述: 返回执行成功,返回数据
* @param message 自定义成功提示信息
* @param data 自定义返回数据
* @return
*/
public static RestResult success(String message, Object data) {
return new RestResult(message, data, null);
}
/**
* @方法描述: 返回执行成功,返回数据
* @param message 自定义成功提示信息
* @return
*/
public static RestResult success(Object data) {
return new RestResult(null, data, null);
}
/**
* @方法描述: 成功返回执行成功,返回数据并返回额外参数
* @param data 自定义返回数据
* @param extraInfo 额外参数
* @return
*/
public static RestResult success(Object data, Map<String, Object> extraInfo) {
return new RestResult(null, data, extraInfo);
}
/**
* @方法描述:返回执行成功,返回数据并返回额外参数
* @param message 自定义成功提示信息
* @param data 自定义返回数据
* @param extraInfo 额外参数
* @return
*/
public static RestResult success(String message, Object data, Map<String, Object> extraInfo) {
return new RestResult(message, data, extraInfo);
}
/**
* @方法描述:返回执行失败
* @return
*/
public static RestResult fail() {
return new RestResult(ResultCode.FAILURE);
}
/**
* @方法描述:返回失败的消息
* @param message 自定义失败原因
* @return
*/
public static RestResult fail(String message) {
RestResult restResult = new RestResult(ResultCode.FAILURE);
restResult.setMessage(message);
return restResult;
}
/**
* @方法描述:返回错误消息
* @param resultCode
* @return
*/
public static RestResult fail(ResultCode resultCode) {
return new RestResult(resultCode);
}
/**
* @方法描述:返回失败的状态码以及数据
* @param resultCode
* @param message 自定义失败原因
* @return
*/
public static RestResult fail(int resultCode, String message) {
RestResult restResult = new RestResult();
restResult.setResultCode(resultCode);
restResult.setMessage(message);
return restResult;
}
/**
* @方法描述:返回失败的状态码以及数据
* @param resultCode
* @param message 自定义失败原因
* @param data 自定义返回数据
* @return
*/
public static RestResult fail(int resultCode, String message, Object data) {
RestResult restResult = new RestResult();
restResult.setResultCode(resultCode);
restResult.setMessage(message);
restResult.setData(data);
return restResult;
}
/**
* @方法描述:返回失败的状态码以及数据
* @param resultCode
* @param data 自定义返回数据
* @return
*/
public static RestResult fail(ResultCode resultCode, Object data) {
RestResult restResult = new RestResult(resultCode);
restResult.setData(data);
return restResult;
}
/**
* @方法描述:失败,自定义失败返回状态并返回数据、额外参数
* @param resultCode
* @param data 自定义返回数据
* @param extraInfo
* @return
*/
public static RestResult fail(ResultCode resultCode, Object data, Map<String, Object> extraInfo) {
RestResult restResult = new RestResult(resultCode);
restResult.setData(data);
restResult.setExtraInfo(extraInfo);
return restResult;
}
}
2.3 控制层例子
@GetMapping("getUserInfoById")
public Result getUserInfoById(@PathVariable("id") Integer id){
if(id.equals(0) ){
return Result.fail(ResultCode.FAILURE);
} else {
return Result.success(userService.getUser(id));
}
}
2.4 返回结果
// 成功
{
"code":200,
"message":"成功",
"data":{
"id":1,
"name":"dllwh"
}
}
// 失败
{
"code":0,
"message":"失败",
"data":null
}
小结
把今天最好的表现当作明天最新的起点…….~
投身于天地这熔炉,一个人可以被毁灭,但绝不会被打败!一旦决定了心中所想,便绝无动摇。迈向光明之路,注定荆棘丛生,自己选择的路,即使再荒谬、再艰难,跪着也要走下去!放弃,曾令人想要逃离,但绝境重生方为宿命。若结果并非所愿,那就在尘埃落定前奋力一搏!