歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Mybatis實戰之自定義TypeHandler處理枚舉

Mybatis實戰之自定義TypeHandler處理枚舉

日期:2017/3/1 9:05:28   编辑:Linux編程

在Mybatis中,處理枚舉類的TypeHandler有兩個:

  1. EnumTypeHandler: 用於保存枚舉名
  2. EnumOrdinalTypeHandler: 用於保存枚舉的序號。

在實際項目中,以上往往不能滿足我們的需求。

需求分析

枚舉需要包含兩個屬性,label(用於顯示), value(實際的枚舉值)。數據庫保存枚舉值(value)。

這很明顯Mybatis提供的兩個枚舉TypeHandler不能滿足我們的需求。此時,我們可以自定義一個通用的枚舉TypeHandler來滿足我們的需求。

自定義枚舉TypeHandler

通用枚舉DisplayedEnum

public interface DisplayedEnum {

    String DEFAULT_VALUE_NAME = "value";

    String DEFAULT_LABEL_NAME = "label";

    default Integer getValue() {
        Field field = ReflectionUtils.findField(this.getClass(), DEFAULT_VALUE_NAME);
        if (field == null)
            return null;
        try {
            field.setAccessible(true);
            return Integer.parseInt(field.get(this).toString());
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    @JsonValue
    default String getLabel() {
        Field field = ReflectionUtils.findField(this.getClass(), DEFAULT_LABEL_NAME);
        if (field == null)
            return null;
        try {
            field.setAccessible(true);
            return field.get(this).toString();
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    static <T extends Enum<T>> T valueOfEnum(Class<T> enumClass, Integer value) {
        if (value == null)
            throw  new IllegalArgumentException("DisplayedEnum value should not be null");
        if (enumClass.isAssignableFrom(DisplayedEnum.class))
            throw new IllegalArgumentException("illegal DisplayedEnum type");
        T[] enums = enumClass.getEnumConstants();
        for (T t: enums) {
            DisplayedEnum displayedEnum = (DisplayedEnum)t;
            if (displayedEnum.getValue().equals(value))
                return (T) displayedEnum;
        }
        throw new IllegalArgumentException("cannot parse integer: " + value + " to " + enumClass.getName());
    }
}

說明:
普通枚舉類通過實現DisplayedEnum接口,就可以:

  1. 通過getValue()獲取枚舉值。
  2. 通過getLabel()獲取枚舉的label屬性。
  3. 通過valueOfEnum()將Integer值轉換為指定的枚舉類型。

普通枚舉類

public enum CommonsType implements DisplayedEnum {

    NORMAL("正常", 0), INVALID("無效", 1);

    String label;

    Integer value;

    private CommonsType(String label, Integer value) {
        this.label = label;
        this.value = value;
    }
}

以上就是一個普通枚舉類的示例。

自定義枚舉TypeHandler

@MappedJdbcTypes(value = JdbcType.TINYINT, includeNullJdbcType = true)
public class DefaultEnumTypeHandler extends BaseTypeHandler<DisplayedEnum> {

    private Class<DisplayedEnum> type;

    public EnumTypeHandler(){};

    public EnumTypeHandler(Class<DisplayedEnum> type) {
        if (type == null) throw new IllegalArgumentException("Type argument cannot be null");
        this.type = type;
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, DisplayedEnum parameter, JdbcType jdbcType)
            throws SQLException {
        ps.setInt(i, parameter.getValue());
    }

    @Override
    public DisplayedEnum getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return convert(rs.getInt(columnName));
    }

    @Override
    public DisplayedEnum getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return convert(rs.getInt(columnIndex));
    }

    @Override
    public DisplayedEnum getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return convert(cs.getInt(columnIndex));
    }

    private DisplayedEnum convert(int status){
        DisplayedEnum[] objs = type.getEnumConstants();
        for(DisplayedEnum em: objs){
            if(em.getValue() == status){
                return  em;
            }
        }
        return null;
    }
}

使用我們自定義的DefaultEnumTypeHandler

由於Mybatis默認在處理枚舉類型的時候會使用EnumTypeHandler(只保存及轉換枚舉類型的名字), 因此,我們需要手動指定使用DefaultEnumTypeHandler。示例如下:

<resultMap id="xxx" type="xxx">
    ...
    <result column="type" jdbcType="TINYINT" property="type" typeHandler="xxx.xxx.xxx.DefaultEnumTypeHandler" />
    ...
</resultMap>    

即我們需要通過使用typeHandler來指定。

小結

以上是我們應用在實際項目中的一個對於Mybatis處理枚舉類的方案。我看大多數人也都是這樣在用。然而,在實際項目中,我們會發現隨著枚舉類的增多,這樣寫起來會很繁瑣。我看了一下網絡上似乎也沒人處理這種情況。

Copyright © Linux教程網 All Rights Reserved