无情的你无情的雨 2018-12-02
问题描述
实体中的属性使用枚举和boolean会增加代码的可读性,但是实体和数据库的映射上不能很自然地支持,这样导致由于数据库的原因使得实体中属性使用基本类型来代替枚举和boolean。
实体中属性实例如下
private Integer status;// 0:草稿,1:合格 2:优秀 3:退回
private Byte open;//0;关闭 1:打开
在页面,java代码,和sql到处使用数字,使得代码可读性极差,代码越多,时间越长越没法维护。
<#if trainGroup.type==1>
<a href="javascript:" class="zi-lv" onclick="createAllGroup()" >教研组</a>
<#else>
<a href="javascript:" class="zi-lv" onclick="createAllCoop()" >协作组</a>
</#if>
param.setStatus(2); //优秀
或者使用常量(不能保证大家都使用常量,直接使用数字也没有错)param.setStatus(CONST.GOOD); //优秀
select ....
from T_DT_TRAIN_GROUP t .....m.STATUS = 2
使用枚举后的代码如下
<#if trainGroup.type=='JIAOYAN'>
<a href="javascript:" class="zi-lv" onclick="createAllGroup()" >教研组</a>
<#else>
<a href="javascript:" class="zi-lv" onclick="createAllCoop()" >协作组</a>
</#if>
param.setStatus(Status.GOOD);//只能使用枚举,否则编译通不过
select ....
from T_DT_TRAIN_GROUP t .....m.STATUS =${@[email protected]()}
解决办法
在mybatis中实体属性与表字段之间的映射使用TypeHandler机制,mybatis本身提供了两种枚举类型的转换 EnumTypeHandler和EnumOrdinalTypeHandler。
EnumTypeHandler:将枚举值转化成字符串,字符串取枚举值的名称,使用枚举的.name()方法。EnumTypeHandler已经被内置了,只需要将实体属性改成枚举即可,不需要做任何TypeHandler配置,下面是mybatis获得TypeHandler的源码,如果没有匹配上任何TypeHandler,并且属性是枚举类型就使用EnumTypeHandler。
private <T> TypeHandler<T> getTypeHandler(Type type, JdbcType jdbcType) {
Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = TYPE_HANDLER_MAP.get(type);
TypeHandler<?> handler = null;
if (jdbcHandlerMap != null) {
handler = jdbcHandlerMap.get(jdbcType);
if (handler == null) {
handler = jdbcHandlerMap.get(null);
}
}
if (handler == null && type != null && type instanceof Class && Enum.class.isAssignableFrom((Class<?>) type)) {
handler = new EnumTypeHandler((Class<?>) type);
}
@SuppressWarnings("unchecked")
// type drives generics here
TypeHandler<T> returned = (TypeHandler<T>) handler;
return returned;
}
这种方式最简洁,不需要做任何配置,但是要求表字段中存储的是枚举的名称。
EnumOrdinalTypeHandler:将枚举值转换数字,使用的是枚举的.ordinal()方法。如果要使用这种方式必须给每一个枚举类配置一次EnumOrdinalTypeHandler,如下给两个枚举配置同一个
EnumOrdinalTypeHandler,没有配置的枚举会走默认的EnumTypeHandler。
<typeHandlers>
<!-- <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler"
javaType="cn.com.teacher.cistus.dt.entity.TestMenu" /> -->
<typeHandler
handler="org.apache.ibatis.type.EnumOrdinalTypeHandler"
javaType="cn.com.teacher.cistus.dt.enums.EnumTrainGroupType" />
<typeHandler
handler="org.apache.ibatis.type.EnumOrdinalTypeHandler"
javaType="cn.com.teacher.cistus.dt.enums.EnumPortalConfigType" />
</typeHandlers>
sql mapper中如何使用枚举
public class TrainGroup extends AbstractEntity
private EnumTrainGroupType type;//0教研组 1协作组
映射和查询条件中不用任何特殊处理即可使用枚举。
<resultMap id="BaseResultMap" type="cn.com.teacher.cistus.dt.entity.TrainGroup" >
<result column="TYPE" property="type" jdbcType="INTEGER" />
。。。
<if test="type != null" >
TYPE = #{type,jdbcType=INTEGER},
</if>
sql中使用枚举常量
如下示例直接在sql中使用枚举,这样提高了代码的可读性,并且枚举值写错了会报错提示的。type=${@cn.com.teacher.cistus.
枚举常量的获取使用了ongl表达式的功能,${@cn.co。。[email protected]()}是原生的ongl执行静态代码的写法。
枚举值按指定值映射
mybatis本身只提供了上面两种枚举映射方式,如果想映射自定义的值,比如
JIAOYAN(10,"教研组"),XIEZUO(20,"协作组");映射成 10 ,20.
public class EnumValueTypeHandler <E extends Enum & IDBEnum> extends BaseTypeHandler<E>{
private Class<E> type;
// private final E[] enums;
public EnumValueTypeHandler(Class<E> type) {
this.type = type;
E[] enums = type.getEnumConstants();
if (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.getValue());
}
@Override
public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
int i = rs.getInt(columnName);
if (rs.wasNull()) {
return null;
} else {
try {
return DBEnumUtils.getEnumInstance(type,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 DBEnumUtils.getEnumInstance(type,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 DBEnumUtils.getEnumInstance(type,i);
} catch (Exception ex) {
throw new IllegalArgumentException("Cannot convert " + i + " to " + type.getSimpleName() + " by ordinal value.", ex);
}
}
}
}
public enum EnumTrainGroupType implements IDBEnum{
JIAOYAN(10,"教研组"),XIEZUO(20,"协作组");
private int value;
private String name;
EnumTrainGroupType(int value,String name){
this.value=value;
this.name=name;
}
@Override
public int getValue() {
return value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setValue(int value) {
this.value = value;
}
}