连表查询支持type handle

This commit is contained in:
admin 2021-05-19 15:43:20 +08:00
parent 8f51f86182
commit ee22855046
5 changed files with 959 additions and 6 deletions

View File

@ -2,10 +2,13 @@ package com.github.yulichang.interceptor;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.github.yulichang.metadata.TableInfo;
import com.github.yulichang.metadata.TableInfoHelper;
import com.github.yulichang.method.MPJResultType;
import com.github.yulichang.toolkit.Constant;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultFlag;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.plugin.Interceptor;
@ -15,10 +18,7 @@ import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
@ -39,6 +39,11 @@ public class MPJInterceptor implements Interceptor {
*/
private static final Map<String, MappedStatement> MS_CACHE = new ConcurrentHashMap<>();
/**
* 缓存ResultMap
*/
private static final Map<Class<?>, ResultMap> RM_CACHE = new ConcurrentHashMap<>();
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object[] args = invocation.getArgs();
@ -89,10 +94,44 @@ public class MPJInterceptor implements Interceptor {
builder.keyProperty(String.join(StringPool.COMMA, ms.getKeyProperties()));
}
List<ResultMap> resultMaps = new ArrayList<>();
resultMaps.add(new ResultMap.Builder(ms.getConfiguration(), ms.getId(), resultType, EMPTY_RESULT_MAPPING).build());
resultMaps.add(newResultMap(ms, resultType));
builder.resultMaps(resultMaps);
MappedStatement mappedStatement = builder.build();
MS_CACHE.put(id, mappedStatement);
return mappedStatement;
}
/**
* 构建resultMap
*/
private ResultMap newResultMap(MappedStatement ms, Class<?> resultType) {
com.baomidou.mybatisplus.core.metadata.TableInfo tableInfo = com.baomidou.mybatisplus.core.metadata.TableInfoHelper.getTableInfo(resultType);
if (tableInfo != null && tableInfo.isAutoInitResultMap()) {
ResultMap resultMap = RM_CACHE.get(resultType);
if (resultMap == null) {
TableInfo info = TableInfoHelper.initTableInfo(ms.getConfiguration(), ms.getId().substring(0, ms.getId().lastIndexOf(".")), resultType);
resultMap = initResultMapIfNeed(info, resultType);
RM_CACHE.put(resultType, resultMap);
}
return resultMap;
}
return new ResultMap.Builder(ms.getConfiguration(), ms.getId(), resultType, EMPTY_RESULT_MAPPING).build();
}
/**
* 构建resultMap
*/
private ResultMap initResultMapIfNeed(TableInfo info, Class<?> resultType) {
String id = info.getCurrentNamespace() + ".mybatis-plus-join_" + resultType.getSimpleName();
List<ResultMapping> resultMappings = new ArrayList<>();
if (info.havePK()) {
ResultMapping idMapping = new ResultMapping.Builder(info.getConfiguration(), info.getKeyProperty(), info.getKeyColumn(), info.getKeyType())
.flags(Collections.singletonList(ResultFlag.ID)).build();
resultMappings.add(idMapping);
}
if (CollectionUtils.isNotEmpty(info.getFieldList())) {
info.getFieldList().forEach(i -> resultMappings.add(i.getResultMapping(info.getConfiguration())));
}
return new ResultMap.Builder(info.getConfiguration(), id, resultType, resultMappings).build();
}
}

View File

