mirror of
https://gitee.com/best_handsome/mybatis-plus-join
synced 2025-07-11 00:02:22 +08:00
升级mybatis-plus版本到 3.4.3
This commit is contained in:
parent
746ecc0e17
commit
f230f52b44
@ -1,9 +1,11 @@
|
|||||||
package com.github.yulichang.interceptor;
|
package com.github.yulichang.interceptor;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.StringPool;
|
import com.baomidou.mybatisplus.core.toolkit.StringPool;
|
||||||
import com.github.yulichang.metadata.TableInfo;
|
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||||
import com.github.yulichang.metadata.TableInfoHelper;
|
|
||||||
import com.github.yulichang.method.MPJResultType;
|
import com.github.yulichang.method.MPJResultType;
|
||||||
import com.github.yulichang.toolkit.Constant;
|
import com.github.yulichang.toolkit.Constant;
|
||||||
import org.apache.ibatis.executor.Executor;
|
import org.apache.ibatis.executor.Executor;
|
||||||
@ -15,9 +17,16 @@ import org.apache.ibatis.plugin.Interceptor;
|
|||||||
import org.apache.ibatis.plugin.Intercepts;
|
import org.apache.ibatis.plugin.Intercepts;
|
||||||
import org.apache.ibatis.plugin.Invocation;
|
import org.apache.ibatis.plugin.Invocation;
|
||||||
import org.apache.ibatis.plugin.Signature;
|
import org.apache.ibatis.plugin.Signature;
|
||||||
|
import org.apache.ibatis.session.Configuration;
|
||||||
import org.apache.ibatis.session.ResultHandler;
|
import org.apache.ibatis.session.ResultHandler;
|
||||||
import org.apache.ibatis.session.RowBounds;
|
import org.apache.ibatis.session.RowBounds;
|
||||||
|
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.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@ -105,12 +114,22 @@ public class MPJInterceptor implements Interceptor {
|
|||||||
* 构建resultMap
|
* 构建resultMap
|
||||||
*/
|
*/
|
||||||
private ResultMap newResultMap(MappedStatement ms, Class<?> resultType) {
|
private ResultMap newResultMap(MappedStatement ms, Class<?> resultType) {
|
||||||
com.baomidou.mybatisplus.core.metadata.TableInfo tableInfo = com.baomidou.mybatisplus.core.metadata.TableInfoHelper.getTableInfo(resultType);
|
TableInfo tableInfo = TableInfoHelper.getTableInfo(resultType);
|
||||||
if (tableInfo != null && tableInfo.isAutoInitResultMap()) {
|
if (tableInfo != null && tableInfo.isAutoInitResultMap()) {
|
||||||
ResultMap resultMap = RM_CACHE.get(resultType);
|
ResultMap resultMap = RM_CACHE.get(resultType);
|
||||||
if (resultMap == null) {
|
if (resultMap == null) {
|
||||||
TableInfo info = TableInfoHelper.initTableInfo(ms.getConfiguration(), ms.getId().substring(0, ms.getId().lastIndexOf(".")), resultType);
|
if (tableInfo.getEntityType() != resultType) {
|
||||||
resultMap = initResultMapIfNeed(info, resultType);
|
try {
|
||||||
|
Method info = TableInfoHelper.class.getDeclaredMethod("initTableInfo", Configuration.class, String.class, Class.class);
|
||||||
|
info.setAccessible(true);
|
||||||
|
Object invoke = info.invoke(TableInfoHelper.class, ms.getConfiguration(), ms.getId().substring(0, ms.getId().lastIndexOf(".")), resultType);
|
||||||
|
tableInfo = (TableInfo) invoke;
|
||||||
|
// tableInfo = TableInfoHelper.initTableInfo(ms.getConfiguration(), ms.getId().substring(0, ms.getId().lastIndexOf(".")), resultType);
|
||||||
|
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resultMap = initResultMapIfNeed(tableInfo, resultType);
|
||||||
RM_CACHE.put(resultType, resultMap);
|
RM_CACHE.put(resultType, resultMap);
|
||||||
}
|
}
|
||||||
return resultMap;
|
return resultMap;
|
||||||
@ -130,8 +149,33 @@ public class MPJInterceptor implements Interceptor {
|
|||||||
resultMappings.add(idMapping);
|
resultMappings.add(idMapping);
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isNotEmpty(info.getFieldList())) {
|
if (CollectionUtils.isNotEmpty(info.getFieldList())) {
|
||||||
info.getFieldList().forEach(i -> resultMappings.add(i.getResultMapping(info.getConfiguration())));
|
info.getFieldList().forEach(i -> resultMappings.add(getResultMapping(i, info.getConfiguration())));
|
||||||
}
|
}
|
||||||
return new ResultMap.Builder(info.getConfiguration(), id, resultType, resultMappings).build();
|
return new ResultMap.Builder(info.getConfiguration(), id, resultType, resultMappings).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 ResultMapping
|
||||||
|
*
|
||||||
|
* @param configuration MybatisConfiguration
|
||||||
|
* @return ResultMapping
|
||||||
|
*/
|
||||||
|
private ResultMapping getResultMapping(TableFieldInfo info, final Configuration configuration) {
|
||||||
|
ResultMapping.Builder builder = new ResultMapping.Builder(configuration, info.getProperty(),
|
||||||
|
StringUtils.getTargetColumn(info.getColumn()), info.getPropertyType());
|
||||||
|
TypeHandlerRegistry registry = configuration.getTypeHandlerRegistry();
|
||||||
|
if (info.getJdbcType() != null && info.getJdbcType() != JdbcType.UNDEFINED) {
|
||||||
|
builder.jdbcType(info.getJdbcType());
|
||||||
|
}
|
||||||
|
if (info.getTypeHandler() != null && info.getTypeHandler() != UnknownTypeHandler.class) {
|
||||||
|
TypeHandler<?> typeHandler = registry.getMappingTypeHandler(info.getTypeHandler());
|
||||||
|
if (typeHandler == null) {
|
||||||
|
typeHandler = registry.getInstance(info.getPropertyType(), info.getTypeHandler());
|
||||||
|
// todo 这会有影响 registry.register(typeHandler);
|
||||||
|
}
|
||||||
|
builder.typeHandler(typeHandler);
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,406 +0,0 @@
|
|||||||
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 com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils;
|
|
||||||
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;
|
|
||||||
/**
|
|
||||||
* jdbcType, typeHandler等部分
|
|
||||||
*/
|
|
||||||
private final String mapping;
|
|
||||||
/**
|
|
||||||
* 属性类型
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否存在OrderBy注解
|
|
||||||
*/
|
|
||||||
private boolean isOrderBy;
|
|
||||||
/**
|
|
||||||
* 排序类型
|
|
||||||
*/
|
|
||||||
private String orderByType;
|
|
||||||
/**
|
|
||||||
* 排序顺序
|
|
||||||
*/
|
|
||||||
private short orderBySort;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 全新的 存在 TableField 注解时使用的构造函数
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
||||||
public TableFieldInfo(GlobalConfig.DbConfig dbConfig, TableInfo tableInfo, Field field, TableField tableField,
|
|
||||||
Reflector reflector, boolean existTableLogic,boolean isOrderBy) {
|
|
||||||
this(dbConfig,tableInfo,field,tableField,reflector,existTableLogic);
|
|
||||||
this.isOrderBy = isOrderBy;
|
|
||||||
if(isOrderBy){
|
|
||||||
initOrderBy(field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 全新的 存在 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 + SqlScriptUtils.mappingJdbcType(jdbcType));
|
|
||||||
}
|
|
||||||
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 + SqlScriptUtils.mappingTypeHandler(this.typeHandler));
|
|
||||||
}
|
|
||||||
if (StringUtils.isNotBlank(numericScale)) {
|
|
||||||
el += (COMMA + SqlScriptUtils.mappingNumericScale(Integer.valueOf(numericScale)));
|
|
||||||
}
|
|
||||||
this.el = el;
|
|
||||||
int index = el.indexOf(COMMA);
|
|
||||||
this.mapping = index > 0 ? el.substring(++index) : null;
|
|
||||||
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,boolean isOrderBy) {
|
|
||||||
this(dbConfig,tableInfo,field,reflector,existTableLogic);
|
|
||||||
this.isOrderBy = isOrderBy;
|
|
||||||
if(isOrderBy){
|
|
||||||
initOrderBy(field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 不存在 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.mapping = null;
|
|
||||||
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 field 字段
|
|
||||||
*/
|
|
||||||
private void initOrderBy(Field field){
|
|
||||||
OrderBy orderBy = field.getAnnotation(OrderBy.class);
|
|
||||||
if (null != orderBy) {
|
|
||||||
this.isOrderBy = true;
|
|
||||||
this.orderBySort = orderBy.sort();
|
|
||||||
this.orderByType = orderBy.isDesc()?"desc":"asc";
|
|
||||||
}else{
|
|
||||||
this.isOrderBy = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 逻辑删除初始化
|
|
||||||
*
|
|
||||||
* @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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,234 +0,0 @@
|
|||||||
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.LinkedList;
|
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 排序列表
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public List<TableFieldInfo> orderByFields;
|
|
||||||
|
|
||||||
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.isOrderBy()) {
|
|
||||||
if (null == this.orderByFields) {
|
|
||||||
this.orderByFields = new LinkedList<>();
|
|
||||||
}
|
|
||||||
this.orderByFields.add(i);
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,363 +0,0 @@
|
|||||||
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 (CollectionUtils.isNotEmpty(dbConfig.getKeyGenerators())) {
|
|
||||||
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);
|
|
||||||
// 是否存在 @OrderBy 注解
|
|
||||||
boolean existOrderBy = isExistOrderBy(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, existOrderBy));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 无 @TableField 注解的字段初始化 */
|
|
||||||
fieldList.add(new TableFieldInfo(dbConfig, tableInfo, field, reflector, existTableLogic, existOrderBy));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 字段列表 */
|
|
||||||
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 list 字段列表
|
|
||||||
* @return true 为存在 @TableId 注解;
|
|
||||||
*/
|
|
||||||
public static boolean isExistOrderBy(List<Field> list) {
|
|
||||||
return list.stream().anyMatch(field -> field.isAnnotationPresent(OrderBy.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());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +1,17 @@
|
|||||||
package com.github.yulichang.toolkit;
|
package com.github.yulichang.toolkit;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
|
|
||||||
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
|
import com.baomidou.mybatisplus.core.toolkit.support.ColumnCache;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.support.*;
|
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||||
|
import com.github.yulichang.toolkit.support.SerializedLambda;
|
||||||
import org.apache.ibatis.reflection.property.PropertyNamer;
|
import org.apache.ibatis.reflection.property.PropertyNamer;
|
||||||
|
|
||||||
import java.lang.invoke.SerializedLambda;
|
import java.lang.ref.WeakReference;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Proxy;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import static java.util.Locale.ENGLISH;
|
import static java.util.Locale.ENGLISH;
|
||||||
@ -24,39 +23,46 @@ public final class LambdaUtils {
|
|||||||
|
|
||||||
/* ******* 自定义方法 *********** */
|
/* ******* 自定义方法 *********** */
|
||||||
public static <T> String getName(SFunction<T, ?> fn) {
|
public static <T> String getName(SFunction<T, ?> fn) {
|
||||||
return PropertyNamer.methodToProperty(extract(fn).getImplMethodName());
|
return PropertyNamer.methodToProperty(resolve(fn).getImplMethodName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T> Class<T> getEntityClass(SFunction<T, ?> fn) {
|
public static <T> Class<T> getEntityClass(SFunction<T, ?> fn) {
|
||||||
return (Class<T>) extract(fn).getInstantiatedClass();
|
return (Class<T>) resolve(fn).getInstantiatedType();
|
||||||
}
|
}
|
||||||
/* ******* 自定义方法 结束 以下代码均为拷贝 *********** */
|
/* ******* 自定义方法 结束 以下代码均为拷贝 *********** */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 字段映射
|
* 字段映射
|
||||||
*/
|
*/
|
||||||
private static final Map<String, Map<String, ColumnCache>> COLUMN_CACHE_MAP = new ConcurrentHashMap<>();
|
private static final Map<String, Map<String, ColumnCache>> COLUMN_CACHE_MAP = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* SerializedLambda 反序列化缓存
|
||||||
|
*/
|
||||||
|
private static final Map<String, WeakReference<SerializedLambda>> FUNC_CACHE = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析 lambda 表达式, 该方法只是调用了 {@link SerializedLambda#resolve(SFunction)} 中的方法,在此基础上加了缓存。
|
||||||
* 该缓存可能会在任意不定的时间被清除
|
* 该缓存可能会在任意不定的时间被清除
|
||||||
*
|
*
|
||||||
* @param func 需要解析的 lambda 对象
|
* @param func 需要解析的 lambda 对象
|
||||||
* @param <T> 类型,被调用的 Function 对象的目标类型
|
* @param <T> 类型,被调用的 Function 对象的目标类型
|
||||||
* @return 返回解析后的结果
|
* @return 返回解析后的结果
|
||||||
|
* @see SerializedLambda#resolve(SFunction)
|
||||||
*/
|
*/
|
||||||
public static <T> LambdaMeta extract(SFunction<T, ?> func) {
|
public static <T> SerializedLambda resolve(SFunction<T, ?> func) {
|
||||||
try {
|
Class<?> clazz = func.getClass();
|
||||||
Method method = func.getClass().getDeclaredMethod("writeReplace");
|
String name = clazz.getName();
|
||||||
return new SerializedLambdaMeta((SerializedLambda) ReflectionKit.setAccessible(method).invoke(func));
|
return Optional.ofNullable(FUNC_CACHE.get(name))
|
||||||
} catch (NoSuchMethodException e) {
|
.map(WeakReference::get)
|
||||||
if (func instanceof Proxy) return new ProxyLambdaMeta((Proxy) func);
|
.orElseGet(() -> {
|
||||||
String message = "Cannot find method writeReplace, please make sure that the lambda composite class is currently passed in";
|
SerializedLambda lambda = SerializedLambda.resolve(func);
|
||||||
throw new MybatisPlusException(message);
|
FUNC_CACHE.put(name, new WeakReference<>(lambda));
|
||||||
} catch (InvocationTargetException | IllegalAccessException e) {
|
return lambda;
|
||||||
throw new MybatisPlusException(e);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -99,7 +105,7 @@ public final class LambdaUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
info.getFieldList().forEach(i ->
|
info.getFieldList().forEach(i ->
|
||||||
map.put(formatKey(i.getProperty()), new ColumnCache(i.getColumn(), i.getSqlSelect(), i.getMapping()))
|
map.put(formatKey(i.getProperty()), new ColumnCache(i.getColumn(), i.getSqlSelect()))
|
||||||
);
|
);
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,221 @@
|
|||||||
|
package com.github.yulichang.toolkit.sql;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||||
|
import org.apache.ibatis.type.JdbcType;
|
||||||
|
import org.apache.ibatis.type.TypeHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* sql 脚本工具类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author miemie
|
||||||
|
* @since 2018-08-15
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public abstract class SqlScriptUtils implements Constants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 获取 带 if 标签的脚本
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param sqlScript sql 脚本片段
|
||||||
|
* @return if 脚本
|
||||||
|
*/
|
||||||
|
public static String convertIf(final String sqlScript, final String ifTest, boolean newLine) {
|
||||||
|
String newSqlScript = sqlScript;
|
||||||
|
if (newLine) {
|
||||||
|
newSqlScript = NEWLINE + newSqlScript + NEWLINE;
|
||||||
|
}
|
||||||
|
return String.format("<if test=\"%s\">%s</if>", ifTest, newSqlScript);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 获取 带 trim 标签的脚本
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param sqlScript sql 脚本片段
|
||||||
|
* @param prefix 以...开头
|
||||||
|
* @param suffix 以...结尾
|
||||||
|
* @param prefixOverrides 干掉最前一个...
|
||||||
|
* @param suffixOverrides 干掉最后一个...
|
||||||
|
* @return trim 脚本
|
||||||
|
*/
|
||||||
|
public static String convertTrim(final String sqlScript, final String prefix, final String suffix,
|
||||||
|
final String prefixOverrides, final String suffixOverrides) {
|
||||||
|
StringBuilder sb = new StringBuilder("<trim");
|
||||||
|
if (StringUtils.isNotBlank(prefix)) {
|
||||||
|
sb.append(" prefix=\"").append(prefix).append(QUOTE);
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(suffix)) {
|
||||||
|
sb.append(" suffix=\"").append(suffix).append(QUOTE);
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(prefixOverrides)) {
|
||||||
|
sb.append(" prefixOverrides=\"").append(prefixOverrides).append(QUOTE);
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(suffixOverrides)) {
|
||||||
|
sb.append(" suffixOverrides=\"").append(suffixOverrides).append(QUOTE);
|
||||||
|
}
|
||||||
|
return sb.append(RIGHT_CHEV).append(NEWLINE).append(sqlScript).append(NEWLINE).append("</trim>").toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 生成 choose 标签的脚本
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param whenTest when 内 test 的内容
|
||||||
|
* @param otherwise otherwise 内容
|
||||||
|
* @return choose 脚本
|
||||||
|
*/
|
||||||
|
public static String convertChoose(final String whenTest, final String whenSqlScript, final String otherwise) {
|
||||||
|
return "<choose>" + NEWLINE
|
||||||
|
+ "<when test=\"" + whenTest + QUOTE + RIGHT_CHEV + NEWLINE
|
||||||
|
+ whenSqlScript + NEWLINE + "</when>" + NEWLINE
|
||||||
|
+ "<otherwise>" + otherwise + "</otherwise>" + NEWLINE
|
||||||
|
+ "</choose>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 生成 foreach 标签的脚本
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param sqlScript foreach 内部的 sql 脚本
|
||||||
|
* @param collection collection
|
||||||
|
* @param index index
|
||||||
|
* @param item item
|
||||||
|
* @param separator separator
|
||||||
|
* @return foreach 脚本
|
||||||
|
*/
|
||||||
|
public static String convertForeach(final String sqlScript, final String collection, final String index,
|
||||||
|
final String item, final String separator) {
|
||||||
|
StringBuilder sb = new StringBuilder("<foreach");
|
||||||
|
if (StringUtils.isNotBlank(collection)) {
|
||||||
|
sb.append(" collection=\"").append(collection).append(QUOTE);
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(index)) {
|
||||||
|
sb.append(" index=\"").append(index).append(QUOTE);
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(item)) {
|
||||||
|
sb.append(" item=\"").append(item).append(QUOTE);
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(separator)) {
|
||||||
|
sb.append(" separator=\"").append(separator).append(QUOTE);
|
||||||
|
}
|
||||||
|
return sb.append(RIGHT_CHEV).append(NEWLINE).append(sqlScript).append(NEWLINE).append("</foreach>").toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 生成 where 标签的脚本
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param sqlScript where 内部的 sql 脚本
|
||||||
|
* @return where 脚本
|
||||||
|
*/
|
||||||
|
public static String convertWhere(final String sqlScript) {
|
||||||
|
return "<where>" + NEWLINE + sqlScript + NEWLINE + "</where>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 生成 set 标签的脚本
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param sqlScript set 内部的 sql 脚本
|
||||||
|
* @return set 脚本
|
||||||
|
*/
|
||||||
|
public static String convertSet(final String sqlScript) {
|
||||||
|
return "<set>" + NEWLINE + sqlScript + NEWLINE + "</set>";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 安全入参: #{入参}
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param param 入参
|
||||||
|
* @return 脚本
|
||||||
|
*/
|
||||||
|
public static String safeParam(final String param) {
|
||||||
|
return safeParam(param, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 安全入参: #{入参,mapping}
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param param 入参
|
||||||
|
* @param mapping 映射
|
||||||
|
* @return 脚本
|
||||||
|
*/
|
||||||
|
public static String safeParam(final String param, final String mapping) {
|
||||||
|
String target = HASH_LEFT_BRACE + param;
|
||||||
|
if (StringUtils.isBlank(mapping)) {
|
||||||
|
return target + RIGHT_BRACE;
|
||||||
|
}
|
||||||
|
return target + COMMA + mapping + RIGHT_BRACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 非安全入参: ${入参}
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param param 入参
|
||||||
|
* @return 脚本
|
||||||
|
*/
|
||||||
|
public static String unSafeParam(final String param) {
|
||||||
|
return DOLLAR_LEFT_BRACE + param + RIGHT_BRACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String mappingTypeHandler(Class<? extends TypeHandler<?>> typeHandler) {
|
||||||
|
if (typeHandler != null) {
|
||||||
|
return "typeHandler=" + typeHandler.getName();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String mappingJdbcType(JdbcType jdbcType) {
|
||||||
|
if (jdbcType != null) {
|
||||||
|
return "jdbcType=" + jdbcType.name();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String mappingNumericScale(Integer numericScale) {
|
||||||
|
if (numericScale != null) {
|
||||||
|
return "numericScale=" + numericScale;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String convertParamMapping(Class<? extends TypeHandler<?>> typeHandler, JdbcType jdbcType, Integer numericScale) {
|
||||||
|
if (typeHandler == null && jdbcType == null && numericScale == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String mapping = null;
|
||||||
|
if (typeHandler != null) {
|
||||||
|
mapping = mappingTypeHandler(typeHandler);
|
||||||
|
}
|
||||||
|
if (jdbcType != null) {
|
||||||
|
mapping = appendMapping(mapping, mappingJdbcType(jdbcType));
|
||||||
|
}
|
||||||
|
if (numericScale != null) {
|
||||||
|
mapping = appendMapping(mapping, mappingNumericScale(numericScale));
|
||||||
|
}
|
||||||
|
return mapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String appendMapping(String mapping, String other) {
|
||||||
|
if (mapping != null) {
|
||||||
|
return mapping + COMMA + other;
|
||||||
|
}
|
||||||
|
return other;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,128 @@
|
|||||||
|
package com.github.yulichang.toolkit.support;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.ClassUtils;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.SerializationUtils;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 这个类是从 {@link java.lang.invoke.SerializedLambda} 里面 copy 过来的,
|
||||||
|
* 字段信息完全一样
|
||||||
|
* <p>负责将一个支持序列的 Function 序列化为 SerializedLambda</p>
|
||||||
|
*
|
||||||
|
* @author HCL
|
||||||
|
* @since 2018/05/10
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class SerializedLambda implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 8025925345765570181L;
|
||||||
|
|
||||||
|
private Class<?> capturingClass;
|
||||||
|
private String functionalInterfaceClass;
|
||||||
|
private String functionalInterfaceMethodName;
|
||||||
|
private String functionalInterfaceMethodSignature;
|
||||||
|
private String implClass;
|
||||||
|
private String implMethodName;
|
||||||
|
private String implMethodSignature;
|
||||||
|
private int implMethodKind;
|
||||||
|
private String instantiatedMethodType;
|
||||||
|
private Object[] capturedArgs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过反序列化转换 lambda 表达式,该方法只能序列化 lambda 表达式,不能序列化接口实现或者正常非 lambda 写法的对象
|
||||||
|
*
|
||||||
|
* @param lambda lambda对象
|
||||||
|
* @return 返回解析后的 SerializedLambda
|
||||||
|
*/
|
||||||
|
public static SerializedLambda resolve(SFunction<?, ?> lambda) {
|
||||||
|
if (!lambda.getClass().isSynthetic()) {
|
||||||
|
throw ExceptionUtils.mpe("该方法仅能传入 lambda 表达式产生的合成类");
|
||||||
|
}
|
||||||
|
try (ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(SerializationUtils.serialize(lambda))) {
|
||||||
|
@Override
|
||||||
|
protected Class<?> resolveClass(ObjectStreamClass objectStreamClass) throws IOException, ClassNotFoundException {
|
||||||
|
Class<?> clazz;
|
||||||
|
try {
|
||||||
|
clazz = ClassUtils.toClassConfident(objectStreamClass.getName());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
clazz = super.resolveClass(objectStreamClass);
|
||||||
|
}
|
||||||
|
return clazz == java.lang.invoke.SerializedLambda.class ? SerializedLambda.class : clazz;
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
return (SerializedLambda) objIn.readObject();
|
||||||
|
} catch (ClassNotFoundException | IOException e) {
|
||||||
|
throw ExceptionUtils.mpe("This is impossible to happen", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取接口 class
|
||||||
|
*
|
||||||
|
* @return 返回 class 名称
|
||||||
|
*/
|
||||||
|
public String getFunctionalInterfaceClassName() {
|
||||||
|
return normalizedName(functionalInterfaceClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取实现的 class
|
||||||
|
*
|
||||||
|
* @return 实现类
|
||||||
|
*/
|
||||||
|
public Class<?> getImplClass() {
|
||||||
|
return ClassUtils.toClassConfident(getImplClassName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 class 的名称
|
||||||
|
*
|
||||||
|
* @return 类名
|
||||||
|
*/
|
||||||
|
public String getImplClassName() {
|
||||||
|
return normalizedName(implClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取实现者的方法名称
|
||||||
|
*
|
||||||
|
* @return 方法名称
|
||||||
|
*/
|
||||||
|
public String getImplMethodName() {
|
||||||
|
return implMethodName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正常化类名称,将类名称中的 / 替换为 .
|
||||||
|
*
|
||||||
|
* @param name 名称
|
||||||
|
* @return 正常的类名
|
||||||
|
*/
|
||||||
|
private String normalizedName(String name) {
|
||||||
|
return name.replace('/', '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return 获取实例化方法的类型
|
||||||
|
*/
|
||||||
|
public Class<?> getInstantiatedType() {
|
||||||
|
String instantiatedTypeName = normalizedName(instantiatedMethodType.substring(2, instantiatedMethodType.indexOf(';')));
|
||||||
|
return ClassUtils.toClassConfident(instantiatedTypeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return 字符串形式
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
String interfaceName = getFunctionalInterfaceClassName();
|
||||||
|
String implName = getImplClassName();
|
||||||
|
return String.format("%s -> %s::%s",
|
||||||
|
interfaceName.substring(interfaceName.lastIndexOf('.') + 1),
|
||||||
|
implName.substring(implName.lastIndexOf('.') + 1),
|
||||||
|
implMethodName);
|
||||||
|
}
|
||||||
|
}
|
@ -8,10 +8,10 @@ import com.baomidou.mybatisplus.core.conditions.segments.MergeSegments;
|
|||||||
import com.baomidou.mybatisplus.core.enums.SqlKeyword;
|
import com.baomidou.mybatisplus.core.enums.SqlKeyword;
|
||||||
import com.baomidou.mybatisplus.core.enums.SqlLike;
|
import com.baomidou.mybatisplus.core.enums.SqlLike;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.*;
|
import com.baomidou.mybatisplus.core.toolkit.*;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils;
|
|
||||||
import com.baomidou.mybatisplus.core.toolkit.sql.SqlUtils;
|
import com.baomidou.mybatisplus.core.toolkit.sql.SqlUtils;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.sql.StringEscape;
|
import com.baomidou.mybatisplus.core.toolkit.sql.StringEscape;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||||
|
import com.github.yulichang.toolkit.sql.SqlScriptUtils;
|
||||||
import com.github.yulichang.wrapper.interfaces.Compare;
|
import com.github.yulichang.wrapper.interfaces.Compare;
|
||||||
import com.github.yulichang.wrapper.interfaces.Func;
|
import com.github.yulichang.wrapper.interfaces.Func;
|
||||||
import com.github.yulichang.wrapper.interfaces.Join;
|
import com.github.yulichang.wrapper.interfaces.Join;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user