处理enum在实体类跟mysql(Integer/Varchar)类型间的转换
首先,构建一个基础的抽象接口BaseEnum,EnumCodeType
public interface BaseEnum<T>{
T getCode();
String getMessage();
}
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public enum EnumCodeType {
Integer {
public Object getObject(ResultSet rs, String columnName) throws SQLException {
return rs.getInt(columnName);
}
public Object getObject(ResultSet rs, int columnIndex) throws SQLException {
return rs.getInt(columnIndex);
}
public Object getObject(CallableStatement cs, int columnIndex) throws SQLException {
return cs.getObject(columnIndex);
}
},
String {
public Object getObject(ResultSet rs, String columnName) throws SQLException {
return rs.getString(columnName);
}
public Object getObject(ResultSet rs, int columnIndex) throws SQLException {
return rs.getString(columnIndex);
}
public Object getObject(CallableStatement cs, int columnIndex) throws SQLException {
return cs.getString(columnIndex);
}
};
private EnumCodeType() {
}
public abstract Object getObject(ResultSet rs, String columnName) throws SQLException;
public abstract Object getObject(ResultSet rs, int columnIndex) throws SQLException;
public abstract Object getObject(CallableStatement cs, int columnIndex) throws SQLException;
}
其中EnumCodeType是为了确定枚举code类型(存储到mysql中的值),支持Integer、String两种类型
接着构建一个默认的枚举处理器DefaultEnumTypeHandler
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.kw.framework.common.croe.enums.BaseEnum;
import com.kw.framework.common.croe.enums.EnumCodeType;
import com.kw.framework.common.croe.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 枚举,字符串互转
* @param <E>
*/
@MappedTypes(value = { BaseEnum.class })
@MappedJdbcTypes(value = {JdbcType.VARCHAR,JdbcType.CHAR,JdbcType.INTEGER})
@Slf4j
public class DefaultEnumTypeHandler<E extends Enum<E> & BaseEnum<?>> extends BaseTypeHandler<E> {
private Class<E> type;
private E[] baseEnum;
private EnumCodeType enumCodeType;
public DefaultEnumTypeHandler(Class<E> type) {
if (type == null) {
throw new IllegalArgumentException("Type argument cannot be null");
}
this.type = type;
this.baseEnum = type.getEnumConstants();
Class<?> clazz = (Class<?>) ((ParameterizedType) getInterfaceBaseEnum(type)).getActualTypeArguments()[0];
this.enumCodeType = clazz.getName().equals("java.lang.String") ? EnumCodeType.String : EnumCodeType.Integer;
if (this.baseEnum == null) {
throw new IllegalArgumentException(type.getSimpleName() + " does not represent an enum type.");
}
}
private Type getInterfaceBaseEnum(Class<E> type) {
Type[] types = type.getGenericInterfaces();
for (Type t : types) {
if (t.getTypeName().contains(BaseEnum.class.getName())) {
return t;
}
}
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 {
if (enumCodeType == EnumCodeType.String) {
ps.setString(i, (String) parameter.getCode());
} else {
if (jdbcType == JdbcType.VARCHAR) {
ps.setString(i, String.valueOf(parameter.getCode()));
} else if (jdbcType != null) {
ps.setObject(i, parameter.getCode(), jdbcType.TYPE_CODE);
} else {
Class<?> codeType = parameter.getCode().getClass();
if (codeType.equals(String.class)) {
ps.setString(i, String.valueOf(parameter.getCode()));
} else if (codeType.equals(Integer.class)) {
ps.setInt(i, (Integer) parameter.getCode());
} else {
throw new BusinessException("系统错误");
}
}
}
}
@Override
public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
return getEnum(rs, enumCodeType.getObject(rs, columnName));
}
@Override
public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
// 根据数据库存储类型决定获取类型,本例子中数据库中存放String类型
return getEnum(rs, enumCodeType.getObject(rs, columnIndex));
}
private E getEnum(ResultSet rs, Object object) throws SQLException {
if (enumCodeType == EnumCodeType.String && StringUtils.isBlank(String.valueOf(object))) {
return null;
}
if (object == null || rs.wasNull())
return null;
return selectEnum(object);
}
@Override
public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
// 根据数据库存储类型决定获取类型,本例子中数据库中存放String类型
Object object = enumCodeType.getObject(cs, columnIndex);
if (object == null || cs.wasNull())
return null;
return selectEnum(object);
}
/**
* 枚举类型转换,由于构造函数获取了枚举的子类enums,让遍历更加高效快捷
*
* @param value 数据库中存储的自定义value属性
* @return value对应的枚举类
*/
public E selectEnum(Object value) {
for (E e : baseEnum) {
if (e.getCode().equals(value)) {
return e;
}
}
log.error("未知的枚举类型:{},请核对: {}", value, type.getSimpleName());
throw new BusinessException("not found enum");
}
}
最后在application.yml中加入一下配置:
mybatis-plus:
configuration:
default-enum-type-handler: com.kw.framework.mybatis.interfaces.DefaultEnumTypeHandler #枚举转string处理器
使用demo:
新建一个枚举MenuTypeEnum,实现BaseEnum:
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.stream.Stream;
/**
* 菜单类型
*/
@Getter
@AllArgsConstructor
public enum MenuTypeEnum implements BaseEnum<String>{
/**
* 左侧菜单
*/
LEFT_MENU("0", "left"),
/**
* 顶部菜单
*/
TOP_MENU("2", "top"),
/**
* 按钮
*/
BUTTON("1", "button");
/**
* 类型
*/
private final String code;
/**
* 描述
*/
private final String message;
@Override
public String getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
public MenuTypeEnum convertCode(String code) {
return Stream.of(values())
.filter(bean -> bean.code.equals(code))
.findAny()
.orElse(null);
}
public MenuTypeEnum convertMessage(String message) {
return Stream.of(values())
.filter(bean -> bean.message.equals(message))
.findAny()
.orElse(null);
}
}
后面只需要在实体类中使用MenuTypeEnum类型定义变量,在处理sql时会自动将MenuTypeEnum转换为String存储到mysql,在查询时会将String转为MenuTypeEnum
小小enum在excel导入导出的处理
前提:使用easyExcel做导入导出操作
构建枚举-字符串转换器EnumToStringConvert
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.kw.framework.common.croe.enums.BaseEnum;
import java.lang.reflect.Field;
import java.util.stream.Stream;
public class EnumToStringConvert implements Converter<Object> {
@Override
public Class<?> supportJavaTypeKey() {
return Object.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
/**
* 导入转换
* @param cellData 当前单元格对象
* @param contentProperty 当前单元格属性
* @param globalConfiguration
* @return 当返回null时表示无对应的枚举值,在处理业务时可以根据是否为null来判断是否抛异常
* @throws Exception
*/
@Override
public Object convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
String cellMsg = cellData.getStringValue();
Field field = contentProperty.getField();
Class<? extends BaseEnum> c = (Class<? extends BaseEnum>) field.getType();
return Stream.of(c.getEnumConstants())
.filter(bean -> bean.getMessage().equals(cellMsg))
.findAny()
.orElse(null);
}
/**
* 导出转化
* @param value 当前值
* @param contentProperty 当前单元格属性
* @param globalConfiguration
* @return
* @throws Exception
*/
@Override
public WriteCellData<?> convertToExcelData(Object value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
BaseEnum baseEnum = (BaseEnum) value;
return new WriteCellData(baseEnum.getMessage());
}
}
使用时只需要在枚举类对应的变量上指定converter为EnumToStringConvert即可
使用demo:
@ExcelProperty(index = 1,converter = EnumToStringConvert.class)
private MenuTypeEnum menuTypeEnum ;