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

一文詳解Java項目中如何優(yōu)雅的使用枚舉類型

 更新時間:2024年03月14日 09:47:17   作者:趙俠客  
枚舉類型在開發(fā)中是很常見的,有非常多的應用場景,這篇文章我們就來學習一下項目中如何優(yōu)雅的使用枚舉類型,感興趣的小伙伴可以跟隨小編一起學習一下

前言

枚舉類型在開發(fā)中是很常見的,有非常多的應用場景,如狀態(tài)管理、類型分類、權限控制、配置管理、錯誤碼管理、日志級別等。正確合理的使用枚舉可以給我們帶來非常多的好處:

  • 增強代碼可讀性:枚舉可以使得代碼更加清晰、易于理解。它們提供了一種方式來組織和表示相關的常量值,使得代碼更易于閱讀和維護。
  • 類型安全性:枚舉類型能夠限制變量的值,只能取枚舉類型中定義的常量之一,從而避免了錯誤的賦值。這有助于減少代碼中的錯誤,并提高代碼的穩(wěn)定性。
  • 更好的維護性:枚舉類型可以在編譯時進行類型檢查,這有助于更早地發(fā)現(xiàn)和修復問題。此外,由于枚舉類型中的常量值是預定義的,因此可以減少對常量值的修改,從而簡化代碼的維護。
  • 更好的性能:枚舉類型的值是在編譯時確定的,因此在運行時訪問枚舉類型的值會更快。此外,由于枚舉類型中的常量值是唯一的,因此可以直接使用“==”進行兩個值之間的對比,這有助于提高性能。
  • 更好的組織性:枚舉類型可以幫助我們將相關的值組織在一起,使代碼更加整潔。通過將相關的常量值組合在一起,可以使代碼更加易于理解和維護。
  • 可擴展性:枚舉類型可以輕松地擴展或更新,而不會對其他部分的代碼造成影響。這有助于保持代碼的靈活性和可擴展性。
  • 便于測試:枚舉類型可以方便地進行測試,因為它們具有有限且確定的值域。這使得測試人員可以更容易地覆蓋所有可能的場景,并確保代碼的正確性。

雖然枚舉有諸多的好處,但是使用枚舉也給我們帶來了一些困擾:

  • 前后端數(shù)據(jù)格式轉換:前端主要給用戶展示數(shù)據(jù),不能直接顯示枚舉值,需要前端將枚舉轉成用戶可讀的數(shù)據(jù)顯示
  • 數(shù)據(jù)庫的存儲:代碼中的枚舉類型無法直接存儲數(shù)據(jù)庫,一般轉成數(shù)值類型,這樣還可以減少存儲空間
  • 代碼中大量類型轉換:查詢時需要數(shù)值類型轉成枚舉類型,保存時又需要將枚舉類型轉成數(shù)值類型

針對枚舉存在的問題,本文介紹一種枚舉從數(shù)據(jù)庫-->后端代碼-->前端代碼-->頁面和從頁面-->前端代碼-->后端代碼-->數(shù)據(jù)庫的自動轉換方案,大大方便前后端使用枚舉類型。

自動轉換目標

我們以用戶狀態(tài)為例,用戶有兩種狀態(tài):禁用和啟用

前端頁面:前端頁面顯示用戶狀態(tài)時用“禁用、啟用”;

前端代碼:前端代碼里處理用戶狀態(tài)時用:“ENABLE、DISABLE”或者用“0、1”;

后端代碼:后端代碼使用StatusEnum枚舉類;

數(shù)據(jù)庫:數(shù)據(jù)庫存儲用戶狀態(tài)時禁用存1、啟用存0。 

我們的目標是讓枚舉在各個環(huán)境流轉時全自動轉換。

代碼與數(shù)據(jù)庫自動轉換

第一步創(chuàng)建統(tǒng)一的枚舉基類BaseEnum

