看看人家在接口中使用枚举类型的方式,那叫一个优雅!下

简介: 看看人家在接口中使用枚举类型的方式,那叫一个优雅!下

2.5. 通用枚举字典接口

有时可以将 枚举 理解为系统的一类字段,比较典型的就是管理页面的各种下拉框,下拉框中的数据来自于后台服务。

有了 CommonEnum 之后,可以提供统一的一组枚举字典,避免重复开发,同时在新增枚举时也无需进行扩展,系统自动识别并添加到字典中。

2.5.1. 构建字典Controller

在 CommonEnumRegistry 基础之上实现通用字典接口非常简单,只需按规范构建 Controller 即可,具体如下:

@Api(tags = "通用字典接口")
@RestController
@RequestMapping("/enumDict")
@Slf4j
public class EnumDictController {
    @Autowired
    private CommonEnumRegistry commonEnumRegistry;
    @GetMapping("all")
    public RestResult<Map<String, List<CommonEnumVO>>> allEnums(){
        Map<String, List<CommonEnum>> dict = this.commonEnumRegistry.getNameDict();
        Map<String, List<CommonEnumVO>> dictVo = Maps.newHashMapWithExpectedSize(dict.size());
        for (Map.Entry<String, List<CommonEnum>> entry : dict.entrySet()){
            dictVo.put(entry.getKey(), CommonEnumVO.from(entry.getValue()));
        }
        return RestResult.success(dictVo);
    }
    @GetMapping("types")
    public RestResult<List<String>> enumTypes(){
        Map<String, List<CommonEnum>> dict = this.commonEnumRegistry.getNameDict();
        return RestResult.success(Lists.newArrayList(dict.keySet()));
    }
    @GetMapping("/{type}")
    public RestResult<List<CommonEnumVO>> dictByType(@PathVariable("type") String type){
        Map<String, List<CommonEnum>> dict = this.commonEnumRegistry.getNameDict();
        List<CommonEnum> commonEnums = dict.get(type);
        return RestResult.success(CommonEnumVO.from(commonEnums));
    }
}

该 Controller 提供如下能力:

  1. 获取全部字典,一次性获取系统中所有的 CommonEnum
  2. 获取所有字典类型,仅获取字典类型,通常用于测试
  3. 获取指定字典类型的全部信息,比如上述所说的填充下拉框

2.5.2. 效果展示

获取全部字典:

获取所有字典类型:

获取指定字段类型的全部信息:

2.6. 输出适配器

输出适配器主要以 ORM 框架为主,同时各类 ORM 框架均提供了类型映射的扩展点,通过该扩展点可以对 CommonEnum 使用 code 进行存储。

2.6.1. MyBatis 支持

MyBatis 作为最流行的 ORM 框架,提供了 TypeHandler 用于处理自定义的类型扩展。

@MappedTypes(NewsStatus.class)
public class MyBatisNewsStatusHandler extends CommonEnumTypeHandler<NewsStatus> {
    public MyBatisNewsStatusHandler() {
        super(NewsStatus.values());
    }
}

MyBatisNewsStatusHandler 通过 @MappedTypes(NewsStatus.class) 对其进行标记,以告知框架该 Handler 是用于 NewsStatus 类型的转换。

CommonEnumTypeHandler 是为 CommonEnum 提供的通用转化能力,具体如下:

public abstract  class CommonEnumTypeHandler<T extends Enum<T> & CommonEnum>
        extends BaseTypeHandler<T> {
    private final List<T> commonEnums;
    protected CommonEnumTypeHandler(T[] commonEnums){
        this(Arrays.asList(commonEnums));
    }
    protected CommonEnumTypeHandler(List<T> commonEnums) {
        this.commonEnums = commonEnums;
    }
    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, T t, JdbcType jdbcType) throws SQLException {
        preparedStatement.setInt(i, t.getCode());
    }
    @Override
    public T getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
        int code = resultSet.getInt(columnName);
        return commonEnums.stream()
                .filter(commonEnum -> commonEnum.match(String.valueOf(code)))
                .findFirst()
                .orElse(null);
    }
    @Override
    public T getNullableResult(ResultSet resultSet, int i) throws SQLException {
        int code = resultSet.getInt(i);
        return commonEnums.stream()
                .filter(commonEnum -> commonEnum.match(String.valueOf(code)))
                .findFirst()
                .orElse(null);
    }
    @Override
    public T getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        int code = callableStatement.getInt(i);
        return commonEnums.stream()
                .filter(commonEnum -> commonEnum.match(String.valueOf(code)))
                .findFirst()
                .orElse(null);
    }
}

