likes
comments
collection
share

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

作者站长头像
站长
· 阅读数 20

今日话题

基于 Spring Boot 优化枚举重构,完善 Result 失败方法

作者:云层上的光

时间:2024年7月12日 13时46分14秒

主线任务

优化枚举重构,完善 Result 失败方法依旧在 demo-todo-list 中实现~

一、完善 Result 失败方法

1、改造 common/result 软件包下的 Result 类文件

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

代码如下:

package com.chuxin.demotodolist.common.result;
import lombok.Data;
import java.io.Serializable;

@Data
public class Result<T> implements Serializable {
    // 定义要返回的格式
    private int code;
    private T data;
    private String msg;

    // 定义失败的无参构造
    public static <T> Result<T> failed() {
        Result<T> result = new Result<>();
        result.setCode(201);
        result.setData(null);
        result.setMsg("操作失败");
        return result;
    }
    // 定义失败方法的有参构造
    public static <T> Result<T> failed(int code, String msg, T data) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setData(data);
        result.setMsg(msg);
        return result;
    }
}

2、改造 controller 中 UserController 类文件,增加 test 方法

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

代码如下:

package com.chuxin.demotodolist.controller;

import com.chuxin.demotodolist.common.result.Result;
import com.chuxin.demotodolist.entity.User;
import com.chuxin.demotodolist.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    // 测试
    @GetMapping("/failedTest")
    public Result test() {
        // 调用的 Result.failed ,这里调用的是 failed无参构造方法~
        return Result.failed();
    }
}

3、启动项目

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

4、浏览器访问:http://localhost:8080/user/failedTest

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

二、枚举重构

程序代码中痛恨别人写的魔法数字,但是实际项目自己的魔法数字没少写~

1、common/result 软件包下的新建 ResultCode 枚举文件

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

2、改造 ResultCode 枚举文件,适配接口返回~

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

代码如下:

package com.chuxin.demotodolist.common.result;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@AllArgsConstructor
@NoArgsConstructor
public enum ResultCode implements Serializable {
    SUCCESS(200, "操作成功"), ERROR(201, "操作失败");

    private int code;
    private String msg;
}

3、枚举类中 code 和 msg 一般不需要 Setter 方法,所以此处不采用 @Data 生成 code 和 msg 的 Setter 方法,手动生成 Getter 方法~

getValue 等价前端数组 find 方法~ 用来拓展获取值~

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

代码如下:

package com.chuxin.demotodolist.common.result;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@AllArgsConstructor
@NoArgsConstructor
public enum ResultCode implements Serializable {
    // 此处 code 200 201 为演示随意写的 不适用真实项目取值~
    SUCCESS(200, "操作成功"), ERROR(201, "操作失败");

    private int code;
    private String msg;

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
    // 获取value值,此处的操作和数组 find 一个功能,找到了就返回 没找到就 走 ERROR 这个枚举 不过 js 是 undefined
    public static ResultCode getValue(int code) {
        for (ResultCode value : values()) {
            if (value.getCode().equals(code)) {
                return value;
            }
        }
        return ERROR; // 默认系统执行错误
    }
}

4、启动项目

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

5、终端报错:java: 无法取消引用int

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

6、点击 Ctrl + 鼠标左键 进入到报错文件中

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

7、由于定义的 code 是 int 类型,而 equals 是校验字符串类型的,此处修改为 == 修复问题~

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

代码如下:

package com.chuxin.demotodolist.common.result;

import java.io.Serializable;

public enum ResultCode implements Serializable {

    // 获取value值,此处的操作和数组 find 一个功能,找到了就返回 没找到就 走 ERROR 这个枚举 不过 js 是 undefined
    public static ResultCode getValue(int code) {
        for (ResultCode value : values()) {
            // 先换成 ==  或者把 code 修改为 String 类型
            if (value.getCode() == code) {
                return value;
            }
        }
        return ERROR; // 默认系统执行错误
    }
}

8、改造 common/result 软件包下的 Result 类文件,消除魔法数字

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

代码如下:

package com.chuxin.demotodolist.common.result;
import lombok.Data;
import java.io.Serializable;

@Data
public class Result<T> implements Serializable {
    // 定义要返回的格式
    private int code;
    private T data;
    private String msg;
    // 增加 result 方法 简化 failed 的无参构造和有参构造方法的代码量
    private static <T> Result<T> result(int code, String msg, T data) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setData(data);
        result.setMsg(msg);
        return result;
    }
    // 定义失败的无参构造
    public static <T> Result<T> failed() {
        // 利用枚举消除魔法值
        return result(ResultCode.ERROR.getCode(), ResultCode.ERROR.getMsg(), null);
    }
}

9、重启项目,浏览器访问:http://localhost:8080/user/failedTest

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

10、使用枚举消除剩余魔法值

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

11、重启项目,浏览器访问:http://localhost:8080/user/getList?page=1&pageSize=10

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

