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()));
}
mybatis-plus - TableInfo的更多相关文章
- spring-cloud集成mybatis-plus
mybatis-plus插件是对mybatis做出系列增强插件,后面简称MP,MP可免去开发者重复编写xml.mapper.service.entity等代码,通过MP提供的实体注解来完成单表的CRU ...
- Mybatis-Plus 代码生成器基本使用
Mybatis-Plus 代码生成器基本使用 参考 https://mp.baomidou.com/guide/generator.html#%E4%BD%BF%E7%94%A8%E6%95%99%E ...
- spring boot整合mybatis+mybatis-plus
Spring boot对于我来说是一个刚接触的新东西,学习过程中,发现这东西还是很容易上手的,Spring boot没配置时会默认使用Spring data jpa,这东西可以说一个极简洁的工具,可是 ...
- 使用mybatis plus自动生成controller、service、dao、mapper、entity代码
官网:http://mp.baomidou.com(这个项目不仅仅可以用于代码生成,还有分页等其他功能,是对mybatis的一层封装) 要求:基于sql自动生成domain.controller.se ...
- Mybatis Plus启动注入 SQL 原理分析
1) 问题: xxxMapper 继承了 BaseMapper<T>, BaseMapper 中提供了通用的 CRUD 方法, 方法来源于 BaseMapper, 有方法就必须有 SQL, ...
- 步步截图的SMM框架入门实战指引(SpringBoot、Mybatis Plus、Maven)
前提是对spring.springmvc.mybatis有初步学习和理解,因为要全部讲这些框架的知识点太多了,自己学习,这里是实战示范(大部分人学了知识之后去实战会出现很多问题,所以出此教程) 开发环 ...
- Mybatis - plus 配置与运用
Mybatis - plus mybatis-plus 官方文档 1.配置 引入对应的文件包,spring boot + mybatis 需添加依赖文件如下: <dependencies> ...
- Mybatis Generator通用Join的实现
通常,我们使用Mybatis实现join表关联的时候,一般都是通过在xml或注解里写自定义sql实现. 本文通过Mybatis Generator的插件功能新增一个JoinPlugin插件,只要在配置 ...
- 想做时间管理大师?你可以试试Mybatis Plus代码生成器
1. 前言 对于写Crud的老司机来说时间非常宝贵,一些样板代码写不但费时费力,而且枯燥无味.经常有小伙伴问我,胖哥你怎么天天那么有时间去搞新东西,透露一下秘诀呗. 好吧,今天就把Mybatis-pl ...
- SpringCloud或SpringBoot+Mybatis-Plus利用AOP+mybatis插件实现数据操作记录及更新对比
引文 本文主要介绍如何使用Spring AOP + mybatis插件实现拦截数据库操作并根据不同需求进行数据对比分析,主要适用于系统中需要对数据操作进行记录.在更新数据时准确记录更新字段 核心:AO ...
随机推荐
- 非常简洁简单的tcp socket库 XKSocket
一个非常简洁简单的异步tcp socket库,主要就是分包的问题,处理组包,粘包等问题 非常适合新手:) 项目中带有使用示例. http://git.oschina.net/dreamzgj/XKSo ...
- (vue操作storage)Vue plugin for work with local storage,session storage and memo
vue-ls https://www.npmjs.com/package/vue-ls NPM npm install vue-ls --save Yarn yarn add vue-ls Usage ...
- mysql 表结构操作
alter table name : alter table table1 to table2;add column : alter table 表名 add column 列名 varchar(); ...
- findContours()函数
函数原型 findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int m ...
- Golang模块之HTTP
HTTP客户端和服务端 Go语言中内置net/http包提供了HTTP客户端和服务端的实现 HTTP服务端 package main import ( "encoding/json" ...
- STL中的Set和Map——入门新手篇
STL中的Set和Map 先来看一段网络上的文字描述: 上图是一段关于STL中Set集合的描述,同样的,也近似适合Map的描述.上述文字中,描述了最为重要的特征: Set和Map,底层调用了红黑树的结 ...
- maven的核心概念——依赖
一.STS集成maven(以下是mac版的STS) 1.点击Spring Tool Suite,点击preferences maven中的installations 点击add,选择对应的路径即可 点 ...
- final 和 static之间的区别和联系
关键字final和关键字static两者的含义并不相似,但是笔者常常使用一段时间后就会忘记它们之间的区别,因为它俩总是相伴着出现.当只出现其中一个时,就对其代表的含义不甚清晰了.故而特地将相关知识点记 ...
- iframe在iphone手机上的问题
问题1: 通过document.addEventListener("scroll",function(){})对页面滚动监听事件进行监听,但ios下$(document).scro ...
- vue 学习2
模板指令.属性总结 html 中的标签属性 1. :class 值是对象,key为class 的值,值为boolean类型 html标签任意属性都可以:属性,表示动态值(值是变化的,不是固定不变的) ...