在上一篇文章 Mybatis 结合枚举类型 中提到,Mybatis 为枚举类型提供类两种类型控制器,最终体现都效果就是,对于枚举类型要么存储枚举名,要么存储索引值,如果我们想存储别的值怎么办呢?这就是本文要涉及都内容了。
通过实现 TypeHandler 接口可以实现自定义类型处理器,然后通过一定的配置,就可以使用你喜欢的数据转化效果了。
这个过程的本质是你可以控制数据库插入的数据的最终形态,也可以根据数据库存储数据的形态转化为你期望的形态
//EnumTypeHandler
org.apache.ibatis.type.EnumTypeHandler
//EnumOrdinalTypeHandler
org.apache.ibatis.type.EnumOrdinalTypeHandler
enum 枚举类型定义常量及调用的应用举例
看 第三种-重点关注里面包含的静态方法 即可
有了前面的试探,我们这次简化实验,只用一个字段对应枚举类型
create table ENUM_DEMO
(
ID bigint not null
primary key,
STR2 varchar(32) null,
);
public enum Str2Enum {
INIT("init","初始化"),
ACTIVE("active","激活"),
FREEZE("freeze","冻结");
private String key;
private String value;
public String getKey() {
return key;
}
public String getValue() {
return value;
}
Str2Enum(String key,String value){
this.key=key;
this.value=value;
}
/**
* 根据key值得到对应的枚举类型
* @param columnName
* @return
*/
public static Str2Enum getStr2EnumByKey(String key){
if("init".equals(key)){
return INIT;
}else if("active".equals(key)){
return ACTIVE;
}else if("freeze".equals(key)){
return FREEZE;
}
return null;
}
/**
* 根据枚举 value 返回枚举
* @param value
* @return
*/
public static Str2Enum getStr2EnumByValue(String value){
if("初始化".equals(value)){
return INIT;
}else if("激活".equals(value)){
return ACTIVE;
}else if("冻结".equals(value)){
return FREEZE;
}
return null;
}
/**
* 根据枚举名字返回类型
* @param name
* @return
*/
public static Str2Enum getStr2EnumByName(String columnName){
return Str2Enum.valueOf(columnName);
}
/**
* 根据索引数返回枚举类型
* @param index
* @return
*/
public static Str2Enum getStr2EnumByIndex(int index){
return Str2Enum.values()[index];
}
public static void main(String[] args) {
System.out.println("输出枚举名字:"+Str2Enum.ACTIVE);
System.out.println("输出枚举key:"+Str2Enum.ACTIVE.getKey());
System.out.println("输出枚举value:"+Str2Enum.ACTIVE.getValue());
System.out.println("根据 value 值获取枚举:"+Str2Enum.getStr2EnumByValue("冻结"));
System.out.println("根据 key 值获取枚举:"+Str2Enum.getStr2EnumByKey("init"));
System.out.println("根据序数获取枚举:"+Str2Enum.getStr2EnumByIndex(0));
System.out.println("根据 枚举名字 值获取枚举:"+Str2Enum.getStr2EnumByName("INIT"));
}
}
如果你对代码逻辑有疑问,请参考本文中关于源码的类的内容
由于存在自定义内容,你也需要参考枚举类中的静态方法
数据库的值-对应枚举类的那个值-静态方法转化为枚举类型
枚举类型-对应枚举的某个值-数据库中的值
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import com.bestcxx.stu.springmybatis.enums.Str2Enum;
public class Str2EnumTypeHandler implements TypeHandler<Str2Enum> {
@Override
public void setParameter(PreparedStatement ps, int i, Str2Enum parameter, JdbcType jdbcType) throws SQLException {
//比如我们希望存储的是枚举类型的 key
ps.setString(i, parameter.getKey());
}
@Override
public Str2Enum getResult(ResultSet rs, String columnName) throws SQLException {
//获取数据库中的值
String key=rs.getString(columnName);
//根据之前存储的规则,这个值是 枚举 的 key ,所以根据枚举的key获取枚举
return Str2Enum.getStr2EnumByKey(key);
}
@Override
public Str2Enum getResult(ResultSet rs, int columnIndex) throws SQLException {
//获取数据库中的值
String key =rs.getString(columnIndex);
//根据之前存储的规则,这个值是 枚举 的 key ,所以根据枚举的key获取枚举
return Str2Enum.getStr2EnumByKey(key);
}
@Override
public Str2Enum getResult(CallableStatement cs, int columnIndex) throws SQLException {
//获取数据库中的值
String key=cs.getString(columnIndex);
//根据之前存储的规则,这个值是 枚举 的 key ,所以根据枚举的key获取枚举
return Str2Enum.getStr2EnumByKey(key);
}
}
<table tableName="ENUM_DEMO" domainObjectName="EnumDemoEntity" enableCountByExample="false"
enableDeleteByExample="false" enableSelectByExample="false" enableUpdateByExample="false">
<columnOverride column="STR2" jdbcType="VARCHAR" javaType="com.bestcxx.stu.springmybatis.enums.Str2Enum" typeHandler="com.bestcxx.stu.springmybatis.typehandler.Str2EnumTypeHandler"></columnOverride>
</table>
<result column="STR2" property="str2" jdbcType="VARCHAR" typeHandler="com.bestcxx.stu.springmybatis.typehandler.Str2EnumTypeHandler" />
#{str2,jdbcType=VARCHAR,typeHandler=com.bestcxx.stu.springmybatis.typehandler.Str2EnumTypeHandler},
@Test
public void test(){
EnumDemoEntity record=new EnumDemoEntity();
record.setId(1l);
record.setStr2(Str2Enum.INIT);
enumDemoEntityMapper.insert(record);
System.out.println(enumDemoEntityMapper.selectByPrimaryKey(1l).getStr2().toString());
}
这里我们使用了直接在具体属性上指定 typeHandler 的方式,我觉得这是最简单的,但是比如你有其他的需求,对于字符串类型的所有字段都有一个需求,比如加密,你不希望每一个字段都写一下,那么就可以采取其他方法了。
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.apache.ibatis.type.TypeHandler;
@MappedTypes(String.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class Str2EnumTypeHandler implements TypeHandler<Str2Enum> {//内容略}
<typeHandlers>
<typeHandler handler="com.bestcxx.stu.springmybatis.typehandler.Str2EnumTypeHandler"/>
typeHandlers>
这个需要在 xml 映射文件配置了,两个都指定,Mybatis 如果匹配到两个类型和具有 @MappedTypes、@MappedJdbcTypes 注解一致到类型就会自动调用对应到类型控制了。
根据实验,会调用最后一个
<typeHandlers>
<typeHandler handler="com.bestcxx.stu.springmybatis.typehandler.Str2EnumTypeHandler2"/>
<typeHandler handler="com.bestcxx.stu.springmybatis.typehandler.Str2EnumTypeHandler"/>
typeHandlers>