使用泛型定义统一结果返回类
为什么需要统一结果返回类
一般我们在开发项目时,每个接口要返回数据类型是不一样的,比如有些接口返回的是整数、有的返回的是List等等,那么前端在解析不同的返回数据类型时就会很麻烦,为了解决这个问题,需要对返回结果进行统一的封装。通过定义一个通用的结果封装类,例如名为Result的泛型类,可以对接口返回的结果进行统一的封装。在统一用JSON的格式返回给前端,一般统一返回类包括状态码、信息、数据三个属性。
泛型
定义:允许在定义接口、类、方法时使用类型形参,类型形参在整个接口、类体、方法内可当成类型使用,这个类型形参将在声明变量、创建对象、调用方法时动态的制定(即传入实际的类型参数、类型实参)
枚举类
枚举类的特点:
- 是一种特殊的类,可以定义构造器、成员变量、普通方法和抽象方法
- 枚举类隐式继承了 java.lang.Enum 类,但不能显式继承其它父类
- 其构造器默认使用
private
修饰,一旦为枚举类显式定义了带参数的构造器,列出枚举值时就必须对应地传入参数 - 枚举类的所有实例必须在枚举类的第一行显式列出;列出这些实例时,系统会默认使用
public
static
final
修饰(全局静态常量);枚举值列举结束后以;
作为结束 - 枚举实例后有花括号时,该枚举实例是枚举类匿名内部子类的对象
代码
枚举类代码
@Getter
public enum ResultCodeEnum {
SUCCESS(200,"successful"),
FAIL(201, "fail"),
SERVICE_ERROR(2012, "service error"),
DATA_ERROR(204, "data error"),
ILLEGAL_REQUEST(205, "illegal request"),
REPEAT_SUBMIT(206, "repeat submit"),
ARGUMENT_VALID_ERROR(210, "argument valid error"),
LOGIN_AUTH(208, "未登陆"),
PERMISSION(209, "没有权限"),
ACCOUNT_ERROR(214, "账号不正确"),
PASSWORD_ERROR(215, "密码不正确"),
LOGIN_MOBLE_ERROR( 216, "账号不正确"),
ACCOUNT_STOP( 217, "账号已停用"),
NODE_ERROR( 218, "该节点下有子节点,不可以删除")
;
private Integer code;
private String message;
//构造器
private ResultCodeEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
}
统一返回类代码
@Data
public class Result<T>{
//返回码
private Integer code;
//返回消息
private String message;
//返回数据
private T data;
//私有的无参构造
private Result(){}
//静态方法,返回一个result示例,只设置实例的数据
public static <T> Result<T> build(T data){
Result<T> result = new Result<T>();
if (data != null)
result.setData(data);
return result;
}
//返回一个包含了数据、状态码、信息的返回类示例,方便我们在使用返回类时自定义这些信息
public static <T> Result<T> build(T body, Integer code, String message) {
Result<T> result = build(body);
result.setCode(code);
result.setMessage(message);
return result;
}
/**
操作成功
**/
public static <T> Result<T> ok(T data){
Result<T> result = build(data);
return build(data,ResultCodeEnum.SUCCESS);
}
//操作成功后不需要返回数据用
public static<T> Result<T> ok(){
return Result.ok(null);
}
public static <T> Result<T> fail(T data){
Result<T> result = build(data);
return build(data, ResultCodeEnum.FAIL);
}
public static<T> Result<T> fail(){
return Result.fail(null);
}
//这下面两个方法没有用static方法,属于对象实例的方法,可以链式编程
public Result<T> message(String msg){
this.setMessage(msg);
return this;
}
public Result<T> code(Integer code){
this.setCode(code);
return this;
}
}
解释一下代码,帮助理解:
私有构造器
//私有的无参构造
private Result(){}
使用private修饰构造器,将这个类的构造方法私有,于是别人就不能创建类的实例对象,只能使用类名调用ok()方法和fail()方法,当然,这两个方法都返回Result实例对象,所以以后就可以调用Result类的其他方法了。
static修饰静态方法
//返回一个包含了数据、状态码、信息的返回类示例,方便我们在使用返回类时自定义这些信息
public static <T> Result<T> build(T body, Integer code, String message) {
Result<T> result = build(body);
result.setCode(code);
result.setMessage(message);
return result;
}
拿这个方法举例,这个方法用了static修饰符,表名这个方法是一个静态方法,这里说明一下static修饰符:
static修饰的成员(类成员:类变量、类方法、静态初始化块、静态内部类)
- 随着所在类的加载而加载,优先于该类对象存在
- 被该类所有对象所共享
- 可以直接使用类名调用
static修饰的成员(属于类)不能直接访问没有static修饰的成员(属于对象)
注意static后面不加<T>会报错,个人理解原因如下:
static<T>表示声明这个方法为泛型方法,因为用static修饰的方法是属于类的,可以直接用类名调用,即不需要new一个对象就可以使用。
类型T是在new一个对象的时候确定的,没有new一个对象,就不确定类型,不确定类型,那么这个方法就会报错。
报错的内容大概是实例对象不能在静态上下文中使用
链式编程
//以下方法可以链式编程
public Result<T> message(String msg){
this.setMessage(msg);
return this;
}
public Result<T> code(Integer code){
this.setCode(code);
return this;
}
//静态方法,返回一个result示例,只设置实例的数据
public static <T> Result<T> build(T data){
Result<T> result = new Result<T>();
if (data != null)
result.setData(data);
return result;
}
这三个方法其实都是返回了实例,前两个方法返回了this,而this在这里表示的是一个Result对象实例
那么我们就可以有如下的编码方式:
result.build(list).message("信息")
表示先设置了数据data,再设置这个类的信息message。
使用步骤
编写枚举类
以个人项目为例,我会把返回相关的类放在utils包下面:
其中包含了枚举类和统一返回类。
编写统一返回类
统一结果返回类的代码放在前面了
编写接口
最后在接口里使用统一结果返回类返回接口信息
public Result deleteLOg(@PathVariable Long blogID,HttpServletRequest request){
......代码
if (条件)
return Result.ok();
else return Result.fail(remove);
}