1 TypeHandler的使用场景
在我们的项目中,可能会涉及到状态类型的枚举到数据库字段的映射转换,此时就需要使用TypeHandler,
对应数据库支付表中pay_type字段,这里就需要定义一个类型转换TypeHandler,来把枚举中的code映射到数据库中
2 TypeHandler原理
无论是用Spring DataJpa, Hibernate,Mybatis 或者Mybatis-plus,其最终都是使用的Jdbc,而Jdbc操作数据需要模板式的7步操作,在使用Mybatis #{} 占位符式设置值的时候,使用的就是PreparedStatement对象,通过占位符的下标位置,以及对应Value进行赋值,在查询的时候,返回的结果集为ResultSet,通过指针的方式,get出来获取到指定行
,
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public interface TypeHandler<T> {
/**
* java属性->数据库字段映射 占位符赋值操作
*/
void setParameter(PreparedStatement var1, int var2, T var3, JdbcType var4) throws SQLException;
/**
* 下面3个方法 都是数据库字段->java属性 数据库字段映射java属性操作
*/
T getResult(ResultSet var1, String var2) throws SQLException;
T getResult(ResultSet var1, int var2) throws SQLException;
T getResult(CallableStatement var1, int var2) throws SQLException;
}
3 自定义TypeHandler使用
mybatis中抽象类BaseTypeHandler已经实现了TypleHandler接口,我们直接继承它就好
public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {....}
4 实现LocalDateTime的TypeHanlder转换
自定义TypeHandler,添加泛型为LocalDateTime
@MappedJdbcTypes(JdbcType.VARCHAR) // 数据库中该字段存储的类型
@MappedTypes(LocalDateTime.class) // 需要转换的对象
public class MyLocalDateTimeTypeHanlder extends BaseTypeHandler<LocalDateTime> {
private static DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
/*
* java属性 - > db属性
*/
@Override
public void setNonNullParameter(PreparedStatement ps, int i, LocalDateTime localDateTime, JdbcType jdbcType) throws SQLException {
// 这里需要把LocalDateTime格式化成标准的数据格式,否则数据库中字段属性为varchar而不是datetime,则会出现毫秒后面多出几位的情况
String formatStr = localDateTime.format(df);
// 这里setObject的原因是 ps.setXXX()只有常见的基本类型,LocalDateTime不属于其中,故需setObject
ps.setObject(i, formatStr);
}
/*
* 如下3个方法都是 db - > java 即查询出来的数据 -> java属性映射
*/
@Override
public LocalDateTime getNullableResult(ResultSet resultSet, String s) throws SQLException {
// 返回的时候也需要格式化,变成标准格式
LocalDateTime localDateTime = LocalDateTime.parse(s, df);
return localDateTime;
}
@Override
public LocalDateTime getNullableResult(ResultSet resultSet, int i) throws SQLException {
return resultSet.getObject(i,LocalDateTime.class);
}
@Override
public LocalDateTime getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return callableStatement.getObject(i, LocalDateTime.class);
}
}
5 实际应用,只需要在对应的注解上加上即可
如下图,当数据库createTime为varchar类型时
没有转换之前(第一个行)和转换后的效果如下,使用自定义TypeHandler后,转换后正常,为标准的的:yyyy-MM-dd HH:mm:ss格式
6 实现普通枚举的TypeHanlder转换
public enum PayTypeEnum {
//
WECHAT(1, "微信"),
ALIPAY(2, "支付宝"),
UNION(3, "银联"),
;
private Integer code;
private String msg;
PayTypeEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer code() {
return code;
}
public String msg() {
return msg;
}
public static PayTypeEnum parse(Integer code) {
for (PayTypeEnum value : values()) {
if (value.code.equals(code)) {
return value;
}
}
return null;
}
}
定义该枚举的TypeHandler
@MappedJdbcTypes(JdbcType.INTEGER)
@MappedTypes(PayTypeEnum.class)
public class MyEnumTypeHanlder extends BaseTypeHandler<PayTypeEnum> {
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, PayTypeEnum payTypeEnum, JdbcType jdbcType) throws SQLException {
// 枚举code对应的数据库字段类型
preparedStatement.setInt(i,PayTypeEnum.code());
}
@Override
public PayTypeEnum getNullableResult(ResultSet resultSet, String columName) throws SQLException {
// 根据字段名获取枚举code值
int code = resultSet.getInt(columName);
PayTypeEnum instance = PayTypeEnum.parse(code);
return instance;
}
@Override
public PayTypeEnum getNullableResult(ResultSet resultSet, int columIndex) throws SQLException {
int code = resultSet.getInt(columIndex);
PayTypeEnum instance = PayTypeEnum.parse(code);
return instance;
}
@Override
public PayTypeEnum getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return null;
}
}
7 所用依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
8 配置扫包
如果为mybatis-plus 则在yml文件中加入如下配置:
# mybatis-plus 配置 typeHandler
mybatis-plus:
type-handlers-package: 你的自定义typeHandler所在包
如果为mybatis 则去掉前缀中 -plus即可