public interface BaseEnum {
    int getCode();
    String getName();
    String getEnumName();
    static <T extends BaseEnum> T getInstance(Class<T> clazz, String value) {
        T[] constants = clazz.getEnumConstants();
        for (T t : constants) {
            if(StrUtil.isNumeric(value)){
                if (t.getCode() == Integer.parseInt(value)) {
                    return t;
                }
            }else {
                if (t.getEnumName().equals(value)) {
                    return t;
                }
            }
        }
        return null;
    }
}

第二步創(chuàng)建用戶狀態(tài)類StatusEnum實現(xiàn)BaseEnum接口

public enum StatusEnum implements BaseEnum {
    ENABLE(0,"啟用"),
    DISABLE(1,"禁用");
    @EnumValue
    private int code;
    private String name;
    StatusEnum(int code, String name) {
        this.code = code;
        this.name=name;
    }
    @Override
    public int getCode() {
        return code;
    }
    @Override
    public String getName() {
        return name;
    }
    @Override
    public String getEnumName() {
        return this.name();
    }
}

BaseEnum主要有三個方法

  • getCode()獲取枚舉的數(shù)值如“0、1”;
  • getName()獲取枚舉顯示值如“禁用、啟用” ;
  • getEnumName()獲取枚舉的枚舉值如“ENABLE、DISABLE”.

如果使用MybatisPlus, 可以使用@EnumValue注解很方便的幫我們解決數(shù)據(jù)庫與實體對象中枚舉類型的相互轉換,如果只使用的Mybatis可以自定義TypeHandler來解決數(shù)據(jù)庫到JAVA枚舉對象的自動轉換。

第三步創(chuàng)建用戶類User用戶狀態(tài)使用StatusEnum

@Data
@TableName("user")
public class User {
    private Long id;
    private String userName;
    private StatusEnum status;
}

前后端相互轉換

當前端查詢用戶時,我們希望將枚舉的三個屬性都返回給前端,前端頁面顯示時取status.name代碼中使用status.enum或者status.code

{
  "id": 3581209395268,
  "userName": "test2@8531.cn",
  "status": {
    "name": "禁用",
    "enum": "DISABLE",
    "code": 1
  }
}

為了達到將枚舉序列化成一個json對象,我們需要自定義序列化器和反序列化器,以下以SpringBoot自帶的Jackson為例:

public class BaseEnumSerializer extends StdSerializer<BaseEnum> {
    public BaseEnumSerializer() {
        this(null);
    }
    public BaseEnumSerializer(Class<BaseEnum> t) {
        super(t);
    }
    @Override
    public void serialize(BaseEnum value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeStartObject();
        gen.writeStringField("name",value.getName());
        gen.writeStringField("enum",value.getEnumName());
        gen.writeNumberField("code",value.getCode());
        gen.writeEndObject();;
    }
}
public class BaseEnumDeserializer<T extends BaseEnum> extends StdDeserializer<T> {
    private Class<T> type;
    public BaseEnumDeserializer() {
        this(null);
    }
    public BaseEnumDeserializer(Class<T> vc) {
        super(vc);
        type = vc;
    }
    @Override
    public T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        return BaseEnum.getInstance(type, p.getText());
    }
}

自定義Jackson序列化器與反序列化器只能解決數(shù)據(jù)類型為application/json格式的請求,當請求類型為application/x-www-form-urlencoded我們還需要自定義Spring消息轉換器

public class NumBaseEnumConverterFactory implements ConverterFactory<Number, BaseEnum> {
    @Override
    public <T extends BaseEnum> Converter<Number, T> getConverter(Class<T> aClass) {
        return new NumberToEnumConverter<>(aClass);
    }
    private final class NumberToEnumConverter<T extends BaseEnum> implements Converter<Number, T> {
        private Class<T> enumType;
        public NumberToEnumConverter(Class<T> enumType) {
            this.enumType = enumType;
        }
        @Override
        public T convert(Number s) {
            return BaseEnum.getInstance(enumType,s.toString());
        }
    }
}