@ -0,0 +1,346 @@
package com.github.yulichang.metadata;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.*;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.reflection.Reflector;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.*;
import java.lang.reflect.Field;
import java.util.Map;
/**
* 为自定义resultType提供resultMap
* <p>
* copy {@link com.baomidou.mybatisplus.core.metadata.TableFieldInfo}
*/
@Getter
@ToString
@EqualsAndHashCode
@SuppressWarnings("serial")
public class TableFieldInfo implements Constants {
/**
* 属性
*
* @since 3.3.1
*/
private final Field field;
/**
* 字段名
*/
private final String column;
/**
* 属性名
*/
private final String property;
/**
* 属性表达式#{property}, 可以指定jdbcType, typeHandler等
*/
private final String el;
/**
* 属性类型
*/
private final Class<?> propertyType;
/**
* 是否是基本数据类型
*
* @since 3.4.0 @2020-6-19
*/
private final boolean isPrimitive;
/**
* 属性是否是 CharSequence 类型
*/
private final boolean isCharSequence;
/**
* 字段验证策略之 insert
* Refer to {@link TableField#insertStrategy()}
*
* @since added v_3.1.2 @2019-5-7
*/
private final FieldStrategy insertStrategy;
/**
* 字段验证策略之 update
* Refer to {@link TableField#updateStrategy()}
*
* @since added v_3.1.2 @2019-5-7
*/
private final FieldStrategy updateStrategy;
/**
* 字段验证策略之 where
* Refer to {@link TableField#whereStrategy()}
*
* @since added v_3.1.2 @2019-5-7
*/
private final FieldStrategy whereStrategy;
/**
* 是否是乐观锁字段
*/
private final boolean version;
/**
* 是否进行 select 查询
* <p>大字段可设置为 false 不加入 select 查询范围</p>
*/
private boolean select = true;
/**
* 是否是逻辑删除字段
*/
private boolean logicDelete = false;
/**
* 逻辑删除值
*/
private String logicDeleteValue;
/**
* 逻辑未删除值
*/
private String logicNotDeleteValue;
/**
* 字段 update set 部分注入
*/
private String update;
/**
* where 字段比较条件
*/
private String condition = SqlCondition.EQUAL;
/**
* 字段填充策略
*/
private FieldFill fieldFill = FieldFill.DEFAULT;
/**
* 表字段是否启用了插入填充
*
* @since 3.3.0
*/
private boolean withInsertFill;
/**
* 表字段是否启用了更新填充
*
* @since 3.3.0
*/
private boolean withUpdateFill;
/**
* 缓存 sql select
*/
@Setter(AccessLevel.NONE)
private String sqlSelect;
/**
* JDBC类型
*
* @since 3.1.2
*/
private JdbcType jdbcType;
/**
* 类型处理器
*
* @since 3.1.2
*/
private Class<? extends TypeHandler<?>> typeHandler;
/**
* 全新的 存在 TableField 注解时使用的构造函数
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public TableFieldInfo(GlobalConfig.DbConfig dbConfig, TableInfo tableInfo, Field field, TableField tableField,
Reflector reflector, boolean existTableLogic) {
field.setAccessible(true);
this.field = field;
this.version = field.getAnnotation(Version.class) != null;
this.property = field.getName();
this.propertyType = reflector.getGetterType(this.property);
this.isPrimitive = this.propertyType.isPrimitive();
this.isCharSequence = StringUtils.isCharSequence(this.propertyType);
this.fieldFill = tableField.fill();
this.withInsertFill = this.fieldFill == FieldFill.INSERT || this.fieldFill == FieldFill.INSERT_UPDATE;
this.withUpdateFill = this.fieldFill == FieldFill.UPDATE || this.fieldFill == FieldFill.INSERT_UPDATE;
this.update = tableField.update();
JdbcType jdbcType = tableField.jdbcType();
final Class<? extends TypeHandler> typeHandler = tableField.typeHandler();
final String numericScale = tableField.numericScale();
String el = this.property;
if (JdbcType.UNDEFINED != jdbcType) {
this.jdbcType = jdbcType;
el += (COMMA + "jdbcType=" + jdbcType.name());
}
if (UnknownTypeHandler.class != typeHandler) {
this.typeHandler = (Class<? extends TypeHandler<?>>) typeHandler;
if (tableField.javaType()) {
String javaType = null;
TypeAliasRegistry registry = tableInfo.getConfiguration().getTypeAliasRegistry();
Map<String, Class<?>> typeAliases = registry.getTypeAliases();
for (Map.Entry<String, Class<?>> entry : typeAliases.entrySet()) {
if (entry.getValue().equals(propertyType)) {
javaType = entry.getKey();
break;
}
}
if (javaType == null) {
javaType = propertyType.getName();
registry.registerAlias(javaType, propertyType);
}
el += (COMMA + "javaType=" + javaType);
}
el += (COMMA + "typeHandler=" + typeHandler.getName());
}
if (StringUtils.isNotBlank(numericScale)) {
el += (COMMA + "numericScale=" + numericScale);
}
this.el = el;
this.initLogicDelete(dbConfig, field, existTableLogic);
String column = tableField.value();
if (StringUtils.isBlank(column)) {
column = this.property;
if (tableInfo.isUnderCamel()) {
/* 开启字段下划线申明 */
column = StringUtils.camelToUnderline(column);
}
if (dbConfig.isCapitalMode()) {
/* 开启字段全大写申明 */
column = column.toUpperCase();
}
}
String columnFormat = dbConfig.getColumnFormat();
if (StringUtils.isNotBlank(columnFormat) && tableField.keepGlobalFormat()) {
column = String.format(columnFormat, column);
}
this.column = column;
this.sqlSelect = column;
if (tableInfo.getResultMap() == null && !tableInfo.isAutoInitResultMap() &&
TableInfoHelper.checkRelated(tableInfo.isUnderCamel(), this.property, this.column)) {
/* 未设置 resultMap 也未开启自动构建 resultMap, 字段规则又不符合 mybatis 的自动封装规则 */
String propertyFormat = dbConfig.getPropertyFormat();
String asProperty = this.property;
if (StringUtils.isNotBlank(propertyFormat)) {
asProperty = String.format(propertyFormat, this.property);
}
this.sqlSelect += (AS + asProperty);
}
this.insertStrategy = this.chooseFieldStrategy(tableField.insertStrategy(), dbConfig.getInsertStrategy());
this.updateStrategy = this.chooseFieldStrategy(tableField.updateStrategy(), dbConfig.getUpdateStrategy());
this.whereStrategy = this.chooseFieldStrategy(tableField.whereStrategy(), dbConfig.getSelectStrategy());
if (StringUtils.isNotBlank(tableField.condition())) {
// 细粒度条件控制
this.condition = tableField.condition();
}
// 字段是否注入查询
this.select = tableField.select();
}
/**
* 优先使用单个字段注解否则使用全局配置
*/
private FieldStrategy chooseFieldStrategy(FieldStrategy fromAnnotation, FieldStrategy fromDbConfig) {
return fromAnnotation == FieldStrategy.DEFAULT ? fromDbConfig : fromAnnotation;
}
/**
* 不存在 TableField 注解时, 使用的构造函数
*/
public TableFieldInfo(GlobalConfig.DbConfig dbConfig, TableInfo tableInfo, Field field, Reflector reflector,
boolean existTableLogic) {
field.setAccessible(true);
this.field = field;
this.version = field.getAnnotation(Version.class) != null;
this.property = field.getName();
this.propertyType = reflector.getGetterType(this.property);
this.isPrimitive = this.propertyType.isPrimitive();
this.isCharSequence = StringUtils.isCharSequence(this.propertyType);
this.el = this.property;
this.insertStrategy = dbConfig.getInsertStrategy();
this.updateStrategy = dbConfig.getUpdateStrategy();
this.whereStrategy = dbConfig.getSelectStrategy();
this.initLogicDelete(dbConfig, field, existTableLogic);
String column = this.property;
if (tableInfo.isUnderCamel()) {
/* 开启字段下划线申明 */
column = StringUtils.camelToUnderline(column);
}
if (dbConfig.isCapitalMode()) {
/* 开启字段全大写申明 */
column = column.toUpperCase();
}
String columnFormat = dbConfig.getColumnFormat();
if (StringUtils.isNotBlank(columnFormat)) {
column = String.format(columnFormat, column);
}
this.column = column;
this.sqlSelect = column;
if (tableInfo.getResultMap() == null && !tableInfo.isAutoInitResultMap() &&
TableInfoHelper.checkRelated(tableInfo.isUnderCamel(), this.property, this.column)) {
/* 未设置 resultMap 也未开启自动构建 resultMap, 字段规则又不符合 mybatis 的自动封装规则 */
String propertyFormat = dbConfig.getPropertyFormat();
String asProperty = this.property;
if (StringUtils.isNotBlank(propertyFormat)) {
asProperty = String.format(propertyFormat, this.property);
}
this.sqlSelect += (AS + asProperty);
}
}
/**
* 逻辑删除初始化
*
* @param dbConfig 数据库全局配置
* @param field 字段属性对象
*/
private void initLogicDelete(GlobalConfig.DbConfig dbConfig, Field field, boolean existTableLogic) {
/* 获取注解属性,逻辑处理字段 */
TableLogic tableLogic = field.getAnnotation(TableLogic.class);
if (null != tableLogic) {
if (StringUtils.isNotBlank(tableLogic.value())) {
this.logicNotDeleteValue = tableLogic.value();
} else {
this.logicNotDeleteValue = dbConfig.getLogicNotDeleteValue();
}
if (StringUtils.isNotBlank(tableLogic.delval())) {
this.logicDeleteValue = tableLogic.delval();
} else {
this.logicDeleteValue = dbConfig.getLogicDeleteValue();
}
this.logicDelete = true;
} else if (!existTableLogic) {
String deleteField = dbConfig.getLogicDeleteField();
if (StringUtils.isNotBlank(deleteField) && this.property.equals(deleteField)) {
this.logicNotDeleteValue = dbConfig.getLogicNotDeleteValue();
this.logicDeleteValue = dbConfig.getLogicDeleteValue();
this.logicDelete = true;
}
}
}
/**
* 获取 ResultMapping
*
* @param configuration MybatisConfiguration
* @return ResultMapping
*/
public 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 这会有影响 registry.register(typeHandler);
}
builder.typeHandler(typeHandler);
}
return builder.build();
}
}

