Mybatis使用自定义枚举
# MyBatis使用自定义枚举
# 背景
通常我们会使用类似 1==男,2==女的数据类型在mysql中进行存储。 但是这种数据类型不不易于维护的,在类型过多的情况下经常会忘记int值的含义。所以大多情况下会使用枚举类,示例如下:
@AllArgsConstructor
@Getter
public enum SexType {
/***/
BOY(1,"男"),
GIRL(2,"女");
private final Integer code;
private final String val;
}
# 实现
mybatis 默认的类型转换类为 BaseTypeHandler
通过观察BaseTypeHandler 子类,我们发现了EnumTypeHandler 再观察实现,发现他使用的是 parameter.name() 和Enum.valueOf() 看这里到能清楚的知道默认使用的是Enum.name()值,对应我们的枚举SexType也就是BOY/GIRL,显然不符合我们需要存储Enum.code值的需求。 所有我们需要自定义一个枚举转换器
# 1. 首先定义一个公共接口 BaseBizEnum
public interface BaseBizEnum {
/**
* 得到枚举code,对应数据库int值
* @return int
*/
Integer getCode();
/**
* 得到枚举值 ,对应前端显示值
* @return str
*/
String getVal();
}
# 2. 改造下之前的枚举类
@AllArgsConstructor
@Getter
public enum SexType implements BaseBizEnum {
/***/
BOY(1,"男"),
GIRL(2,"女");
private final Integer code;
private final String val;
}
# 3.自定义枚举处理器基类
@Slf4j
public class BizEnumTypeHandler<E extends BaseBizEnum> extends BaseTypeHandler<BaseBizEnum> {
private Class<E> type;
//初始化时定义枚举和code的映射关系
private final Map<Integer,E> enumsMap = new HashMap<>();
public BizEnumTypeHandler() {
}
public BizEnumTypeHandler(Class<E> type) {
if (type == null) {
throw new IllegalArgumentException("Type argument cannot be null");
}
this.type = type;
for (E enumConstant : type.getEnumConstants()) {
enumsMap.put(enumConstant.getCode(),enumConstant);
}
if (this.enumsMap.size() == 0) {
throw new IllegalArgumentException(type.getSimpleName() + " does not represent an enum type.");
}
}
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, BaseBizEnum baseBizEnum, JdbcType jdbcType) throws SQLException {
preparedStatement.setInt(i,baseBizEnum.getCode());
}
@Override
public BaseBizEnum getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
if (resultSet.wasNull()) {
return null;
}
int code = resultSet.getInt(columnName);
return getEnum(code);
}
@Override
public BaseBizEnum getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException {
if (resultSet.wasNull()) {
return null;
}
int code = resultSet.getInt(columnIndex);
return getEnum(code);
}
@Override
public BaseBizEnum getNullableResult(CallableStatement callableStatement, int columnIndex) throws SQLException {
if (callableStatement.wasNull()) {
return null;
}
int code = callableStatement.getInt(columnIndex);
return getEnum(code);
}
private E getEnum(Integer code) {
try {
return getEnumByValue(code);
} catch (Exception ex) {
throw new IllegalArgumentException(
"Cannot convert " + code + " to " + type.getSimpleName() + " by ordinal value.", ex);
}
}
protected E getEnumByValue(Integer code) {
return enumsMap.get(code);
}
}
到了这一步,相信懂行的同学都已经明白啥意思了。很简单就是在构造器里简历 code-enum 的对应关系,存储时直接存储枚举的code值,取出时通过code值得到枚举值。那么问题来了,构造器啥时候调用呢。继续往下看。。。
# 4.指定枚举处理器
@MappedTypes(value = {SexType.class})
@MappedJdbcTypes(value = {JdbcType.INTEGER,JdbcType.TINYINT,JdbcType.SMALLINT})
public class SexTypeEnumTypeHandler extends BizEnumTypeHandler<SexType> {
/**
* 实例化时使用父类构造器
*/
public SexTypeEnumTypeHandler() {
super(SexType.class);
}
}
# 5.加入配置
mybatis:
type-handlers-package: com.xxx
到这里一切就结束了。此时如果有对象属性SexType==SexType.BOY 数据库将会存储1,SexType.GIRL 同理存储2。 获取时1,2将自动转换为SexType.BOY,SexType.GIRL。下面附上测试类有兴趣的同学可自行测试
@RestController
@RequestMapping(value = "/sex")
public class SexController {
@Resource
private TestSexMapper testSexMapper;
@GetMapping(value = "insertTest")
public Object insertTest(String name, SexType sexType) {
MdcUtil.put("开始");
System.out.println("name="+name+",agreementType="+sexType.name());
return testSexMapper.insert(name,sexType);
}
@GetMapping(value = "getTest")
public Object getTest( ) {
MdcUtil.put("开始");
return testSexMapper.selectByName();
}
}
public interface TestSexMapper {
@Insert("insert into test_agreement_info(name,agreement_type) value(#{name},#{sexType})")
boolean insert(@Param("name") String name, @Param("agreementType") SexType sexType);
@Select("select * from test_agreement_info")
List<TestSexModel> selectByName();
}
@Data
public class TestSexModel implements Serializable {
private static final long serialVersionUID = 3285353798809906968L;
private String name;
private SexType sexType;
}
上次更新: 2024/11/05, 08:29:31