由于逻辑比较简单,在此不做过多解释。

有了类型之后,需要在 spring boot 的配置文件中指定 type-handler 的加载逻辑,具体如下:

mybatis:
  type-handlers-package: com.geekhalo.lego.enums.mybatis

完成配置后,使用 Mapper 对数据进行持久化,数据表中存储的便是 code 信息,具体如下:

2.6.2. JPA 支持

随着 Spring data 越来越流行,JPA 又焕发出新的活力,JPA 提供 AttributeConverter 以对属性转换进行自定义。

首先,构建 JpaNewsStatusConverter,具体如下:

public class JpaNewsStatusConverter extends CommonEnumAttributeConverter<NewsStatus> {
    public JpaNewsStatusConverter() {
        super(NewsStatus.values());
    }
}

CommonEnumAttributeConverter 为 CommonEnum 提供的通用转化能力,具体如下:

public abstract class CommonEnumAttributeConverter<E extends Enum<E> & CommonEnum>
        implements AttributeConverter<E, Integer> {
    private final List<E> commonEnums;
    public CommonEnumAttributeConverter(E[] commonEnums){
        this(Arrays.asList(commonEnums));
    }
    public CommonEnumAttributeConverter(List<E> commonEnums) {
        this.commonEnums = commonEnums;
    }
    @Override
    public Integer convertToDatabaseColumn(E e) {
        return e.getCode();
    }
    @Override
    public E convertToEntityAttribute(Integer code) {
        return (E) commonEnums.stream()
                .filter(commonEnum -> commonEnum.match(String.valueOf(code)))
                .findFirst()
                .orElse(null);
    }
}

在有了 JpaNewsStatusConverter 之后,我们需要在 Entity 的属性上增加配置信息,具体如下:

@Entity
@Data
@Table(name = "t_jpa_news")
public class JpaNewsEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Convert(converter = JpaNewsStatusConverter.class)
    private NewsStatus status;
}

@Convert(converter = JpaNewsStatusConverter.class) 是对 status 的配置,使用 JpaNewsStatusConverter 进行属性的转换。

运行持久化指令后,数据库如下:

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

3. 项目信息

项目仓库地址:https://gitee.com/litao851025/lego



相关文章
|
4月前
|
安全 Python
扩展类实例的类型转换,和关键字 None
扩展类实例的类型转换,和关键字 None
20 0
|
7月前
|
设计模式 存储 Java
JavaSE——面向对象高级三(3/5)-枚举(认识枚举、拓展:抽象枚举、用枚举实现单例模式、枚举的应用场景)
JavaSE——面向对象高级三(3/5)-枚举(认识枚举、拓展:抽象枚举、用枚举实现单例模式、枚举的应用场景)
38 0
|
8月前
|
JavaScript 前端开发 编译器
TypeScript【可选属性、只读属性、额外的属性检查、函数类型、类类型、继承接口】(四)-全面详解(学习总结---从入门到深化)
TypeScript【可选属性、只读属性、额外的属性检查、函数类型、类类型、继承接口】(四)-全面详解(学习总结---从入门到深化)
82 0
|
Java 编译器 C++
常量接口 vs 常量类 vs 枚举区别
把常量定义在接口里与类里都能通过编译,那2者到底有什么区别呢?
86 0
|
Java 编译器 数据库
Java维护常量方式的比较——接口、常量类与枚举
Java维护常量方式的比较——接口、常量类与枚举 一、示例 ​ 1.让类实现定义了常量的接口
|
存储 JSON 缓存
看看人家在接口中使用枚举类型的方式,那叫一个优雅!上
看看人家在接口中使用枚举类型的方式,那叫一个优雅!上
看看人家在接口中使用枚举类型的方式,那叫一个优雅!上
|
安全 Java 编译器
枚举使用、转数组、实现接口、枚举单例
枚举使用、转数组、实现接口、枚举单例
126 0
|
Kotlin
【Kotlin】接口 ( 声明 | 实现 | 接口方法 | 接口属性 | 接口覆盖冲突 | 接口继承 )(二)
【Kotlin】接口 ( 声明 | 实现 | 接口方法 | 接口属性 | 接口覆盖冲突 | 接口继承 )(二)
298 0
|
Java Kotlin
【Kotlin】接口 ( 声明 | 实现 | 接口方法 | 接口属性 | 接口覆盖冲突 | 接口继承 )(一)
【Kotlin】接口 ( 声明 | 实现 | 接口方法 | 接口属性 | 接口覆盖冲突 | 接口继承 )(一)
186 0