三、接口类 完成 ResultCode 适配

1、真实项目中,希望出现 code 就需要百分百存在 msg,所以我们可以尝试增加接口来进行约束

提示:当然话不能说太满了,根据业务而定~

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

2、common/result 软件包下的新建 IResultCode 接口文件

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

3、改造 common/result 软件包下的新建 IResultCode 接口文件

我们不是实体类,不需要描述code msg 这些属性,这里希望约束 ResultCode 中必须要存在

getCode 和 getMsg ,这是因为业务中使用 枚举使用的是 getCode 进行调用~

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

代码如下:

package com.chuxin.demotodolist.common.result;

public interface IResultCode {
    // 描述 code Getter 方法
    int getCode();
    // 描述 msg Getter 方法
    String getMsg();
}

4、改造 common/result 软件包下的新建 ResultCode 枚举文件

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

代码如下:

package com.chuxin.demotodolist.common.result;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@AllArgsConstructor
@NoArgsConstructor
public enum ResultCode implements IResultCode,Serializable {
    // 此处 code 200 201 为演示随意写的 不适用真实项目取值~
    SUCCESS(200, "操作成功"), ERROR(201, "操作失败");

    private int code;
    private String msg;

    @Override
    public int getCode() {
        return code;
    }

    @Override
    public String getMsg() {
        return msg;
    }

}

5、通过接口进行约束,完成对 getCode 和 getMsg 方法的重写

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

6、有了接口,在消费层消费 枚举时就更安全,虽然编辑器会自动检测,但是希望养成好习惯编写好的代码~

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

支线任务

一、Result 其他方法拓展

1、重构 failed 方法,增加 result 方法,简化代码~

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

2、重启项目,浏览器访问:http://localhost:8080/user/failedTest

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

3、增强 failed 方法传参业务场景

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

代码如下:

package com.chuxin.demotodolist.common.result;
import lombok.Data;
import java.io.Serializable;

@Data
public class Result<T> implements Serializable {
    // 定义要返回的格式
    private int code;
    private T data;
    private String msg;
    // 增加 result 方法 简化 failed 的无参构造和有参构造方法的代码量
    private static <T> Result<T> result(int code, String msg, T data) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setData(data);
        result.setMsg(msg);
        return result;
    }
    // 定义失败方法只传msg
    public static <T> Result<T> failed(String msg) {
        return result(201, msg, null);
    }
    // 定义失败方法只传code 和 msg
    public static <T> Result<T> failed(int code, String msg) {
        return result(code, msg, null);
    }
}

4、总结:

其实说白了就是多增加不同的调用方法~

二、枚举重构相关思考

1、枚举在前端历史中一直是 const 的角色在扮演,知道 ts 的出现

const SUCCESS_CODE = 200;
const SRCCESS_MSG = "操作成功"

const ERROR_CODE = 201
const ERROR_MSG = "操作失败"

2、这是由于 const 定义的变量不能修改

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

3、js 引用类型就不太好约束了

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

代码如下:

const ERROR = {
  CODE: 200,
  MSG: "操作成功"
}
// 修改 CODE
ERROR.CODE = 0

// 修改 ERROR
ERROR = {} // 报错: TypeError: Assignment to constant variable.

4、那么 Java 中是怎么实现常量的呢?

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

5、改造 controller 软件包下的 ResultCode 类

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

代码如下:

package com.chuxin.demotodolist.controller;

public class ResultCode {
    public static final int SUCCESS_CODE = 200;
    public static final String SUCCESS_MSG = "操作成功";
    public static final int ERROR_CODE = 201;
    public static final String ERROR_MSG = "操作失败";
}

6、改造 controller 软件包 UserController 类文件

值得注意的 ResultCode 是当前 controller 软件包下,所以他们的 package 定义的也是相同

所以在上面的 import 引用中 找不到 import 引用 这是应该同一包下可以直接使用

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

7、启动项目,浏览器访问:http://localhost:8080/user/failedTest

这里 code 等于200 是应该上面代码中传入的是 SUCCESS_CODE

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

8、不过上面提到 ts 中也实现了枚举

ERROR[ERROR["CODE"] = 0] = "CODE"; 乍一看有点懵,拆开就简单了

  • 首先 ERROR 是一个对象

  • 会先执行 ERROR["CODE"] = 0 然后这个赋值结果会直接返回 0

  • 就会走到 ERROR[0] = "CODE"

  • 访问: ERROR.CODE 返回 0

  • 访问:ERROR[0] 返回 "CODE"

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

代码如下:

// ts 中 如果不给值 就是默认下标 index 从0开始 (这里不过多介绍)
enum ERROR { 
  CODE,
  MSG
}

9、Java 中实现 ts 的 enum 枚举

单纯作为演示,在 controller 中创建~

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

10、改造 controller 软件包 ResultEnum 枚举文件

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

代码如下:

package com.chuxin.demotodolist.controller;

