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

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

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



相关文章
|
6月前
|
安全 算法 编译器
【C++基础语法 枚举】C/C++ 中enum枚举量的介绍:介绍enum枚举量在C/C中的作用和使用方法
【C++基础语法 枚举】C/C++ 中enum枚举量的介绍:介绍enum枚举量在C/C中的作用和使用方法
70 2
|
2月前
|
安全 Python
扩展类实例的类型转换,和关键字 None
扩展类实例的类型转换,和关键字 None
13 0
|
6月前
|
安全 API C#
C#.Net筑基-类型系统②常见类型--枚举Enum
枚举(enum)是C#中的一种值类型,用于创建一组命名的整数常量。它们基于整数类型(如int、byte等),默认为int。枚举成员可指定值,未指定则从0开始自动递增。默认值为0。枚举可以与整数类型互相转换,并可通过`[Flags]`特性表示位域,支持位操作,用于多选场景。`System.Enum`类提供了如`HasFlag`、`GetName`等方法进行枚举操作。
|
6月前
|
Java 索引
通用枚举类
本文介绍了Java中枚举类的两种常见用法。场景一展示了一个包含类型值的枚举`OperatorType`,通过构造函数设置类型并在`enumOf`方法中按值查找枚举常量。场景二的`EnableCheck`枚举使用`ordinal()`方法获取枚举常量的序号(默认从0开始),并转化为字符串返回,提供了`getValue()`方法以获取序号的字符串表示。
47 5
|
6月前
|
JSON API 数据库
使用现代方式定义接口
【5月更文挑战第14天】FastAPI是一个现代化的、基于类型的web框架,用于构建API。它支持自动补全和类型检查,提供数据校验并能自动生成清晰的错误消息。 它基于OpenAPI标准,能自动生成交互式Swagger UI和ReDoc文档。 FastAPI内置安全性特性,支持身份验证,如HTTP基本认证和OAuth2。依赖注入系统使得复杂逻辑易于管理,同时兼容Starlette,具备高性能、WebSocket和GraphQL支持。
182 0
|
12月前
|
Java 索引
枚举类 - 自定义枚举类与使用enum关键字
枚举类 - 自定义枚举类与使用enum关键字
114 0
|
Java 编译器 C++
常量接口 vs 常量类 vs 枚举区别
把常量定义在接口里与类里都能通过编译,那2者到底有什么区别呢?
69 0
|
Java 编译器 数据库
Java维护常量方式的比较——接口、常量类与枚举
Java维护常量方式的比较——接口、常量类与枚举 一、示例 ​ 1.让类实现定义了常量的接口
|
存储 JSON 缓存
看看人家在接口中使用枚举类型的方式,那叫一个优雅!上
看看人家在接口中使用枚举类型的方式,那叫一个优雅!上
看看人家在接口中使用枚举类型的方式,那叫一个优雅!上
Lambda表达式实现方式、标准格式、练习、省略模式、注意事项及和匿名内部类的区别
Lambda表达式实现方式、标准格式、练习、省略模式、注意事项及和匿名内部类的区别
122 0