亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

MyBatisPlus的autoResultMap生成策略實(shí)現(xiàn)

 更新時(shí)間:2024年02月18日 09:44:22   作者:118路司機(jī)  
本文主要介紹了MyBatisPlus的autoResultMap生成策略實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

使用MyBatis-Plus的字段類型處理器,只需一個(gè)注解,就可以很方便的將數(shù)組、對(duì)象等數(shù)據(jù)直接映射到實(shí)體類中。

@Data
@Accessors(chain = true)
@TableName(autoResultMap = true)
public class User {
    private Long id;

    ...


    /**
     * 注意?。?必須開啟映射注解
     *
     * @TableName(autoResultMap = true)
     *
     * 以下兩種類型處理器,二選一 也可以同時(shí)存在
     *
     * 注意??!選擇對(duì)應(yīng)的 JSON 處理器也必須存在對(duì)應(yīng) JSON 解析依賴包
     */
    @TableField(typeHandler = JacksonTypeHandler.class)
    // @TableField(typeHandler = FastjsonTypeHandler.class)
    private OtherInfo otherInfo;

}

該注解對(duì)應(yīng)了 XML 中寫法為

<result column="other_info" jdbcType="VARCHAR" property="otherInfo" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler" />

實(shí)現(xiàn)的原理可以參考TableInfo的源碼initResultMapIfNeed方法:

    /**
     * 自動(dòng)構(gòu)建 resultMap 并注入(如果條件符合的話)
     */
    void initResultMapIfNeed() {
        if (autoInitResultMap && null == resultMap) {
            String id = currentNamespace + DOT + MYBATIS_PLUS + UNDERSCORE + entityType.getSimpleName();
            List<ResultMapping> resultMappings = new ArrayList<>();
            if (havePK()) {
                ResultMapping idMapping = new ResultMapping.Builder(configuration, keyProperty, keyColumn, keyType)
                    .flags(Collections.singletonList(ResultFlag.ID)).build();
                resultMappings.add(idMapping);
            }
            if (CollectionUtils.isNotEmpty(fieldList)) {
                fieldList.forEach(i -> resultMappings.add(i.getResultMapping(configuration)));
            }
            ResultMap resultMap = new ResultMap.Builder(configuration, id, entityType, resultMappings).build();
            configuration.addResultMap(resultMap);
            this.resultMap = id;
        }
    }

存在的問(wèn)題

當(dāng)使用autoResultMap=true時(shí), MP會(huì)做以下事情:

  • 如果字段的Java類型不是基本類型,則會(huì)強(qiáng)制提示你設(shè)置typeHandler屬性,比如這么寫是不行的:
/**
 * IN 查詢
*/
public static final String IN = "%s IN <foreach item=\"item\" collection=\"%s\" separator=\",\" open=\"(\" close=\")\" index=\"\">#{item}</foreach>";

@TableField(value="code",select=false, condition=IN )
private Strinng[] codes;
  • 如果字段比較復(fù)雜,比如包含函數(shù),帶有表別名限定等,那么自動(dòng)生成的resultMap對(duì)應(yīng)的column屬性則會(huì)變得很奇怪:
@TableField(value = "array_agg(distinct code)",jdbcType = JdbcType.VARCHAR, typeHandler = ArrayTypeHandler.class)
private String[] codes;

