Skip to content

Mybatis-Plus 自定义类型转换器

在Mybatis中,对于特殊类型的处理,需要使用TypeHandler进行转换,同样的Mybatis-Plus提供了对类型转换的支持。

Mybatis 中使用自定义类型转换器

  1. 首先创建自定义的类型转换器,可以实现org.apache.ibatis.type.TypeHandler接口,或者直接继承org.apache.ibatis.type.BaseTypeHandler

例如这里我们对Postgresql中的json类型进行转换,选择继承org.apache.ibatis.type.BaseTypeHandler的方式如下:

java
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的序列化与反序列化的逻辑定义在抽象类中,实现了setNonNullParametergetNullableResult方法,这样我们只需要在对应类型的类型转换器中通过实现getType方法返回其对应的类型即可。

  1. Mapper.xml中配置对应的类型转换器,例如:
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>
java
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注解来配置对应的表和字段,在这两个注解中同样也提供了对类型转换器的配置。

java
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;
}
java
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.xmlselect标签中不使用resultMap属性而是使用resultType属性,这样在mybatis中进行结果集映射时就不会使用到typeHandler了。

Mybatis-Plus 2.x 中使用自定义类型转换器

在实际使用过程中一些老项目使用的是Mybatis-Plus 2.x的版本,由于2.x3.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}是一样的。
java
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;
}
java
import com.example.entity.User;

public class UserJsonHandler extends AbstractJsonHandler<User> {
    @Override
    public Class<User> getType() {
        return User.class;
    }
}
java
<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>