View File

@ -0,0 +1,220 @@
package com.github.yulichang.metadata;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.AccessLevel;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.apache.ibatis.session.Configuration;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 为自定义resultType提供resultMap
* <p>
* copy {@link com.baomidou.mybatisplus.core.metadata.TableInfo}
*/
@Data
@Setter(AccessLevel.PACKAGE)
@Accessors(chain = true)
@SuppressWarnings("serial")
public class TableInfo implements Constants {
/**
* 实体类型
*/
private Class<?> entityType;
/**
* 表主键ID 类型
*/
private IdType idType = IdType.NONE;
/**
* 表名称
*/
private String tableName;
/**
* 表映射结果集
*/
private String resultMap;
/**
* 是否是需要自动生成的 resultMap
*/
private boolean autoInitResultMap;
/**
* 主键是否有存在字段名与属性名关联
* <p>true: 表示要进行 as</p>
*/
private boolean keyRelated;
/**
* 表主键ID 字段名
*/
private String keyColumn;
/**
* 表主键ID 属性名
*/
private String keyProperty;
/**
* 表主键ID 属性类型
*/
private Class<?> keyType;
/**
* 表主键ID Sequence
*/
private KeySequence keySequence;
/**
* 表字段信息列表
*/
private List<TableFieldInfo> fieldList;
/**
* 命名空间 (对应的 mapper 接口的全类名)
*/
private String currentNamespace;
/**
* MybatisConfiguration 标记 (Configuration内存地址值)
*/
@Getter
private Configuration configuration;
/**
* 是否开启下划线转驼峰
* <p>
* 未注解指定字段名的情况下,用于自动从 property 推算 column 的命名
*/
private boolean underCamel;
/**
* 缓存包含主键及字段的 sql select
*/
@Setter(AccessLevel.NONE)
@Getter(AccessLevel.NONE)
private String allSqlSelect;
/**
* 缓存主键字段的 sql select
*/
@Setter(AccessLevel.NONE)
@Getter(AccessLevel.NONE)
private String sqlSelect;
/**
* 表字段是否启用了插入填充
*
* @since 3.3.0
*/
@Getter
@Setter(AccessLevel.NONE)
private boolean withInsertFill;
/**
* 表字段是否启用了更新填充
*
* @since 3.3.0
*/
@Getter
@Setter(AccessLevel.NONE)
private boolean withUpdateFill;
/**
* 表字段是否启用了逻辑删除
*
* @since 3.4.0
*/
@Getter
@Setter(AccessLevel.NONE)
private boolean withLogicDelete;
/**
* 逻辑删除字段
*
* @since 3.4.0
*/
@Getter
@Setter(AccessLevel.NONE)
private TableFieldInfo logicDeleteFieldInfo;
/**
* 表字段是否启用了乐观锁
*
* @since 3.3.1
*/
@Getter
@Setter(AccessLevel.NONE)
private boolean withVersion;
/**
* 乐观锁字段
*
* @since 3.3.1
*/
@Getter
@Setter(AccessLevel.NONE)
private TableFieldInfo versionFieldInfo;
public TableInfo(Class<?> entityType) {
this.entityType = entityType;
}
/**
* 获得注入的 SQL Statement
*
* @param sqlMethod MybatisPlus 支持 SQL 方法
* @return SQL Statement
* @deprecated 3.4.0 如果存在的多mapper共用一个实体的情况这里可能会出现获取命名空间错误的情况
*/
@Deprecated
public String getSqlStatement(String sqlMethod) {
return currentNamespace + DOT + sqlMethod;
}
/**
* 设置 Configuration
*/
void setConfiguration(Configuration configuration) {
Assert.notNull(configuration, "Error: You need Initialize MybatisConfiguration !");
this.configuration = configuration;
this.underCamel = configuration.isMapUnderscoreToCamelCase();
}
/**
* 是否有主键
*
* @return 是否有
*/
public boolean havePK() {
return StringUtils.isNotBlank(keyColumn);
}
void setFieldList(List<TableFieldInfo> fieldList) {
this.fieldList = fieldList;
AtomicInteger logicDeleted = new AtomicInteger();
AtomicInteger version = new AtomicInteger();
fieldList.forEach(i -> {
if (i.isLogicDelete()) {
this.withLogicDelete = true;
this.logicDeleteFieldInfo = i;
logicDeleted.getAndAdd(1);
}
if (i.isWithInsertFill()) {
this.withInsertFill = true;
}
if (i.isWithUpdateFill()) {
this.withUpdateFill = true;
}
if (i.isVersion()) {
this.withVersion = true;
this.versionFieldInfo = i;
version.getAndAdd(1);
}
});
/* 校验字段合法性 */
Assert.isTrue(logicDeleted.get() <= 1, "@TableLogic not support more than one in Class: \"%s\"", entityType.getName());
Assert.isTrue(version.get() <= 1, "@Version not support more than one in Class: \"%s\"", entityType.getName());
}
public List<TableFieldInfo> getFieldList() {
return Collections.unmodifiableList(fieldList);
}
@Deprecated
public boolean isLogicDelete() {
return withLogicDelete;
}
}