上面的代碼中,生成的resultMap的column屬性是 rray_agg(distinct code , (value屬性前后各截取一位),具體的邏輯可以查看MP的源碼:

TableFieldInfo.java

    /**
  * 獲取 ResultMapping
  *
  * @param configuration MybatisConfiguration
  * @return ResultMapping
  */
 ResultMapping getResultMapping(final Configuration configuration) {
     ResultMapping.Builder builder = new ResultMapping.Builder(configuration, property,
         StringUtils.getTargetColumn(column), propertyType);
     TypeHandlerRegistry registry = configuration.getTypeHandlerRegistry();
     if (jdbcType != null && jdbcType != JdbcType.UNDEFINED) {
         builder.jdbcType(jdbcType);
     }
     if (typeHandler != null && typeHandler != UnknownTypeHandler.class) {
         TypeHandler<?> typeHandler = registry.getMappingTypeHandler(this.typeHandler);
         if (typeHandler == null) {
             typeHandler = registry.getInstance(propertyType, this.typeHandler);
             // todo 這會(huì)有影響 registry.register(typeHandler);
         }
         builder.typeHandler(typeHandler);
     }
     return builder.build();
 }

StringUtils.java

  /**
    * 驗(yàn)證字符串是否是數(shù)據(jù)庫(kù)字段
    */
   private static final Pattern P_IS_COLUMN = Pattern.compile("^\\w\\S*[\\w\\d]*$");
  
    /**
    * 判斷字符串是否符合數(shù)據(jù)庫(kù)字段的命名
    *
    * @param str 字符串
    * @return 判斷結(jié)果
    */
   public static boolean isNotColumnName(String str) {
       return !P_IS_COLUMN.matcher(str).matches();
   }

   /**
    * 獲取真正的字段名
    *
    * @param column 字段名
    * @return 字段名
    */
   public static String getTargetColumn(String column) {
       if (isNotColumnName(column)) {
           return column.substring(1, column.length() - 1);
       }
       return column;
   }

是的,就是這么簡(jiǎn)單粗暴,這里吐槽一下國(guó)內(nèi)開源軟件的毛病,邏輯莫名其妙,而且git上對(duì)于開發(fā)者提出的疑問(wèn)視而不見(jiàn)。

優(yōu)化思路

其實(shí)如果一個(gè)字段存在typeHander屬性,那就必須要建一個(gè)ResultMap來(lái)處理類型映射了,根本不需要再畫蛇添足的指定autoResultMap=true, 不過(guò)也好在有這個(gè)屬性,MP才會(huì)自動(dòng)生成一個(gè)ResultMap,這樣我們就可以在不指定這個(gè)屬性的時(shí)候,生成自己的ResultMap了。
直接修改官方源代碼不是我的風(fēng)格,好在MP提供了Sql注入器,在往Mapper中注入方法之前,我們把ResultMap生成就可以了。

優(yōu)化步驟

  • 創(chuàng)建抽象注入方法的子類:BetterAutoResultMap.java
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.caspe.base.support.mybatisplus.toolkit.ConstantsX;
import lombok.SneakyThrows;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.apache.ibatis.type.UnknownTypeHandler;

import java.lang.reflect.Field;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 優(yōu)化的AutoResultMap生成策略
 * 只要字段中指定了TypeHandler即自動(dòng)生成ResultMap, 而不需要指定autoResultMap=true
 * 且只對(duì)設(shè)置了TypeHandler的字段生成ResultMapping, 而不是所有的字段
 *
 * @author yongfeng_meng
 */
public class BetterAutoResultMap extends AbstractMethod {

    /**
     * 強(qiáng)制重設(shè)TableInfo的resultMap屬性
     */
    static Field ResultMapOfTableInfo;

    /**
     * 強(qiáng)制重設(shè)TableInfo的autoInitResultMap屬性
     */
    static Field AutoInitResultMapOfTableInfo;

    static {
        try {
            ResultMapOfTableInfo = TableInfo.class.getDeclaredField("resultMap");
            ResultMapOfTableInfo.setAccessible(true);
            AutoInitResultMapOfTableInfo = TableInfo.class.getDeclaredField("autoInitResultMap");
            AutoInitResultMapOfTableInfo.setAccessible(true);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

    /**
     * 注入自定義 MappedStatement
     * <p>
     * 當(dāng)實(shí)體類沒(méi)有指定autoResultMap和resultMap時(shí), 即可使用該方法自動(dòng)注入ResultMap
     *
     * @param mapperClass mapper 接口
     * @param modelClass  mapper 泛型
     * @param tableInfo   數(shù)據(jù)庫(kù)表反射信息
     * @return MappedStatement
     */
    @SneakyThrows
    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        if (!tableInfo.isAutoInitResultMap() && tableInfo.getResultMap() == null) {

            // 只要字段中指定了TypeHandler即自動(dòng)生成ResultMap
            if (tableInfo.getFieldList().stream().filter(this::needToAutoMap).findAny().isPresent()) {

                // 生成ResultMap
                ResultMap resultMap = generatorResultMap(tableInfo);
                configuration.addResultMap(resultMap);

                // 將ResultMap屬性設(shè)置到TableInfo
                ResultMapOfTableInfo.set(tableInfo, resultMap.getId());
                AutoInitResultMapOfTableInfo.set(tableInfo, true);
            }
        }
        return null;
    }

    /**
     * 構(gòu)建 resultMap
     */
    ResultMap generatorResultMap(TableInfo tableInfo) {
        String resultMapId = tableInfo.getCurrentNamespace() + DOT + ConstantsX.MYBATIS_PLUS_X + UNDERSCORE + tableInfo.getEntityType().getSimpleName();
        List<ResultMapping> resultMappings = tableInfo.getFieldList().stream().filter(this::needToAutoMap)
                .map(this::getResultMapping).collect(Collectors.toList());
        return new ResultMap.Builder(configuration, resultMapId, tableInfo.getEntityType(), resultMappings).build();
    }

    boolean needToAutoMap(TableFieldInfo f) {
        return f.getTypeHandler() != null && f.getTypeHandler() != UnknownTypeHandler.class;
    }

    /**
     * 構(gòu)建 resultMapping (只針對(duì)typeHandler的字段)
     *
     * @param tableFieldInfo
     * @return
     */
    ResultMapping getResultMapping(TableFieldInfo tableFieldInfo) {
        String column = tableFieldInfo.getColumn();
        String property = tableFieldInfo.getProperty();
        if (!StringUtils.underlineToCamel(column).equals(property)) {
            column = property;
        }
        ResultMapping.Builder builder = new ResultMapping.Builder(configuration, property, column, tableFieldInfo.getPropertyType());
        TypeHandlerRegistry registry = configuration.getTypeHandlerRegistry();
        JdbcType jdbcType = tableFieldInfo.getJdbcType();
        if (jdbcType != null && jdbcType != JdbcType.UNDEFINED) {
            builder.jdbcType(jdbcType);
        }
        TypeHandler<?> typeHandlerMapped = registry.getMappingTypeHandler(tableFieldInfo.getTypeHandler());
        if (typeHandlerMapped == null) {
            typeHandlerMapped = registry.getInstance(tableFieldInfo.getPropertyType(), tableFieldInfo.getTypeHandler());
        }
        builder.typeHandler(typeHandlerMapped);
        return builder.build();
    }
}
  • 創(chuàng)建SQL注入器的自定義類:SqlInjectorX.java
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.caspe.base.support.mybatisplus.injector.methods.BetterAutoResultMap;
import com.caspe.base.support.mybatisplus.injector.methods.DeleteByMultiId;
import com.caspe.base.support.mybatisplus.injector.methods.SelectByMultiId;
import com.caspe.base.support.mybatisplus.injector.methods.UpdateByMultiId;

import java.util.ArrayList;
import java.util.List;

public class SqlInjectorX extends DefaultSqlInjector {

    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
        List<AbstractMethod> methodList = new ArrayList<>();
        // 優(yōu)先注入AutoResultMap生成方法
        methodList.add(new BetterAutoResultMap());
        methodList.addAll(super.getMethodList(mapperClass));
        return methodList;
    }
}
  • 將自定義Sql注入器加入到容器中
@Configuration
@Import({SqlInjectorX.class})
public class MybatisPlusAutoConfiguration {
}

驗(yàn)證

首先按照優(yōu)化思路,肯定先要將autoResultMap=true這個(gè)屬性刪掉。
問(wèn)題1將不復(fù)存在,問(wèn)題2使用了我們自定義的ResultMap,column屬性和property屬性將一致,一切變得簡(jiǎn)單而自然。

到此這篇關(guān)于MyBatisPlus的autoResultMap生成策略實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)MyBatisPlus autoResultMap生成策略內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring的兩種事務(wù)管理機(jī)制的基本概念和demo示例

    Spring的兩種事務(wù)管理機(jī)制的基本概念和demo示例

    Spring事務(wù)包括聲明式事務(wù)管理和注解式事務(wù)管理,我們通過(guò)概念和小demo的形式一步一步地來(lái)一起學(xué)習(xí)這個(gè)知識(shí)點(diǎn),需要的朋友可以參考下
    2023-07-07
  • spring帶bean和config如何通過(guò)main啟動(dòng)測(cè)試

    spring帶bean和config如何通過(guò)main啟動(dòng)測(cè)試

    這篇文章主要介紹了spring帶bean和config,通過(guò)main啟動(dòng)測(cè)試,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-07-07
  • 解決jackson反序列化失敗InvalidFormatException:Can not deserialize value of type java.util.Date

    解決jackson反序列化失敗InvalidFormatException:Can not dese

    這篇文章主要介紹了解決jackson反序列化失敗InvalidFormatException:Can not deserialize value of type java.util.Date問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • JAVA線程池監(jiān)控以及動(dòng)態(tài)調(diào)整示例詳解

    JAVA線程池監(jiān)控以及動(dòng)態(tài)調(diào)整示例詳解

    這篇文章主要為大家介紹了JAVA線程池監(jiān)控以及動(dòng)態(tài)調(diào)整示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • 解決jmap命令打印JVM堆信息異常的問(wèn)題

    解決jmap命令打印JVM堆信息異常的問(wèn)題

    這篇文章主要介紹了解決jmap命令打印JVM堆信息異常的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • 詳談Jedis連接池的使用

    詳談Jedis連接池的使用

    下面小編就為大家?guī)?lái)一篇詳談Jedis連接池的使用。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-05-05
  • java創(chuàng)建子類對(duì)象設(shè)置并調(diào)用父類的變量操作

    java創(chuàng)建子類對(duì)象設(shè)置并調(diào)用父類的變量操作

    這篇文章主要介紹了java創(chuàng)建子類對(duì)象設(shè)置并調(diào)用父類的變量操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-01-01
  • jQuery 動(dòng)畫效果代碼分享

    jQuery 動(dòng)畫效果代碼分享

    本文給大家分享一段關(guān)于jquery實(shí)現(xiàn)的動(dòng)畫效果,代碼簡(jiǎn)單易懂,非常不錯(cuò),感興趣的朋友參考下
    2016-11-11
  • Java?Guava異步編程實(shí)踐

    Java?Guava異步編程實(shí)踐

    今天咱們要聊的是Guava在異步編程中的應(yīng)用,讓我們搞清楚為什么要用Guava來(lái)處理異步任務(wù),在Java的世界里,異步編程是個(gè)老話題了,但它依舊非常關(guān)鍵,它能讓咱們的應(yīng)用更高效,尤其是在處理那些耗時(shí)的I/O操作
    2023-12-12
  • Java如何通過(guò)ssh遠(yuǎn)程連接主機(jī)并執(zhí)行命令

    Java如何通過(guò)ssh遠(yuǎn)程連接主機(jī)并執(zhí)行命令

    這篇文章主要介紹了Java如何通過(guò)ssh遠(yuǎn)程連接主機(jī)并執(zhí)行命令問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07

最新評(píng)論