枚举

咩咩咩针对枚举类型,做了一系列扩展与适配。在开发过程中,针对枚举值我们通常会定义一个特定的枚举类型:

public enum Gender {

    MALE, 
    FEMALE,
    ;

}

在开发中,只需要将获取到的数据库的string值,使用 Enum.valueOf(Gender.class, "MALE") 来将string值转换为枚举对象,或者通过 Gender.MALE.name() 方法将枚举转换为数据库所要的 string。

这种方式来处理枚举有以下几个优点:

  1. 使用jdk本身提供的功能即可,不需要做额外的扩展,且比较、转换都比较容易
  2. 同样的,在mybatis、jackson等框架中,本身也提供了对枚举的支持
  3. 枚举类相对更精简,存入的字符串可读性也比较高

同样的,也有一些缺点,这些缺点导致我们通常不在项目中使用纯枚举类:

  1. 存储的数值,通常可能不是枚举对象的名字,我无法自定义存储值
  2. 数据类型受限,我可能需要数字类型的枚举,与上述实际是一个问题
  3. jdk提供的Enum.valueOf()方法,在找不到对应的枚举值时,会抛出异常,并且我很难对这个方法进行规则定义,比如如果传入null,就返回一个NULL的枚举值。

故在项目中我们会通常自定义一个拥有自己字段的枚举类型,并定义根据code获取枚举、获取message的工具方法:

@AllArgsConstructor
@Getter
public enum Gender {

    MALE(0, "男人"),
    FEMALE(1, "女人"),
    ;

    private final Integer code;

    private final String message;

    public static Gender getEnums(Integer code) {
        for (Gender type : Gender.values()) {
            if (type.code.equals(code)) {
                return type;
            }
        }
        return null;
    }
}

这种方式也很繁琐:

  1. 每次定义枚举,都要copy一份getEnum方法
  2. mybatis的实体,很难直接使用枚举类型,除非你对每个枚举进行注册
  3. jackson与mybatis的问题类似,不过jackson可以对code字段增加 @JsonValue字段来解决这个问题

因为这些痛点,miemiemie对枚举的处理就应运而生了。

CommonEnum

miemiemie-core 模块的 enums 包下,定义了一个 CommonEnum 接口,该接口是对所有枚举的抽象接口,他提供了一些方法,可以让我们方便的定义枚举、使用枚举:

// 拥有两个泛型,一个代表code字段的类型(枚举唯一标记)、一个代表message的类型
public interface CommonEnum<K, V> {
    K getCode();
    V getMessage();
}

如果要定义一个枚举,需要实现此接口,并添加code和message字段:

@AllArgsConstructor
@Getter
public enum Gender implements CommonEnum<Integer, String> {

    MALE(0, "男人"),
    FEMALE(1, "女人"),
    ;

    private final Integer code;

    private final String message;
}

如果想要根据枚举值获取对应的枚举,获取获取对应的描述信息,CommonEnum同样提供了一些静态方法,可以让你完成这些操作:

  • CommonEnum.getOptionalEnum(0, Gender.class);
  • CommonEnum.getEnum(0, Gender.class);
  • CommonEnum.getMessage(0, Gender.class);
  • CommonEnum.getOptionalMessage(0, Gender.class);

CommonEnum的扩展

CommoneEnum提供了几个默认的实现:

  • NameCodeEnum,以枚举类的name()作为code的CommonEnum
  • OrdinalCodeEnum,以枚举类的 ordinal() 作为code的CommonEnum

这两个都不建议使用。

对Jackson的支持

为了让枚举无缝的与Json序列化、以及web接口支持,在 miemiemie-webjackson包下,定义了

  • CommonEnumDeserializer,在返序列化时将CommonEnum枚举code值转换为枚举对象
  • CommonEnumSerializer, 在序列化时将CommonEnum枚举对象序列化,并且只序列化code值

这样,你就可以在请求体与响应体重,很方便的使用枚举类型,且不用在做烦人的字面量与枚举对象的转化了,并且枚举的判断也会更加简单。

备注: Jackson的配置位于JacksonConfig,如果你对枚举的处理有扩展或者优化、或者不想使用该功能,可以对该bean进行修改,或者覆盖此Bean重新配置。

对MybatisPlus的支持

为了让entity可以无缝使用枚举类型,在miemiemie-mybatisplus模块的config包下,定义了两个类型处理器,可以自动将CommonEnum枚举类型处理为枚举类型的code值:

  1. CommonEnumTypeHandler,核心处理CommonEnum的逻辑
  2. GenericEnumTypeHandler,通用枚举处理,包含了CommonEnum的逻辑,是为了兼容非实现了CommonEnum接口枚举而存在的

备注:在MybatisPlusAutoConfig中配置了这这个类型处理器。

对OpenAPI的支持

你需要依赖miemiemie-openapi模块已实现openapi的功能,该模块相比较于spring提供的,多增加了对枚举字段类型的处理:

  1. CommonEnumParameterCustomizer
  2. CommonEnumPropertyCustomizer

也就是说生成的API文档中,如果字段类型是CommonEnum枚举类型,则会在发送时,发送正常的枚举code值,而不是错误的枚举name()。并且在字段的展示上也更加人性化。

启动后访问地址 http://localhost:8080/swagger-ui/index.html:

预览

results matching ""

    No results matching ""