mybatis TypeHandler处理自定义枚举类型

之前做一个项目一个表字段中有很多状态,通过状态码来实现各个状态,但是在java 实体类中用int类型表示状态码,就出现一堆魔鬼数字。如果这样,那么后期代码维护和可读性比较困难,如果没有完整注释。
后来在官方参考 中发现mybatis提供两种枚举类型转换器:EnumTypeHandler(默认),EnumOrdinalTypeHandler.

EnumTypeHandler主要将字段值转换成对应枚举对象。通过Enum.valueOf(class,string) 方法实现。部分源码如下

 @Override
  public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
    String s = rs.getString(columnName);
    return s == null ? null : Enum.valueOf(type, s);
  }

EnumOrdinalTypeHandler 是将字段值(必须数字类型)作为枚举下标搜索对应枚举对象.部分源码如下

  @Override
  public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
    int i = rs.getInt(columnName);
    if (rs.wasNull()) {
      return null;
    } else {
      try {
        return enums[i];
      } catch (Exception ex) {
        throw new IllegalArgumentException("Cannot convert " + i + " to " + type.getSimpleName() + " by ordinal value.", ex);
      }
    }
  }

int i = rs.getInt(columnName); i是返回字段值,然后通过return enums[i];返回对应下标枚举对象。

但是很多时候码是根据业务确定的不一定是按照枚举下标来表示的。没办法这个时候只能自己动手,但是可以参考EnumOrdinalTypeHandler 做法,替换return enums[i];代码
自定义枚举类型转换器MyEnumTypeHandler完整代码如下:

    public class MyEnumTypeHandler<E extends Enum<E>&BaseEnum<E>> extends BaseTypeHandler<E> {

    private Class type;
    private E[] enums;

    public MyEnumTypeHandler(Class type) throws InstantiationException, IllegalAccessException{

        if (type == null) {
              throw new IllegalArgumentException("Type argument cannot be null");
         }

        this.type=type;
        this.enums=this.type.getEnumConstants();

        if(this.enums==null){
             throw new IllegalArgumentException(type.getSimpleName() + " does not represent an enum type.");
        }       
    }

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

    }

    @Override
    public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
         int i = rs.getInt(columnName);
            if (rs.wasNull()) {
              return null;
            } else {
              try {
                return getEnum(i);
              } catch (Exception ex) {
                throw new IllegalArgumentException("Cannot convert " + i + " to " + type.getSimpleName() + " by ordinal value.", ex);
              }
            }
    }

    @Override
    public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
         int i = rs.getInt(columnIndex);
            if (rs.wasNull()) {
              return null;
            } else {
              try {
                return getEnum(i);
              } catch (Exception ex) {
                throw new IllegalArgumentException("Cannot convert " + i + " to " + type.getSimpleName() + " by ordinal value.", ex);
              }
            }
    }

    @Override
    public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        int i = cs.getInt(columnIndex);
        if (cs.wasNull()) {
          return null;
        } else {
          try {
            return getEnum(i);
          } catch (Exception ex) {
            throw new IllegalArgumentException("Cannot convert " + i + " to " + type.getSimpleName() + " by ordinal value.", ex);
          }
        }
    }

    private E getEnum(int code){

        for(E tmpE:this.enums){

            if(tmpE.getCode()==code){
                return tmpE;
            }
        }
        return null;
    }
}

BaseEnum 代码:

public interface BaseEnum {

    int getCode();

    String getName();   

    T getEnumByCode(int code);
}

BaseEnum 接口是所有枚举必须继承,主要为了统一性。这样一个TypeHandler可以实现很多自定义enum.
在完成typeHandler之后需要将其加入到mybatis 配置文件中。

<typeHandlers>
        <typeHandler handler="com.test.mybatis.typeHandler.MyEnumTypeHandler" javaType="XXEnum" />
    typeHandlers>

考虑到如果很多枚举出现,不能都要修改一次配置文件,而且变化仅仅是javaType。后来发现mybatis提供一个MappedTypes 注解。只要在自定义typeHandler上实现即可。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MappedTypes {
  Class[] value();
}

这个注解value是数组类型,所以可以更方便添加。这样mybatis配置文件中只要将javaType属性去掉即可,后期再多枚举也不用改动mybatis配置文件,只要在MappedTypes注解里加新枚举即可。

你可能感兴趣的:(mybatis)