版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/joefany/article/details/82467908
因项目需要,在项目中需要实现mybatis 的枚举自动转换。
具体要求:可以根据枚举自定义属性在mybatis中自动转换。
1.先定义一个枚举基类
/**
* 枚举基类
* @author joefan
* @create 2018年9月6日10:42:11
*/
public interface Identifiable {
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("Identifiable value should not be null");
if (enumClass.isAssignableFrom(Identifiable.class))
throw new IllegalArgumentException("illegal Identifiable type");
T[] enums = enumClass.getEnumConstants();
for (T t : enums) {
Identifiable displayedEnum = (Identifiable) t;
if (displayedEnum.getValue().equals(value))
return (T) displayedEnum;
}
throw new IllegalArgumentException("cannot parse integer: " + value + " to " + enumClass.getName());
}
}
2.修改 SqlSessionFactoryBean方法,加入以下代码
// 1.加入属性和get set 方法
//我们自定义的属性,扫描Enum的base package
private String enumBasePackage;
//我们自定义的属性,扫描Alias的base package
private String aliasBasePackage;
public String getEnumBasePackage() {
return enumBasePackage;
}
public void setEnumBasePackage(String enumBasePackage) {
this.enumBasePackage = enumBasePackage;
}
public String getAliasBasePackage() {
return aliasBasePackage;
}
public void setAliasBasePackage(String aliasBasePackage) {
this.aliasBasePackage = aliasBasePackage;
}
// 2.在buildSqlSessionFactory方法中加入以下代码
//alias
if (null != this.aliasBasePackage && this.aliasBasePackage.trim().length() > 0) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
resolverUtil.find(new ResolverUtil.IsA(BaseEntity.class), this.aliasBasePackage);
//resolverUtil.find(new ResolverUtil.IsA(Identifiable.class), this.aliasBasePackage);
Set<Class<? extends Class<?>>> mTypes = resolverUtil.getClasses();
for (Class<?> javaTypeClass : mTypes) {
logger.debug("Registered Alias : '" + javaTypeClass.getName() + "'");
configuration.getTypeAliasRegistry().registerAlias(javaTypeClass);
}
}
//enum
if (this.enumBasePackage != null && this.aliasBasePackage.trim().length() > 0) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
resolverUtil.find(new ResolverUtil.IsA(Identifiable.class), this.enumBasePackage);
Set<Class<? extends Class<?>>> mTypes = resolverUtil.getClasses();
for (Class<?> javaTypeClass : mTypes) {
logger.debug("Registered Enum type handler: '" + javaTypeClass.getName() + "'->"+ EnumOrdinalTypeHandler.class.getName());
configuration.getTypeAliasRegistry().registerAlias(javaTypeClass.getName(), javaTypeClass);
configuration.getTypeAliasRegistry().registerAlias(javaTypeClass.getName().replace("$", "."), javaTypeClass);
configuration.getTypeHandlerRegistry().register(javaTypeClass, DefaultEnumTypeHandler.class);
}
}
BaseEntity为实体类继承的基类,
Identifiable为枚举实现的接口
DefaultEnumTypeHandler为转换器,使我们自定义的,为了满足根据枚举自定义属性在mybatis中自动转换,如果只需要枚举的属性的下标转换只需要用默认的 mybatis的EnumOrdinalTypeHandler就行了
3.DefaultEnumTypeHandler转换器
public class DefaultEnumTypeHandler extends BaseTypeHandler<Identifiable> {
private Class<Identifiable> type;
public DefaultEnumTypeHandler(){};
public DefaultEnumTypeHandler(Class<Identifiable> type) {
if (type == null) throw new IllegalArgumentException("Type argument cannot be null");
this.type = type;
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Identifiable parameter, JdbcType jdbcType)
throws SQLException {
ps.setInt(i, parameter.getValue());
}
@Override
public Identifiable getNullableResult(ResultSet rs, String columnName) throws SQLException {
return convert(rs.getInt(columnName));
}
@Override
public Identifiable getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return convert(rs.getInt(columnIndex));
}
@Override
public Identifiable getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return convert(cs.getInt(columnIndex));
}
private Identifiable convert(int status){
Identifiable[] objs = type.getEnumConstants();
for(Identifiable em: objs){
if(em.getValue() == status){
return em;
}
}
return null;
}
}
4.在spring的配置文件中配置 sqlSessionFactory的属性,用于配置扫描的包路径
<property name="aliasBasePackage" value="com.joefan.entity" />
<property name="enumBasePackage" value="com.joefan.entity" />
5.用法
/**
* 类型
*/
public enum Type implements Identifiable {
many("many", 10),
some("some", 20);
String label;
Integer value;
Type(String label, Integer value) {
this.label = label;
this.value = value;
}
}
这样我们就可以根据10或者20 和枚举相互转换了
搞定!