前言
在每个项目中,都有自己的一套统一开发规范。比如API接口必须返回统一格式,比如实体对象必须继承指定的类等等。 好的设计可以让开发事半功倍,而坏的设计可能让开发感到很难受。
废话不多说,下面是本项目的设计。
具体实现
API统一返回类 ApiResult
最先应该设计的就是API的返回格式,如下:
@Slf4j
@Getter
@Setter
public class ApiResult<T> implements Serializable {
private static final long serialVersionUID = 2538767816320181885L;
protected Integer code;
protected T data;
protected String message;
public ApiResult() {
}
public ApiResult(Integer code) {
this(code, null, null);
}
public ApiResult(Integer code, T data) {
this(code, data, null);
}
public ApiResult(Integer code, T data, String message) {
this.code = code;
this.data = data;
this.message = message;
}
public static ApiResult success() {
return success(null);
}
public static <T> ApiResult<T> success(T data) {
ApiResult apiResult = withCode(ResultCode.SUCCESS);
apiResult.setData(data);
return apiResult;
}
public static ApiResult fail(String message) {
ApiResult apiResult = withCode(ResultCode.FAIL);
apiResult.setMessage(message);
return apiResult;
}
public static ApiResult withCode(ResultCode resultCode) {
return withCode(resultCode, null);
}
public static <T> ApiResult<T> withCode(ResultCode resultCode, T data) {
return new ApiResult(resultCode.getCode(), data, resultCode.getMessage());
}
}
所有的API接口返回类型必须为ApiResult,统一格式方便前端处理。使用如下:
@RestController
public class IndexController {
@GetMapping("/index")
public ApiResult<String> index() {
return ApiResult.success("Hello World");
}
}
调用成功的返回结果:
{
"code": 200,
"data": "Hello World",
"message": "成功"
}
调用失败的返回结果:
{
"code": 500,
"data": null,
"message": "失败"
}
API统一返回状态码 ResultCode
@Getter
@AllArgsConstructor
public enum ResultCode {
SUCCESS(200, "成功"),
FAIL(500, "失败"),
/* 参数错误:1000 - 1999 */
/* 用户错误:2000 - 2999 */
USER_NOT_LOGIN(2001, "用户未登录"),
/* 接口异常:3000 - 3999 */
;
private Integer code;
private String message;
}
当前状态码并没有完全,可以在开发功能的同时进行添加,当然在后期还可以做成动态可配置的。但是我们可以提前设计好错误类型的区间范围:
- 1000 - 1999 区间表示参数错误
- 2000 - 2999 区间表示用户错误
- 3000 - 3999 区间表示接口异常
这样前端开发人员根据状态码就大致能确定错误。
实体类基类 Common
@Getter
@Setter
public abstract class Common {
/**
* 创建人
*/
private String createUser;
/**
* 创建时间
*/
private Date createDateTime;
/**
* 修改人
*/
private String modifyUser;
/**
* 修改时间
*/
private Date modifyDateTime;
}
Common是所有实体类的基类,用于设置所有实体类的公共属性。
分页查询
分页查询在项目中是必不可少的,下面设计了分页查询条件基类和分页查询统一返回。
分页查询条件基类 Condition
@Getter
@Setter
public abstract class Condition {
/**
* 每页显示条数
*/
private int numPerPage = 20;
/**
* 当前页号
*/
private int pageNum = 1;
/**
* 排序字段
*/
private String orderField;
/**
* 排序方式,默认降序
*/
private String orderDirection = "desc";
}
分页查询统一返回 QueryResult
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class QueryResult<T> {
/**
* 总条数
*/
private Long total;
/**
* 返回结果集
*/
private List<T> items;
}
控制器基类 BaseController
public abstract class BaseController {
/**
* 获得当前用户编号
*/
public String getCurrentUserCode() {
//TODO 待实现
return null;
}
/**
* 设置创建信息
*/
public void setCreateInfo(Common common) {
common.setCreateUser(getCurrentUserCode());
common.setCreateDateTime(new Date());
setModifyInfo(common);
}
/**
* 设置修改信息
*/
public void setModifyInfo(Common common) {
common.setModifyUser(getCurrentUserCode());
common.setModifyDateTime(new Date());
}
}
业务异常 BusinessException
在项目中异常的设计尤为重要。 这里约定异常必须是BusinessException或者子类。方便后续对异常进行统一处理。
public class BusinessException extends RuntimeException {
public BusinessException(String message) {
super(message);
}
public BusinessException(String message, Throwable cause) {
super(message, cause);
}
}
总结
至此,一些基本的设计已经完成。不同的业务可能有不同的设计,但好的设计、适用的设计很重要。