欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Mybatis-Plus自定义集合类型的类型处理器详解

程序员文章站 2022-03-01 13:11:38
目录1.配合xml文件2.手动注册两种方法,第一种很麻烦,对mp自带的插入操作有限制,后来改为更简洁的第二种方法1.配合xml文件typehandler/** * 描述:fastjson的集合对象类型...

两种方法,第一种很麻烦,对mp自带的插入操作有限制,后来改为更简洁的第二种方法

1.配合xml文件

typehandler

/**
 * 描述:fastjson的集合对象类型处理器,将mysql表中的json字段映射到实体类中的{@code list<?>}属性
 * 对照mp自带的fastjsontypehandler,自带的类型处理器会把所有的{@code list<?>}都会解析为{@code list<jsonobject>},
 * 这样在遍历其中对象时,调用对象属性的get、set方法就会发送类型转换jsonobject->?,这种情况转换错误。
 * 该处理器必须配合xml文件使用,不然无法获取要解析的对象类型,同时不能配合mp自带的{@link com.baomidou.mybatisplus.annotation.tablefield}
 * 使用,默认情况下@tablefield会将javatype设置为字段的类型,如果是list<?>则type = list.class,无法明确其中的泛型,类型转换会变成jsonobject。
 * 用法:
 * <pre>{@code
 * 1.实体类上使用注解@tablename(value = "表名", resultmap = "xml文件中的resultmap的id")
 * 2.xml文件中自定义resultmap并设置需要json转换的字段
 * <result property="实体类属性名" column="表字段名" javatype="list中的对象全类名,例如list<email>,则javatype为email的全类名" typehandler="自定义处理器全类名"/>
 * 3.自定义方法上的用法
 * @mapper
 * public interface demodao extends basemapper<demoentity> {
 *    @select("select * from demo where demo_id = #{demoid}")
 *    @resultmap(value = "xml文件中的resultmap的id")
 *    list<demoentity> selectlistbydemoid(long demoid);
 * }
 * }</pre>
 */
@slf4j
@mappedjdbctypes(value = jdbctype.varchar)
public class fastjsonarraytypehandler extends abstractjsontypehandler<list<?>> { 
    private class<?> type; 
    public fastjsonarraytypehandler(class<?> type) {
        if (log.istraceenabled()) {
            log.trace("fastjsontypehandler(" + type + ")");
        }
        assert.notnull(type, "type argument cannot be null");
        this.type = type;
    }
 
    @override
    protected list<?> parse(string json) {
        return json.parsearray(json, type);// 注意不要使用parseobject方法
    }
 
    @override
    protected string tojson(list<?> obj) {
        return json.tojsonstring(obj, serializerfeature.writemapnullvalue, serializerfeature.writenulllistasempty, serializerfeature.writenullstringasempty);
    } 
}

xml文件

<?xml version="1.0" encoding="utf-8" ?>
<!doctype mapper public "-//mybatis.org//dtd mapper 3.0//en" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="a.b.dao.demodao">
    <resultmap type="a.b.entity.demoentity" id="demomap">
        <result property="demoinfo" column="demo_info" javatype="a.b.xx.diseaseinfo" typehandler="a.b.handler.fastjsonarraytypehandler"/>
    </resultmap>
</mapper>

dao

@mapper
public interface demodao extends basemapper<demoentity> {
    @select("select * from demo where demo_id = #{demoid}")
    @resultmap(value = "demomap")
    list<demoentity> selectlistbyplanid(long demoid);
}

entity

@data
@tablename(value = "demo", resultmap = "demomap")
public class demoentity implements serializable {
    private static final long serialversionuid = -1l;
 
    /**
     * 主键
     */
    @tableid
    private long id;
    private long demoid
    /**
     * json字段
     */
    private list<demoinfo> demoinfo;
}

2.手动注册

typehandler

@slf4j
@mappedjdbctypes(value = jdbctype.varchar)
public class fastjsonarraytypehandler<t> extends abstractjsontypehandler<object> { 
    private typereference<list<t>> type; 
    public fastjsonarraytypehandler(typereference<list<t>> type) {
        this.type = type;
    }
 
    @override
    protected object parse(string json) {
        return json.parseobject(json, type);
    }
 
    @override
    protected string tojson(object obj) {
        return json.tojsonstring(obj, serializerfeature.writemapnullvalue, serializerfeature.writenulllistasempty, serializerfeature.writenullstringasempty);
    } 
}

初始化,剩下的bean和dao都不需要额外配置

/**
 * 描述:初始化配置
 * 手动注册类型处理器
 */
@component
public class initconfig implements commandlinerunner {
    public static final com.alibaba.fastjson.typereference<list<demoinfo>> f_demo_info = new com.alibaba.fastjson.typereference<list<demoinfo>>() {
    };
    public static final typereference<list<demoinfo>> m_demo_info = new typereference<list<demoinfo>>() {
    };
    // mp自动装配时注入的factory,可用于获取mybatis的配置属性,这里用来获取类型处理器的注册器
    private final sqlsessionfactory factory;
 
    public initconfig(sqlsessionfactory factory) {
        this.factory = factory;
    }
 
    /**
     * 注册类型处理器
     * <pre>{@code
     * 1.list<demoinfo>类型处理器
     * ...
     * }</pre>
     *
     * @param args incoming main method arguments
     * @throws exception on error
     */
    @suppresswarnings("all")
    @override
    public void run(string... args) throws exception {
        typehandlerregistry typehandlerregistry = factory.getconfiguration().gettypehandlerregistry();
        typehandlerregistry.register(m_demo_info, new fastjsonarraytypehandler(f_demo_info));
    }
}

目前方法二存在的缺陷:虽然新增、查询不存在问题,执行mp自带的更新操作时,parametermap参数类型都是object,不会经过自定义的typehandler处理,最后会把json对象直接set进去(update demo ..., demo_info = json对象 ...)导致报错

暂无优雅的解决方案,先做个记录 。以上为个人经验,希望能给大家一个参考,也希望大家多多支持。