Mybatis-Plus 自定义类型转换器
在Mybatis中,对于特殊类型的处理,需要使用TypeHandler进行转换,同样的Mybatis-Plus提供了对类型转换的支持。
Mybatis 中使用自定义类型转换器
- 首先创建自定义的类型转换器,可以实现
org.apache.ibatis.type.TypeHandler接口,或者直接继承org.apache.ibatis.type.BaseTypeHandler。
例如这里我们对Postgresql中的json类型进行转换,选择继承org.apache.ibatis.type.BaseTypeHandler的方式如下:
import com.alibaba.fastjson2.JSON;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.postgresql.util.PGobject;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public abstract class AbstractJsonHandler<T> extends BaseTypeHandler<T> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
T parameter, JdbcType jdbcType) throws SQLException {
PGobject obj = new PGobject();
obj.setType("json");
obj.setValue(JSON.toJSONString(parameter));
ps.setObject(i, obj);
}
@Override
public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
return JSON.parseObject(rs.getString(columnName), getType());
}
@Override
public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return JSON.parseObject(rs.getString(columnIndex), getType());
}
@Override
public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return JSON.parseObject(cs.getString(columnIndex), getType());
}
public abstract Class<T> getType();
}这里我们创建了一个抽象类,和BaseTypeHandler一样我们使用了模板方法的设计模式,将json的序列化与反序列化的逻辑定义在抽象类中,实现了setNonNullParameter、getNullableResult方法,这样我们只需要在对应类型的类型转换器中通过实现getType方法返回其对应的类型即可。
- 在
Mapper.xml中配置对应的类型转换器,例如:
<mapper namespace="com.example.mapper.UserMapper">
<resultMap id="BaseResultMap" type="com.example.entity.User">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="ext" property="ext" jdbcType="OTHER"
typeHandler="com.example.handler.UserJsonHandler"/>
</resultMap>
<select id="selectById" resultMap="BaseResultMap">
select * from user where id = #{id}
</select>
<insert id="insert" parameterType="com.example.entity.User">
insert into user (id, ext)
values
(#{id}, #{ext, typeHandler=com.example.handler.UserJsonHandler})
</insert>
</mapper>import com.example.entity.User;
public class UserJsonHandler extends AbstractJsonHandler<User> {
@Override
public Class<User> getType() {
return User.class;
}
}Mybatis-Plus 中使用自定义类型转换器
在Mybatis-Plus中,我们通过在实体类上添加@TableName和@TableField注解来配置对应的表和字段,在这两个注解中同样也提供了对类型转换器的配置。
package com.example.entity;
@Data
@TableName(value = "user", autoResultMap = true)
public class User {
@TableId
private Integer id;
@TableField(value = "ext", typeHandler = UserJsonHandler.class)
private User ext;
}import com.example.entity.User;
public class UserJsonHandler extends AbstractJsonHandler<User> {
@Override
public Class<User> getType() {
return User.class;
}
}在@TableName中我们添加了autoResultMap属性,这个属性表示是否自动创建ResultMap,默认为false,设置为true后,Mybatis-Plus会自动创建一个ResultMap,并使用@TableField中配置的typeHandler进行类型转换。如果不设置autoResultMap属性,在查询方法中就不会使用ResultMap,而是直接使用ResultSet进行结果映射,相当于在Mapper.xml中select标签中不使用resultMap属性而是使用resultType属性,这样在mybatis中进行结果集映射时就不会使用到typeHandler了。
Mybatis-Plus 2.x 中使用自定义类型转换器
在实际使用过程中一些老项目使用的是Mybatis-Plus 2.x的版本,由于2.x和3.x的版本存在较大的一些差异,所以没有对版本进行升级,但2.x其实也是可以实现自定义类型转换器的,毕竟Mybatis-Plus只是对Mybatis的增强。
@TableName没有autoResultMap属性: 2.x中该注解没有自动创建ResultMap的功能,但可以指定ResultMap,所以我们需要手动创建一个ResultMap,然后在该注解中指定该ResultMap。@TableField没有typeHandler属性: 2.x中该注解没有typeHandler属性,但可以通过el属性来指定类型转换器,它和在xml中使用#{ext, typeHandler=com.example.handler.UserJsonHandler}是一样的。
package com.example.entity;
@Data
@TableName(value = "user", resultMap = "BaseResultMap")
public class User {
@TableId
private Integer id;
@TableField(el = "ext, typeHandler=com.example.handler.UserJsonHandler")
private User ext;
}import com.example.entity.User;
public class UserJsonHandler extends AbstractJsonHandler<User> {
@Override
public Class<User> getType() {
return User.class;
}
}<mapper namespace="com.example.mapper.UserMapper">
<resultMap id="BaseResultMap" type="com.example.entity.User">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="ext" property="ext" jdbcType="OTHER"
typeHandler="com.example.handler.UserJsonHandler"/>
</resultMap>
</mapper>