mybatis-plus - TableInfo


在前面 的 inject() 方法中, 調用了一個 TableInfoHelper.initTableInfo(builderAssistant, modelClass) 方法, 來獲取 表信息: TableInfo

  /**
     * <p>
     * 實體類反射獲取表信息【初始化】
     * <p>
     *
     * @param clazz 反射實體類
     * @return 數據庫表反射信息
     */
    public synchronized static TableInfo initTableInfo(MapperBuilderAssistant builderAssistant, Class<?> clazz) {
        TableInfo tableInfo = TABLE_INFO_CACHE.get(clazz);
        if (tableInfo != null) {
            if (tableInfo.getConfigMark() == null && builderAssistant != null) {
                tableInfo.setConfigMark(builderAssistant.getConfiguration());
            }
            return tableInfo;
        }

        /* 沒有獲取到緩存信息,則初始化 */
        tableInfo = new TableInfo();
        GlobalConfig globalConfig;
        if (null != builderAssistant) {
            tableInfo.setCurrentNamespace(builderAssistant.getCurrentNamespace());
            tableInfo.setConfigMark(builderAssistant.getConfiguration());
            tableInfo.setUnderCamel(builderAssistant.getConfiguration().isMapUnderscoreToCamelCase());
            globalConfig = GlobalConfigUtils.getGlobalConfig(builderAssistant.getConfiguration());
        } else {
            // 兼容測試場景
            globalConfig = GlobalConfigUtils.defaults();
        }

        /* 初始化表名相關 */ initTableName(clazz, globalConfig, tableInfo);

        /* 初始化字段相關 */ initTableFields(clazz, globalConfig, tableInfo);

        /* 放入緩存 */
        TABLE_INFO_CACHE.put(clazz, tableInfo);

        /* 緩存 Lambda 映射關系 */
        LambdaUtils.createCache(clazz, tableInfo);
        return tableInfo;
    }

是不是還是自己人寫的代碼看起來爽? 這中文注釋, 都不用看方法具體是干啥的. 

這里的  TABLE_INFO_CACHE  是用來緩存表信息的:

/**
 * 儲存反射類表信息
 */
private static final Map<Class<?>, TableInfo> TABLE_INFO_CACHE = new ConcurrentHashMap<>();

第一次進這個方法的時候, 肯定是空的, 要去解析獲取.

 

1. initTableName()

 /**
     * <p>
     * 初始化 表數據庫類型,表名,resultMap
     * </p>
     *
     * @param clazz        實體類
     * @param globalConfig 全局配置
     * @param tableInfo    數據庫表反射信息
     */
    public static void initTableName(Class<?> clazz, GlobalConfig globalConfig, TableInfo tableInfo) {
        /* 數據庫全局配置 */
        GlobalConfig.DbConfig dbConfig = globalConfig.getDbConfig();
        /* 設置數據庫類型 */
        tableInfo.setDbType(dbConfig.getDbType());

        /* 設置表名 */
        TableName table = clazz.getAnnotation(TableName.class);
        String tableName = clazz.getSimpleName();
        if (table != null && StringUtils.isNotEmpty(table.value())) {
            tableName = table.value();
        } else {
            // 開啟表名下划線申明
            if (dbConfig.isTableUnderline()) {
                tableName = StringUtils.camelToUnderline(tableName);
            }
            // 大寫命名判斷
            if (dbConfig.isCapitalMode()) {
                tableName = tableName.toUpperCase();
            } else {
                // 首字母小寫
                tableName = StringUtils.firstToLowerCase(tableName);
            }
            // 存在表名前綴
            if (null != dbConfig.getTablePrefix()) {
                tableName = dbConfig.getTablePrefix() + tableName;
            }
        }
        tableInfo.setTableName(tableName);

        /* 表結果集映射 */
        if (table != null && StringUtils.isNotEmpty(table.resultMap())) {
            tableInfo.setResultMap(table.resultMap());
        }

        /* 開啟了自定義 KEY 生成器 */
        if (null != dbConfig.getKeyGenerator()) {
            tableInfo.setKeySequence(clazz.getAnnotation(KeySequence.class));
        }
    }

判斷邏輯:

1. 判斷實體類上面有沒有 TableName 注解

  |-> 如果有, 則拿注解里面配置的 value 作為表名

  |-> 如果沒有, 則根據類名進行解析

 

2. initTableFields()

  /**
     * <p>
     * 初始化 表主鍵,表字段
     * </p>
     *
     * @param clazz        實體類
     * @param globalConfig 全局配置
     * @param tableInfo    數據庫表反射信息
     */
    public static void initTableFields(Class<?> clazz, GlobalConfig globalConfig, TableInfo tableInfo) {
        /* 數據庫全局配置 */
        GlobalConfig.DbConfig dbConfig = globalConfig.getDbConfig();
        List<Field> list = getAllFields(clazz);
        // 標記是否讀取到主鍵
        boolean isReadPK = false;
        // 是否存在 @TableId 注解
        boolean existTableId = isExistTableId(list);

        List<TableFieldInfo> fieldList = new ArrayList<>();
        for (Field field : list) {
            /*
             * 主鍵ID 初始化
             */
            if (!isReadPK) {
                if (existTableId) {
                    isReadPK = initTableIdWithAnnotation(dbConfig, tableInfo, field, clazz);
                } else {
                    isReadPK = initTableIdWithoutAnnotation(dbConfig, tableInfo, field, clazz);
                }
                if (isReadPK) {
                    continue;
                }
            }
            /* 有 @TableField 注解的字段初始化 */
            if (initTableFieldWithAnnotation(dbConfig, tableInfo, fieldList, field, clazz)) {
                continue;
            }

            /* 無 @TableField 注解的字段初始化 */
            fieldList.add(new TableFieldInfo(dbConfig, tableInfo, field));
        }

        /* 檢查邏輯刪除字段只能有最多一個 */
        Assert.isTrue(fieldList.parallelStream().filter(TableFieldInfo::isLogicDelete).count() < 2L,
            String.format("annotation of @TableLogic can't more than one in class : %s.", clazz.getName()));

        /* 字段列表 */
        tableInfo.setFieldList(fieldList);

        /* 未發現主鍵注解,提示警告信息 */
        if (StringUtils.isEmpty(tableInfo.getKeyColumn())) {
            logger.warn(String.format("Warn: Could not find @TableId in Class: %s.", clazz.getName()));
        }
    }

 