View File

@ -0,0 +1,349 @@
package com.github.yulichang.metadata;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.toolkit.*;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.reflection.Reflector;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.session.Configuration;
import java.lang.reflect.Field;
import java.util.*;
import static java.util.stream.Collectors.toList;
/**
* 为自定义resultType提供resultMap
* <p>
* copy {@link com.baomidou.mybatisplus.core.metadata.TableInfoHelper}
*/
public class TableInfoHelper {
private static final Log logger = LogFactory.getLog(TableInfoHelper.class);
/**
* 默认表主键名称
*/
private static final String DEFAULT_ID_NAME = "id";
public synchronized static TableInfo initTableInfo(Configuration configuration, String currentNamespace, Class<?> clazz) {
/* 没有获取到缓存信息,则初始化 */
TableInfo tableInfo = new TableInfo(clazz);
tableInfo.setCurrentNamespace(currentNamespace);
tableInfo.setConfiguration(configuration);
GlobalConfig globalConfig = GlobalConfigUtils.getGlobalConfig(configuration);
/* 初始化表名相关 */
final String[] excludeProperty = initTableName(clazz, globalConfig, tableInfo);
List<String> excludePropertyList = excludeProperty != null && excludeProperty.length > 0 ? Arrays.asList(excludeProperty) : Collections.emptyList();
/* 初始化字段相关 */
initTableFields(clazz, globalConfig, tableInfo, excludePropertyList);
return tableInfo;
}
/**
* <p>
* 初始化 表数据库类型,表名,resultMap
* </p>
*
* @param clazz 实体类
* @param globalConfig 全局配置
* @param tableInfo 数据库表反射信息
* @return 需要排除的字段名
*/
private static String[] initTableName(Class<?> clazz, GlobalConfig globalConfig, TableInfo tableInfo) {
/* 数据库全局配置 */
GlobalConfig.DbConfig dbConfig = globalConfig.getDbConfig();
TableName table = clazz.getAnnotation(TableName.class);
String tableName = clazz.getSimpleName();
String tablePrefix = dbConfig.getTablePrefix();
String schema = dbConfig.getSchema();
boolean tablePrefixEffect = true;
String[] excludeProperty = null;
if (table != null) {
if (StringUtils.isNotBlank(table.value())) {
tableName = table.value();
if (StringUtils.isNotBlank(tablePrefix) && !table.keepGlobalPrefix()) {
tablePrefixEffect = false;
}
} else {
tableName = initTableNameWithDbConfig(tableName, dbConfig);
}
if (StringUtils.isNotBlank(table.schema())) {
schema = table.schema();
}
/* 表结果集映射 */
if (StringUtils.isNotBlank(table.resultMap())) {
tableInfo.setResultMap(table.resultMap());
}
tableInfo.setAutoInitResultMap(table.autoResultMap());
excludeProperty = table.excludeProperty();
} else {
tableName = initTableNameWithDbConfig(tableName, dbConfig);
}
String targetTableName = tableName;
if (StringUtils.isNotBlank(tablePrefix) && tablePrefixEffect) {
targetTableName = tablePrefix + targetTableName;
}
if (StringUtils.isNotBlank(schema)) {
targetTableName = schema + StringPool.DOT + targetTableName;
}
tableInfo.setTableName(targetTableName);
/* 开启了自定义 KEY 生成器 */
if (null != dbConfig.getKeyGenerator()) {
tableInfo.setKeySequence(clazz.getAnnotation(KeySequence.class));
}
return excludeProperty;
}
/**
* 根据 DbConfig 初始化 表名
*
* @param className 类名
* @param dbConfig DbConfig
* @return 表名
*/
private static String initTableNameWithDbConfig(String className, GlobalConfig.DbConfig dbConfig) {
String tableName = className;
// 开启表名下划线申明
if (dbConfig.isTableUnderline()) {
tableName = StringUtils.camelToUnderline(tableName);
}
// 大写命名判断
if (dbConfig.isCapitalMode()) {
tableName = tableName.toUpperCase();
} else {
// 首字母小写
tableName = StringUtils.firstToLowerCase(tableName);
}
return tableName;
}
/**
* <p>
* 初始化 表主键,表字段
* </p>
*
* @param clazz 实体类
* @param globalConfig 全局配置
* @param tableInfo 数据库表反射信息
*/
private static void initTableFields(Class<?> clazz, GlobalConfig globalConfig, TableInfo tableInfo, List<String> excludeProperty) {
/* 数据库全局配置 */
GlobalConfig.DbConfig dbConfig = globalConfig.getDbConfig();
ReflectorFactory reflectorFactory = tableInfo.getConfiguration().getReflectorFactory();
Reflector reflector = reflectorFactory.findForClass(clazz);
List<Field> list = getAllFields(clazz);
// 标记是否读取到主键
boolean isReadPK = false;
// 是否存在 @TableId 注解
boolean existTableId = isExistTableId(list);
// 是否存在 @TableLogic 注解
boolean existTableLogic = isExistTableLogic(list);
List<TableFieldInfo> fieldList = new ArrayList<>(list.size());
for (Field field : list) {
if (excludeProperty.contains(field.getName())) {
continue;
}
/* 主键ID 初始化 */
if (existTableId) {
TableId tableId = field.getAnnotation(TableId.class);
if (tableId != null) {
if (isReadPK) {
throw ExceptionUtils.mpe("@TableId can't more than one in Class: \"%s\".", clazz.getName());
} else {
initTableIdWithAnnotation(dbConfig, tableInfo, field, tableId, reflector);
isReadPK = true;
continue;
}
}
} else if (!isReadPK) {
isReadPK = initTableIdWithoutAnnotation(dbConfig, tableInfo, field, reflector);
if (isReadPK) {
continue;
}
}
final TableField tableField = field.getAnnotation(TableField.class);
/* 有 @TableField 注解的字段初始化 */
if (tableField != null) {
fieldList.add(new TableFieldInfo(dbConfig, tableInfo, field, tableField, reflector, existTableLogic));
continue;
}
/* 无 @TableField 注解的字段初始化 */
fieldList.add(new TableFieldInfo(dbConfig, tableInfo, field, reflector, existTableLogic));
}
/* 字段列表 */
tableInfo.setFieldList(fieldList);
/* 未发现主键注解,提示警告信息 */
if (!isReadPK) {
logger.warn(String.format("Can not find table primary key in Class: \"%s\".", clazz.getName()));
}
}
/**
* <p>
* 判断主键注解是否存在
* </p>
*
* @param list 字段列表
* @return true 为存在 @TableId 注解;
*/
public static boolean isExistTableId(List<Field> list) {
return list.stream().anyMatch(field -> field.isAnnotationPresent(TableId.class));
}
/**
* <p>
* 判断逻辑删除注解是否存在
* </p>
*
* @param list 字段列表
* @return true 为存在 @TableId 注解;
*/
public static boolean isExistTableLogic(List<Field> list) {
return list.stream().anyMatch(field -> field.isAnnotationPresent(TableLogic.class));
}
/**
* <p>
* 主键属性初始化
* </p>
*
* @param dbConfig 全局配置信息
* @param tableInfo 表信息
* @param field 字段
* @param tableId 注解
* @param reflector Reflector
*/
private static void initTableIdWithAnnotation(GlobalConfig.DbConfig dbConfig, TableInfo tableInfo,
Field field, TableId tableId, Reflector reflector) {
boolean underCamel = tableInfo.isUnderCamel();
final String property = field.getName();
if (field.getAnnotation(TableField.class) != null) {
logger.warn(String.format("This \"%s\" is the table primary key by @TableId annotation in Class: \"%s\",So @TableField annotation will not work!",
property, tableInfo.getEntityType().getName()));
}
/* 主键策略( 注解 > 全局 */
// 设置 Sequence 其他策略无效
if (IdType.NONE == tableId.type()) {
tableInfo.setIdType(dbConfig.getIdType());
} else {
tableInfo.setIdType(tableId.type());
}
/* 字段 */
String column = property;
if (StringUtils.isNotBlank(tableId.value())) {
column = tableId.value();
} else {
// 开启字段下划线申明
if (underCamel) {
column = StringUtils.camelToUnderline(column);
}
// 全局大写命名
if (dbConfig.isCapitalMode()) {
column = column.toUpperCase();
}
}
final Class<?> keyType = reflector.getGetterType(property);
if (keyType.isPrimitive()) {
logger.warn(String.format("This primary key of \"%s\" is primitive !不建议如此请使用包装类 in Class: \"%s\"",
property, tableInfo.getEntityType().getName()));
}
tableInfo.setKeyRelated(checkRelated(underCamel, property, column))
.setKeyColumn(column)
.setKeyProperty(property)
.setKeyType(keyType);
}
/**
* <p>
* 主键属性初始化
* </p>
*
* @param tableInfo 表信息
* @param field 字段
* @param reflector Reflector
* @return true 继续下一个属性判断返回 continue;
*/
private static boolean initTableIdWithoutAnnotation(GlobalConfig.DbConfig dbConfig, TableInfo tableInfo,
Field field, Reflector reflector) {
final String property = field.getName();
if (DEFAULT_ID_NAME.equalsIgnoreCase(property)) {
if (field.getAnnotation(TableField.class) != null) {
logger.warn(String.format("This \"%s\" is the table primary key by default name for `id` in Class: \"%s\",So @TableField will not work!",
property, tableInfo.getEntityType().getName()));
}
String column = property;
if (dbConfig.isCapitalMode()) {
column = column.toUpperCase();
}
final Class<?> keyType = reflector.getGetterType(property);
if (keyType.isPrimitive()) {
logger.warn(String.format("This primary key of \"%s\" is primitive !不建议如此请使用包装类 in Class: \"%s\"",
property, tableInfo.getEntityType().getName()));
}
tableInfo.setKeyRelated(checkRelated(tableInfo.isUnderCamel(), property, column))
.setIdType(dbConfig.getIdType())
.setKeyColumn(column)
.setKeyProperty(property)
.setKeyType(keyType);
return true;
}
return false;
}
/**
* 判定 related 的值
* <p>
* true 表示不符合规则
*
* @param underCamel 驼峰命名
* @param property 属性名
* @param column 字段名
* @return related
*/
public static boolean checkRelated(boolean underCamel, String property, String column) {
column = StringUtils.getTargetColumn(column);
String propertyUpper = property.toUpperCase(Locale.ENGLISH);
String columnUpper = column.toUpperCase(Locale.ENGLISH);
if (underCamel) {
// 开启了驼峰并且 column 包含下划线
return !(propertyUpper.equals(columnUpper) ||
propertyUpper.equals(columnUpper.replace(StringPool.UNDERSCORE, StringPool.EMPTY)));
} else {
// 未开启驼峰,直接判断 property 是否与 column 相同(全大写)
return !propertyUpper.equals(columnUpper);
}
}
/**
* <p>
* 获取该类的所有属性列表
* </p>
*
* @param clazz 反射类
* @return 属性集合
*/
public static List<Field> getAllFields(Class<?> clazz) {
List<Field> fieldList = ReflectionKit.getFieldList(ClassUtils.getUserClass(clazz));
return fieldList.stream()
.filter(field -> {
/* 过滤注解非表字段属性 */
TableField tableField = field.getAnnotation(TableField.class);
return (tableField == null || tableField.exist());
}).collect(toList());
}
}

View File

@ -8,7 +8,6 @@ package com.github.yulichang.wrapper;
* @author yulichang
*/
@Deprecated
@SuppressWarnings("DeprecatedIsStillUsed")
public class MPJJoinLambdaQueryWrapper<T> extends MPJLambdaWrapper<T> {