public class StrBaseEnumConverterFactory implements ConverterFactory<String, BaseEnum> {
    @Override
    public <T extends BaseEnum> Converter<String, T> getConverter(Class<T> aClass) {
        return new StringToEnumConverter<>(aClass);
    }
    private final class StringToEnumConverter<T extends BaseEnum> implements Converter<String, T> {
        private Class<T> enumType;
        public StringToEnumConverter(Class<T> enumType) {
            this.enumType = enumType;
        }
        @Override
        public T convert(String s) {
            return BaseEnum.getInstance(enumType,s);
        }
    }
}

以上兩個消息轉換器可以在數(shù)據(jù)格式以表單形式提交時將數(shù)值類型(0、1)和枚舉值類型(ENABLE、DISABLE)轉成枚舉類型。

將自定義好的數(shù)據(jù)轉換器注入到Spring中,這樣就完成所有枚舉自動轉換。

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addSerializer(BaseEnum.class, new BaseEnumSerializer());
        module.addDeserializer(BaseEnum.class, new BaseEnumDeserializer<>());
        mapper.registerModule(module);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        return mapper;
    }
     @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverterFactory(new StrBaseEnumConverterFactory());
        registry.addConverterFactory(new NumBaseEnumConverterFactory());
    }
}

查詢用戶

GET http://localhost:90/user/3581209395268
返回:
{
  "id": 3581209395268,
  "userName": "test2@8531.cn",
  "status": {
    "name": "啟用",
    "enum": "ENABLE",
    "code": 0
  }
}

application/json格式傳參

POST http://localhost:90/user
Content-Type: application/json

{
  "id": 3581209395268,
  "status": "DISABLE"
}

###
POST http://localhost:90/user
Content-Type: application/json

{
  "id": 3581209395268,
  "status": "0"
}

application/x-www-form-urlencoded格式傳參

PUT http://localhost:90/user
Content-Type: application/x-www-form-urlencoded

id=3581209395268&status=ENABLE
###
PUT http://localhost:90/user
Content-Type: application/x-www-form-urlencoded

id=3581209395268&status=1

###
PUT http://localhost:90/user/3581209395268?status=ENABLE
Content-Type: application/x-www-form-urlencoded

###
PUT http://localhost:90/user/3581209395268?status=1
Content-Type: application/x-www-form-urlencoded

@PathVariable格式傳參

PUT http://localhost:90/user/3581209395268/ENABLE
Content-Type: application/x-www-form-urlencoded

###
PUT http://localhost:90/user/3581209395268/1
Content-Type: application/x-www-form-urlencoded

對應JAVA代碼:

@RestController
public class UserController {
    @Resource
    private UserMapper userMapper;

    @GetMapping("/user/{id}")
    public User getById(@PathVariable Long id) {
        return userMapper.selectById(id);
    }
    
    @PostMapping("/user")
    public User upadteById(@RequestBody User user) {
        userMapper.updateById(user);
        return user;
    }

    @PutMapping("/user")
    public User updateUser(User user) {
        userMapper.updateById(user);
        return user;
    }

    @PutMapping("/user/{id}/{status}")
    public User updateStatus(@PathVariable Long id,@PathVariable StatusEnum status) {
        User user=userMapper.selectById(id);
        user.setStatus(status);
        userMapper.updateById(user);
        return user;
    }

    @PutMapping("/user/{id}")
    public User updateUserStatus(@PathVariable Long id,@RequestParam StatusEnum status) {
        User user=userMapper.selectById(id);
        user.setStatus(status);
        userMapper.updateById(user);
        return user;
    }
}

這樣很方便的解決了枚舉在各個環(huán)節(jié)的自動轉換問題,其它枚舉只要實現(xiàn)BaseEnum接口就能實現(xiàn)全自動轉換,前后端用起來也方便了不少。

總結

本文主要介紹了項目中使用枚舉的優(yōu)缺點,并針對缺點給出了解決方案,解決了枚舉在項目中頻繁轉換的問題,當然解決的還不是非常完美,比如返回給前端的枚舉格式是:{"enum":"DISABLE","code":1} 但是保存時傳此數(shù)據(jù)結構,后端卻無法正確的轉成枚舉,我們可以創(chuàng)建StatusEnumDeserializer,將子json對象轉成對應枚舉就好了,但是范型的寫法目前還不知道怎么寫,不可能增加一個枚舉寫一個反序列化器,有知道的可以回復一下,相互學習。