public enum ResultEnum {
    SUCCESS_CODE,  ERROR_CODE;
}

11、改造 controller 软件包 UserController 类文件

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

代码如下:

package com.chuxin.demotodolist.controller;

import com.chuxin.demotodolist.common.result.Result;
import com.chuxin.demotodolist.entity.User;
import com.chuxin.demotodolist.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    // 测试
    @GetMapping("/failedTest")
    public Result test() {
        // return Result.failed();
        // 这里打印看能取到值么
        System.out.println(ResultEnum.SUCCESS_CODE);
        // 传参中使用常量
        return Result.failed(ResultCode.SUCCESS_CODE, ResultCode.SUCCESS_MSG);
    }
}

12、启动项目,浏览器访问 http://localhost:8080/user/failedTest

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

终端中打印:

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

13、总结:没有值时

Java 中 没有给值就是值本身,不像前端是对应的数字类型

package com.chuxin.demotodolist.controller;

public enum ResultEnum {
    // 获取 SUCCESS_CODE 读到的值是 "SUCCESS_CODE"
    SUCCESS_CODE,
    ERROR_CODE;
}

14、有值时:

如果有值时看有几个值,如果有两个的话 对应类中就要描述两个属性并且描述类型

还需要描述有参构造和无参构造

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

15、枚举大总结:

所以枚举只要一个没有参数 就都必须不能有参数 ,如果有一个参数或多个就必须都要有一个或多个参数,

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

三、枚举相关报错原因

报错是应该没有 ResultCode 有参构造和无参构造的描述方法和声明对应的参数变量,使用 lombok 实现有参构造和无参构造即,并且给出 code 和 msg 描述~

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

2、解决办法:

使用 lombok 实现有参构造和无参构造 并且给出属性 code msg 描述~

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

3、枚举描述需要放最上面,反之会报错~

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

四、枚举参数构造时原理

1、枚举构造的原理是什么呢?

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

2、为了好理解,我删除了部分代码,只保留到可以理解的程度,先说调用:

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

代码如下:

result.setCode(ResultCode.SUCCESS.getCode());

这个很好理解:(调方法取值)

ResultCode.SUCCESS.getCode() 的操作其实是子啊调方法取值

  • ResultCode.SUCCESS 表示获取枚举 ResultCode 中的 SUCCESS 枚举值
  • getCode() 其实是调用 SUCCESS 的 getCode 方法,而不是 ResultCode 的(为什么这么说呢)
@NoArgsConstructor
public enum ResultCode implements IResultCode,Serializable {
    // 此处 code 200 201 为演示随意写的 不适用真实项目取值~
    SUCCESS(200, "操作成功"), ERROR(201, "操作失败");

    private int code;
    private String msg;

    ResultCode(int code, String msg){
        this.code = code;
        this.msg = msg;
    }
}

3、观点2中为什么说 getCode 是 SUCCESS 的而不是 ResultCode 的呢

前端开发 Spring Boot 入门指南:优化枚举重构,完善 Result 失败方法

代码如下:

package com.chuxin.demotodolist.common.result;

import lombok.NoArgsConstructor;

import java.io.Serializable;

@NoArgsConstructor
public enum ResultCode implements IResultCode,Serializable {
    // 此处 code 200 201 为演示随意写的 不适用真实项目取值~
    SUCCESS(200, "操作成功"), ERROR(201, "操作失败");

    private int code;
    private String msg;

    ResultCode(int code, String msg){
        this.code = code;
        this.msg = msg;
    }

    @Override
    public int getCode() {
        return code;
    }

    @Override
    public String getMsg() {
        return msg;
    }

}

这其实是因为:

  • 枚举实例创建

    • 在编译阶段,SUCCESS 和 ERROR 枚举实例会被创建。每个实例在创建时都会调用枚举构造器ResultCode(int code, String msg),并将相应的code和msg参数传递给它。这意味着 SUCCESS 实例的code 字段被设置为 200,msg 字段被设置为 "操作成功" ;同理,ERROR 实例的字段被相应设置。
  • 字段初始化

    • 在构造器中,通过 this.code = code; 和 this.msg = msg; 语句,枚举实例的字段被初始化。这些字段是枚举实例的一部分,一旦初始化后,它们的值就不会改变。
  • 方法调用

    • 当调用 ResultCode.SUCCESS.getCode() 时,实际上是调用了 SUCCESS 枚举实例上的 getCode() 方法。由于 SUCCESS 枚举实例在创建时已经初始化了其 code 字段,因此 getCode() 方法能够返回正确的 code 值,即 200。
  • 返回值

    • 最后,getCode() 方法返回枚举实例SUCCESS的code字段的值,即200

代码仓库

github.com/chuxin-cs/s…

往期内容

点击链接查看:www.yuque.com/chuxin-cs/c…

转载自:https://juejin.cn/post/7390631421326983205
评论
请登录