欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot項目統(tǒng)一枚舉轉(zhuǎn)換實踐過程

 更新時間:2024年12月10日 08:43:51   作者:曾小二的禿頭之路  
文章介紹了在Spring Boot項目中統(tǒng)一枚舉轉(zhuǎn)換的實踐,通過使用自定義的父枚舉接口和AttributeConverter、ConverterFactory、JsonSerializer和JsonDeserializer等工具,實現(xiàn)了枚舉與數(shù)據(jù)庫、請求參數(shù)、響應(yīng)參數(shù)和消息參數(shù)之間的自動轉(zhuǎn)換

SpringBoot 項目統(tǒng)一枚舉轉(zhuǎn)換實踐

1 現(xiàn)有問題

目前的項目中,有些枚舉字段,在傳遞的時候,需要經(jīng)常對枚舉進(jìn)行對應(yīng)的轉(zhuǎn)換,有如下場景:

  1. 存儲進(jìn)數(shù)據(jù)庫的時候,需要存儲為 int;
  2. 查詢出來的時候,需要對該數(shù)值進(jìn)行轉(zhuǎn)換;
  3. 接收前端參數(shù)的時候,需要將數(shù)字轉(zhuǎn)換為我們系統(tǒng)的枚舉;
  4. 響應(yīng)的參數(shù)包含枚舉的時候,需要將枚舉轉(zhuǎn)換成 int;
  5. 發(fā)送或接收 MQ 消息時,又得對枚舉進(jìn)行轉(zhuǎn)換。

可以看到,我們在系統(tǒng)中需要做大量的枚舉轉(zhuǎn)換工作,那么是不是有什么方法對枚舉轉(zhuǎn)換進(jìn)行簡化呢?

2 數(shù)據(jù)庫轉(zhuǎn)換枚舉

我們這邊的系統(tǒng)使用的持久層框架是 Spring Data jpa,底層實現(xiàn)是 Hibernate,對于數(shù)據(jù)庫枚舉的轉(zhuǎn)化提供了 AttributeConverter 接口,可以實現(xiàn)枚舉和 int 自動轉(zhuǎn)換。

例如我們有一個枚舉類

@Getter
@RequiredArgsConstructor
public enum SexEnum {
    /**
     * 1 男
     */
    MALE(1, "男"),
    /**
     * 2 女
     */
    FEMALE(2, "女"),
    ;
    private final Integer value;
}

那么,我們就可以實現(xiàn) AttributeConverter 接口,來實現(xiàn)枚舉的自動轉(zhuǎn)換。

@Converter(autoApply = true)
public class SexEnumConverter implements AttributeConverter<SexEnum, Integer> {

    @Override
    public Integer convertToDatabaseColumn(SexEnum attribute) {
        return attribute == null ? null : attribute.getValue();
    }

    @Override
    public SexEnum convertToEntityAttribute(Integer dbData) {
        return Arrays.stream(SexEnum.class)
                .filter(sexEnum -> sexEnum.getValue().equals(dbData))
                .findFirst()
                .orElse(null);
    }
}

但是這樣子每一個枚舉類又必須寫對應(yīng)的枚舉轉(zhuǎn)換的代碼,很麻煩,因此,接下來進(jìn)行優(yōu)化。

我們可以先定義一個父類的枚舉接口

public interface IEnum {
    Integer getValue();
}

然后優(yōu)化我們的枚舉轉(zhuǎn)換類

public class EnumConverter<E extends IEnum> implements AttributeConverter<E, Integer> {

    private final Class<E> clazz;

