Mybatis-Plus自定义集合类型的类型处理器详解
作者:nasoda_pro1993
这篇文章主要介绍了Mybatis-Plus自定义集合类型的类型处理器详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
两种方法,第一种很麻烦,对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对象 ...)导致报错
暂无优雅的解决方案,先做个记录 。以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。