2.1 getAllFields()

    /**
     * 獲取該類的所有屬性列表
     *
     * @param clazz 反射類
     * @return 屬性集合
     */
    public static List<Field> getAllFields(Class<?> clazz) {
        List<Field> fieldList = ReflectionKit.getFieldList(ClassUtils.getUserClass(clazz));
        if (CollectionUtils.isNotEmpty(fieldList)) {
            return fieldList.stream()
                .filter(i -> {
                    /* 過濾注解非表字段屬性 */
                    TableField tableField = i.getAnnotation(TableField.class);
                    return (tableField == null || tableField.exist());
                }).collect(toList());
        }
        return fieldList;
    }

如果字段上面加了 TableField 注解, 如果有則進行特殊處理. 如果配置了 exist=false, 則這個字段, 過濾掉, 不參與sql生成.

 

2.2 initTableIdWithAnnotation()

如果實體類中有 TableId 注解, 則進入此方法, 一般情況下, 最好是配一下 TableId

    /**
     * <p>
     * 主鍵屬性初始化
     * </p>
     *
     * @param dbConfig  全局配置信息
     * @param tableInfo 表信息
     * @param field     字段
     * @param clazz     實體類
     * @return true 繼續下一個屬性判斷,返回 continue;
     */
    private static boolean initTableIdWithAnnotation(GlobalConfig.DbConfig dbConfig, TableInfo tableInfo,
                                                     Field field, Class<?> clazz) {
        TableId tableId = field.getAnnotation(TableId.class);
        boolean underCamel = tableInfo.isUnderCamel();
        if (tableId != null) {
            if (StringUtils.isEmpty(tableInfo.getKeyColumn())) {
                /* 主鍵策略( 注解 > 全局 ) */
                // 設置 Sequence 其他策略無效
                if (IdType.NONE == tableId.type()) {
                    tableInfo.setIdType(dbConfig.getIdType());
                } else {
                    tableInfo.setIdType(tableId.type());
                }

                /* 字段 */
                String column = field.getName();
                if (StringUtils.isNotEmpty(tableId.value())) {
                    column = tableId.value();
                } else {
                    // 開啟字段下划線申明
                    if (underCamel) {
                        column = StringUtils.camelToUnderline(column);
                    }
                    // 全局大寫命名
                    if (dbConfig.isCapitalMode()) {
                        column = column.toUpperCase();
                    }
                }
                tableInfo.setKeyRelated(checkRelated(underCamel, field.getName(), column))
                    .setClazz(field.getDeclaringClass())
                    .setKeyColumn(column)
                    .setKeyProperty(field.getName());
                return true;
            } else {
                throwExceptionId(clazz);
            }
        }
        return false;
    }

 

2.3 initTableFieldWithAnnotation()

這里對 TableField 進行解析賦值. 如  value 解析成 字段名稱

    /**
     * <p>
     * 字段屬性初始化
     * </p>
     *
     * @param dbConfig  數據庫全局配置
     * @param tableInfo 表信息
     * @param fieldList 字段列表
     * @param clazz     當前表對象類
     * @return true 繼續下一個屬性判斷,返回 continue;
     */
    private static boolean initTableFieldWithAnnotation(GlobalConfig.DbConfig dbConfig, TableInfo tableInfo,
                                                        List<TableFieldInfo> fieldList, Field field, Class<?> clazz) {
        /* 獲取注解屬性,自定義字段 */
        TableField tableField = field.getAnnotation(TableField.class);
        if (null == tableField) {
            return false;
        }
        String columnName = field.getName();
        if (StringUtils.isNotEmpty(tableField.value())) {
            columnName = tableField.value();
        }
        /*
         * el 語法支持,可以傳入多個參數以逗號分開
         */
        String el = field.getName();
        if (StringUtils.isNotEmpty(tableField.el())) {
            el = tableField.el();
        }
        String[] columns = columnName.split(StringPool.SEMICOLON);
        String[] els = el.split(StringPool.SEMICOLON);
        if (columns.length == els.length) {
            for (int i = 0; i < columns.length; i++) {
                fieldList.add(new TableFieldInfo(dbConfig, tableInfo, field, columns[i], els[i], tableField));
            }
            return true;
        }
        throw ExceptionUtils.mpe(String.format("Class: %s, Field: %s, 'value' 'el' Length must be consistent.",
            clazz.getName(), field.getName()));
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM