使用泛型定义统一结果返回类

为什么需要统一结果返回类

一般我们在开发项目时,每个接口要返回数据类型是不一样的,比如有些接口返回的是整数、有的返回的是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包下面:

java接口返回字段为null就不显示_java

其中包含了枚举类和统一返回类。

编写统一返回类

统一结果返回类的代码放在前面了

编写接口

最后在接口里使用统一结果返回类返回接口信息

public Result deleteLOg(@PathVariable Long blogID,HttpServletRequest request){
    ......代码
    if (条件)
        return Result.ok();
    else return Result.fail(remove);
}