    @SuppressWarnings("unchecked")
    public EnumConverter() {
        this.clazz = (Class<E>) (((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments())[0];
    }

    @Override
    public Integer convertToDatabaseColumn(E attribute) {
        return Optional.ofNullable(attribute)
                .map(IEnum::getValue)
                .orElse(null);
    }

    @Override
    public E convertToEntityAttribute(Integer dbData) {
        return Arrays.stream(clazz.getEnumConstants())
                .filter(iEnum -> iEnum.getValue().equals(dbData))
                .findFirst()
                .orElse(null);
    }
}

然后枚舉類繼承我們的父類枚舉接口,再定義一個子類實現(xiàn),就可以實現(xiàn)枚舉的自動轉(zhuǎn)換

@Getter
@RequiredArgsConstructor
public enum SexEnum implements IEnum {
    /**
     * 1 男
     */
    MALE(1, "男"),
    /**
     * 2 女
     */
    FEMALE(2, "女"),
    ;
    private final Integer value;
    
    @Converter(autoApply = true)
    public static class SexEnumConverter extends EnumConverter<SexEnum> {
    }
}

這樣子的話,對于數(shù)據(jù)庫的查詢或者保存,就可以直接使用枚舉進(jìn)行操作,而不用再去手動轉(zhuǎn)換。

3 請求參數(shù)轉(zhuǎn)換枚舉

3.1 @Param 參數(shù)轉(zhuǎn)換成枚舉

對于請求參數(shù),我們分為兩種,先看第一種,攜帶在 URL 后面的參數(shù)。

spring 提供了一個 ConverterFactory 接口,我們通過實現(xiàn)他,便可以實現(xiàn)對枚舉的自動轉(zhuǎn)換,這里同樣要使用到我們的父類接口 IEnum。

@Component
public class IEnumConverterFactory implements ConverterFactory<String, IEnum> {

    @Override
    public <T extends IEnum> Converter<String, T> getConverter(Class<T> targetType) {
        return source ->
                Arrays.stream(targetType.getEnumConstants())
                        .filter(x -> x.getValue().toString().equals(source))
                        .findFirst()
                        .orElse(null);
    }
}

然后實現(xiàn) WebMvcConfigurer,添加該類型轉(zhuǎn)換器

@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
    
    private final IEnumConverterFactory iEnumConverterFactory;

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverterFactory(iEnumConverterFactory);
    }
}

然后我們便可以在在方法上使用枚舉,MVC 框架會自動幫我們把數(shù)值轉(zhuǎn)成對應(yīng)的枚舉。

3.2 @RequestBody 參數(shù)轉(zhuǎn)換成枚舉

使用 @RequestBody 接收請求參數(shù),底層其實是使用了 Jackson 的反序列化功能。

我們可以繼承 Jackson 的 JsonDeserializer 抽象類,自定義我們的反序列化策略。

public class IEnumDeserializer extends JsonDeserializer<IEnum> implements ContextualDeserializer {

    private Class<? extends IEnum> clazz;

    public IEnumDeserializer() {
    }

    public IEnumDeserializer(Class<? extends IEnum> clazz) {
        this.clazz = clazz;
    }

    @SneakyThrows
    @Override
    public IEnum deserialize(JsonParser jsonParser, DeserializationContext ctxt) {
        final String param = jsonParser.getText();
        return Arrays.stream(clazz.getEnumConstants())
                .filter(x -> x.getValue().toString().equals(param))
                .findFirst()
                .orElse(null);
    }

    @SuppressWarnings({"unchecked"})
    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
        JavaType type = property.getType();
        // 如果是容器,則返回容器內(nèi)部枚舉類型
        while (type.isContainerType()) {
            type = type.getContentType();
        }
        return new IEnumDeserializer((Class<? extends IEnum>) type.getRawClass());
    }
}

然后在我們的 IEnum 類上,添加 @JsonDeserialize 注解,指定反序列化。

@JsonDeserialize(using = IEnumDeserializer.class)
public interface IEnum {
    Integer getValue();
}

這樣子,就可以在 @RequestBody 注解的實體類里面使用枚舉。

4 響應(yīng)參數(shù)轉(zhuǎn)換枚舉

我們返回響應(yīng)參數(shù)時,經(jīng)常需要把枚舉值轉(zhuǎn)成對應(yīng)的 int,因為Spring boot框架響應(yīng)參數(shù)的時候,采用的也是 Jackson 序列化,因此我們可以采用類似上面的做法,繼承 JsonSerializer 抽象類,實現(xiàn)自定義轉(zhuǎn)換。

public class IEnumSerializer extends JsonSerializer<IEnum> {

    @Override
    public void serialize(IEnum value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (Objects.isNull(value)) {
            gen.writeNull();
            return;
        }
        gen.writeNumber(value.getValue());
    }
}

然后在我們的 IEnum 類上,添加 @JsonDeserialize 注解,指定序列化。

@JsonSerialize(using = IEnumSerializer.class)
@JsonDeserialize(using = IEnumDeserializer.class)
public interface IEnum {
    Integer getValue();
}

