首頁 > 軟體

springboot+mybatis+列舉處理器的實現

2022-03-24 13:01:41

背景

在Spring boot專案開發中經常遇到需要使用列舉的場景,比如描述狀態、性別、型別等相關欄位。通常這些欄位在資料庫會以tinyint型別存在,比如:0:女性,1:男性;或者,0:裝置掉線,1:裝置線上。如果在系統中我們也以int的方式到處使用,後期在維護的時候對數位的理解會非常困難,所以通常這種欄位我們一般採用列舉的方式在系統的流轉,而在儲存的時候我們使用數位的方式儲存。

以上,因為資料庫儲存欄位的型別和我們在系統中流轉的型別不同,我們需要實現一個兩者自動轉換的功能,也就是標題中提到的列舉處理器。

現狀

如果我們採用全數位的方式在系統中流轉,最終系統程式碼就會變成這樣:

if(status == 1){ // 時間一長,誰來告訴我1代表什麼狀態
    ...
}else if (status == 0){ // 0又代表什麼狀態
    ...
}
...

以上這種操作會造成程式碼的可讀性非常低,非常需要依靠對其中數位的註釋進行編碼。

期望

希望型別性別、狀態這類欄位可以全部使用列舉型別,提高程式碼的可維護性。考慮到大部分我們使用列舉的時候都可以使用ONLINE(1, "線上"), OFFLINE(0, "掉線")這樣的方式,可以總結出一個通用的列舉介面,後續類似的列舉類都實現這個介面。

實現

為了滿足期望的功能,通過一個通用的列舉介面和mybatis的列舉處理器來實現業務系統中使用列舉型別和mysql中使用數值型別的功能。

通用的列舉介面

簡單粗暴的命名這個通用列舉介面為KeyValueEnum:

public interface KeyValueEnum {

    int getKey();

    String getValue();

}

基於該介面實現一個狀態列舉類:

public enum StatusEnum implements KeyValueEnum {

    ONLINE(1, "線上"),
    
    OFFLINE(0, "掉線");
    
    private int key;

    private String value;

    StatusEnum(int key, String value){
        this.key = key;
        this.value = value;
    }

    @Override
    public int getKey() {
        return key;
    }

    @Override
    public String getValue() {
        return value;
    }
}

由此,所有類似的介面都可以用過getKey()getValue()方法來獲取相關數值。

mybaits列舉處理器

@MappedTypes(value = {Status.class, Sex.class}) // 每增加一種列舉型別,就在此新增。
public class EnumTypeHandler<E extends KeyValueEnum> extends BaseTypeHandler<E> {

    private Class<E> type;
    private E[] enums;

    public EnumTypeHandler(Class<E> type){
        this.type = type;
        this.enums = type.getEnumConstants();
    }

    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, KeyValueEnum keyValueEnum, JdbcType jdbcType) throws SQLException {
        preparedStatement.setInt(i, keyValueEnum.getKey());
    }

    @Override
    public E getNullableResult(ResultSet resultSet, int i) throws SQLException {
        int key = resultSet.getInt(i);
        return getEnum(key);
    }

    @Override
    public E getNullableResult(ResultSet resultSet, String s) throws SQLException {
        int key = resultSet.getInt(s);
        return getEnum(key);
    }

    @Override
    public E getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        int key = callableStatement.getInt(i);
        return getEnum(key);
    }

    private E getEnum(int key){
        for (E keyValue:
             enums) {
            if (keyValue.getKey() == key){
                return keyValue;
            }
        }
        return null;
    }
}

列舉處理器是通過繼承mybatis自帶的BaseTypeHandler抽象類實現的,其中包含的具體方法參考mybatis的BaseTypeHandler檔案即可。

需要注意的是,如果每增加一種需要儲存到資料庫的列舉型別就需要在@MappedTypes(value = {Status.class, Sex.class})註解中新增一個對應的列舉類。

設定列舉處理器

# application.yaml
mybatis:
  configuration:
    map-underscore-to-camel-case: true # 下劃線轉駝峰
  type-handlers-package: xxx.xxx.xxx.handler.mybatisTypeHandler # 設定剛才編輯的列舉處理器

包含列舉型別欄位的實體類

@Data
public class device {

    private long id;

    private Status status;
}

期望實現的目標是直接通過資料庫查詢出對應的列舉型別。

查詢mapper

public interface deviceMapper {

    @Results(id="aaa", value = {
            @Result(id = true, column = "id", property = "id"),
            @Result(column = "status", property = "status")
    })
    @Select("select * from device where id = #{id}")
    Device getDeviceById(long id);
}

通過mapper查詢最終可以實現資料庫tinyint型別查詢後轉換為實體類欄位對應的列舉型別。

到此這篇關於springboot+mybatis+列舉處理器的實現的文章就介紹到這了,更多相關springboot mybatis 列舉處理器內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com