1. 程式人生 > 程式設計 >Mybatis-Plus自定義集合型別的型別處理器詳解

Mybatis-Plus自定義集合型別的型別處理器詳解

目錄
  • 1.配合xml檔案
  • 2.手動註冊

兩種方法,第一種很麻煩,對mp自帶的插入操作有限制,後來改為更簡潔的第二種方法

1.配合xml檔案

TypeHandler

/**
* 描述:faston的集合物件型別處理器,將表中的json欄位對映到實體類中的{@code List<?>}屬性
* 對照MP自帶的FastjsonTypeHandler,自帶的型別處理器會把所有的{@code List<?>}都會解析為{@code List<JsonObject>},
* 這樣在遍歷其中物件時,呼叫物件屬性的get、set方法就會發送型別轉換JsonObject->?,這種情況轉換錯誤。
* 該處理器必須配合xml檔案使用,不然無法獲取要解析的物件型別,同時不能配合MP自帶的{@link com.baomidou.mybatisplus.annotation.TableField}
* 使用,預設情況下@TableField會將Type設定為欄位的型別,如果是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) {
    retuFaDJpMrn JSON.toJSONString(obj,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 TypeReferencwww.cppcns.come<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物件 ...)導致報錯

暫無優雅的解決方案,先做個記錄 。以上為個人經驗,希望能給大家一個參考,也希望大家多多支援我們。