public class StatusEnumDeserializer   extends JsonDeserializer<StatusEnum>  {
    @Override
    public StatusEnum  deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonNode node= p.getCodec().readTree(p);
        if(node.isObject()){
            String name= node.get("enum").toString();
            return BaseEnum.getInstance(StatusEnum.class, name);
        }else {
            return BaseEnum.getInstance(StatusEnum.class, node.textValue());
        }
    }
}

以上就是一文詳解Java項目中如何優(yōu)雅的使用枚舉類型的詳細內容,更多關于Java枚舉類型的資料請關注腳本之家其它相關文章!

相關文章

  • Java圖形界面框架AWT布局管理器詳解

    Java圖形界面框架AWT布局管理器詳解

    這篇文章主要介紹了Java圖形界面框架AWT布局管理器,AWT是最早的圖形用戶界面框架之一,它為開發(fā)人員提供了一些基本的組件和工具,用于構建窗口、按鈕、文本框、標簽等圖形界面元素,需要的朋友可以參考下
    2025-04-04
  • Java線程的三種創(chuàng)建方式

    Java線程的三種創(chuàng)建方式

    這篇文章主要給大家分享的是ava線程的三種創(chuàng)建方式,Thread、Runnable和Thread、Runnable和Thread,想了解具體方式的小伙伴可以參考下面文章內容,希望對你有所幫助
    2021-11-11
  • SpringBoot整合mybatis/mybatis-plus實現(xiàn)數(shù)據(jù)持久化的操作

    SpringBoot整合mybatis/mybatis-plus實現(xiàn)數(shù)據(jù)持久化的操作

    這篇文章主要介紹了SpringBoot整合mybatis/mybatis-plus實現(xiàn)數(shù)據(jù)持久化,本節(jié)內容我們介紹了數(shù)據(jù)持久化的相關操作,并且是基礎傳統(tǒng)的關系型數(shù)據(jù)庫——mysql,需要的朋友可以參考下
    2022-10-10
  • SpringBoot+Vue實現(xiàn)數(shù)據(jù)添加功能

    SpringBoot+Vue實現(xiàn)數(shù)據(jù)添加功能

    這篇文章主要介紹了SpringBoot+Vue實現(xiàn)數(shù)據(jù)添加功能,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • MyBatis的嵌套查詢解析

    MyBatis的嵌套查詢解析

    本篇文章主要介紹了MyBatis的嵌套查詢解析,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • SpringMVC中的HandlerMapping和HandlerAdapter詳解

    SpringMVC中的HandlerMapping和HandlerAdapter詳解

    這篇文章主要介紹了SpringMVC中的HandlerMapping和HandlerAdapter詳解,在Spring MVC中,HandlerMapping(處理器映射器)用于確定請求處理器對象,請求處理器可以是任何對象,只要它們使用了@Controller注解或注解@RequestMapping,需要的朋友可以參考下
    2023-08-08
  • Springboot文件上傳出現(xiàn)找不到指定系統(tǒng)路徑的解決

    Springboot文件上傳出現(xiàn)找不到指定系統(tǒng)路徑的解決

    這篇文章主要介紹了Springboot文件上傳出現(xiàn)找不到指定系統(tǒng)路徑的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java中Exception和Error的區(qū)別詳解

    Java中Exception和Error的區(qū)別詳解

    這篇文章主要介紹了Java中Exception和Error的區(qū)別詳解,通過類的關系分析兩者的區(qū)別與應用場景,包含代碼實例,以下就是詳細內容,需要的朋友可以參考下
    2021-07-07
  • springboot項目配置context path失效的問題解決

    springboot項目配置context path失效的問題解決

    本文主要介紹了springboot項目配置context path失效的問題解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-04-04
  • 基于Hibernate中配置文件的學習(分享)

    基于Hibernate中配置文件的學習(分享)

    下面小編就為大家?guī)硪黄贖ibernate中配置文件的學習(分享)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06

最新評論