這樣子,我們在給前端返回枚舉的時候,就可以不用自己手動進(jìn)行轉(zhuǎn)換,讓框架自動幫我們進(jìn)行轉(zhuǎn)換。

5 消息參數(shù)轉(zhuǎn)換枚舉

其實通過我們上面的配置,已經(jīng)自定義了枚舉的序列化和反序列化,只需要在我們的消息接收和發(fā)送的時候,采用 Jackson 序列化的形式,就可以實現(xiàn)枚舉的自動轉(zhuǎn)換。

總結(jié)

通過以上的配置,基本上可以實現(xiàn)我們整個項目的枚舉統(tǒng)一,消除我們在項目內(nèi)頻繁需要對枚舉和數(shù)值互相轉(zhuǎn)換的操作。

如果是前端頁面有相關(guān)的枚舉下拉框選擇查詢,我們還可以根據(jù)頂層的枚舉接口,對所有枚舉進(jìn)行掃描并存儲到內(nèi)存中,然后提供枚舉查詢的接口給前端,這樣子的話,后續(xù)新增枚舉參數(shù)的話,可以直接就從接口獲取到更新的值。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 如何解決Spring in action @valid驗證不生效的問題

    如何解決Spring in action @valid驗證不生效的問題

    這篇文章主要介紹了如何解決Spring in action @valid驗證不生效的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • springboot項目配置多個kafka的示例代碼

    springboot項目配置多個kafka的示例代碼

    這篇文章主要介紹了springboot項目配置多個kafka,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-04-04
  • java面向?qū)ο笤O(shè)計原則之開閉原則示例解析

    java面向?qū)ο笤O(shè)計原則之開閉原則示例解析

    這篇文章主要介紹了java面向?qū)ο笤O(shè)計原則之開閉原則的示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2021-10-10
  • Java 反射機制詳解及實例

    Java 反射機制詳解及實例

    這篇文章主要介紹了Java 反射機制詳解及實例的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • Intellij Idea中進(jìn)行Mybatis逆向工程的實現(xiàn)

    Intellij Idea中進(jìn)行Mybatis逆向工程的實現(xiàn)

    這篇文章主要介紹了Intellij Idea中進(jìn)行Mybatis逆向工程的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • Java 如何解決跨域問題

    Java 如何解決跨域問題

    這篇文章主要介紹了Java 如何解決跨域問題,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下
    2021-03-03
  • java多次嵌套循環(huán)查詢數(shù)據(jù)庫導(dǎo)致代碼中數(shù)據(jù)處理慢的解決

    java多次嵌套循環(huán)查詢數(shù)據(jù)庫導(dǎo)致代碼中數(shù)據(jù)處理慢的解決

    這篇文章主要介紹了java多次嵌套循環(huán)查詢數(shù)據(jù)庫導(dǎo)致代碼中數(shù)據(jù)處理慢的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • 前端和后端解決跨域問題的一些方式詳解

    前端和后端解決跨域問題的一些方式詳解

    跨域?qū)τ谡趯W(xué)習(xí)或者已經(jīng)就業(yè)的前端同學(xué)而言,就是老朋友,只要涉及請求,前后端交互,開發(fā)階段等關(guān)鍵字,都避不開跨域,這篇文章主要給大家介紹了關(guān)于前端和后端解決跨域問題的一些方式,需要的朋友可以參考下
    2024-07-07
  • java實現(xiàn)上傳文件到oss(阿里云)功能示例

    java實現(xiàn)上傳文件到oss(阿里云)功能示例

    這篇文章主要介紹了java實現(xiàn)上傳文件到oss(阿里云)功能,結(jié)合實例形式詳細(xì)分析了java上傳文件到阿里云的具體步驟、配置及相關(guān)實現(xiàn)技巧,需要的朋友可以參考下
    2019-11-11
  • 深入理解Java中的volatile關(guān)鍵字(總結(jié)篇)

    深入理解Java中的volatile關(guān)鍵字(總結(jié)篇)

    volatile這個關(guān)鍵字,不僅僅在Java語言中有,在很多語言中都有的,而且其用法和語義也都是不盡相同的。這篇文章主要介紹了Java中的volatile關(guān)鍵字,需要的朋友可以參考下
    2018-10-10

最新評論