mirror of
https://gitee.com/best_handsome/mybatis-plus-join
synced 2025-07-11 00:02:22 +08:00
一对一 一对多 关系映射注解实现
This commit is contained in:
parent
1f267b1cc2
commit
866bccff28
5
pom.xml
5
pom.xml
@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.github.yulichang</groupId>
|
||||
<artifactId>mybatis-plus-join</artifactId>
|
||||
<version>1.1.8</version>
|
||||
<version>1.1.9-SNAPSHOT</version>
|
||||
<name>mybatis-plus-join</name>
|
||||
<description>An enhanced toolkit of Mybatis-Plus to simplify development.</description>
|
||||
<url>https://github.com/yulichang/mybatis-plus-join</url>
|
||||
@ -32,6 +32,9 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<jdkVersion>1.8</jdkVersion>
|
||||
<jdkVersion.test>1.8</jdkVersion.test>
|
||||
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@ -0,0 +1,86 @@
|
||||
package com.baomidou.mybatisplus.core.metadata;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.core.enums.SqlKeyword;
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||
import com.github.yulichang.annotation.MPJMapping;
|
||||
import com.github.yulichang.annotation.MPJMappingApply;
|
||||
import com.github.yulichang.annotation.MPJMappingCondition;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 关联查询条件
|
||||
*
|
||||
* @author yulichang
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Data
|
||||
public class MPJMappingWrapper {
|
||||
|
||||
private final boolean hasFirst;
|
||||
private String first;
|
||||
|
||||
private final boolean hasSelect;
|
||||
private String select;
|
||||
|
||||
private final boolean hasApply;
|
||||
private List<Apply> applyList;
|
||||
|
||||
private final boolean hasCondition;
|
||||
private List<Condition> conditionList;
|
||||
|
||||
private final boolean hasLast;
|
||||
private String last;
|
||||
|
||||
public MPJMappingWrapper(MPJMapping mapping) {
|
||||
this.hasFirst = StringUtils.isNotBlank(mapping.first());
|
||||
if (this.hasFirst) {
|
||||
this.first = mapping.first();
|
||||
}
|
||||
|
||||
this.hasSelect = StringUtils.isNotBlank(mapping.select());
|
||||
if (this.hasSelect) {
|
||||
this.select = mapping.select();
|
||||
}
|
||||
|
||||
this.hasApply = mapping.apply().length > 0;
|
||||
if (this.hasApply) {
|
||||
this.applyList = new ArrayList<>();
|
||||
for (MPJMappingApply apply : mapping.apply()) {
|
||||
this.applyList.add(new Apply(apply.value(), apply.args()));
|
||||
}
|
||||
}
|
||||
|
||||
this.hasCondition = mapping.condition().length > 0;
|
||||
if (this.hasCondition) {
|
||||
this.conditionList = new ArrayList<>();
|
||||
for (MPJMappingCondition condition : mapping.condition()) {
|
||||
conditionList.add(new Condition(condition.keyWord(), condition.column(), condition.value()));
|
||||
}
|
||||
}
|
||||
|
||||
this.hasLast = StringUtils.isNotBlank(mapping.last());
|
||||
if (this.hasLast) {
|
||||
this.last = mapping.last();
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public static class Apply {
|
||||
private String sql;
|
||||
private String[] val;
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public static class Condition {
|
||||
private SqlKeyword keyword;
|
||||
private String column;
|
||||
private String[] val;
|
||||
}
|
||||
}
|
@ -0,0 +1,243 @@
|
||||
package com.baomidou.mybatisplus.core.metadata;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Assert;
|
||||
import com.baomidou.mybatisplus.core.toolkit.ClassUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||
import com.github.yulichang.annotation.MPJMapping;
|
||||
import com.github.yulichang.base.MPJBaseMapper;
|
||||
import com.github.yulichang.exception.MPJException;
|
||||
import com.github.yulichang.toolkit.SpringContentUtils;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 字段属性
|
||||
*
|
||||
* @author yulichang
|
||||
* @see TableFieldInfo
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
public class MPJTableFieldInfo {
|
||||
|
||||
/**
|
||||
* 实体类
|
||||
*/
|
||||
private final Class<?> entityType;
|
||||
/**
|
||||
* 属性
|
||||
*/
|
||||
private final Field field;
|
||||
/**
|
||||
* 属性
|
||||
*/
|
||||
private final boolean fieldIsMap;
|
||||
/**
|
||||
* 属性是否是集合
|
||||
*/
|
||||
private final boolean isCollection;
|
||||
/**
|
||||
* 当前映射属性
|
||||
*/
|
||||
private Field thisField;
|
||||
/**
|
||||
* 当前类实体属性
|
||||
*/
|
||||
private final String thisProperty;
|
||||
/**
|
||||
* 当前字段信息
|
||||
*/
|
||||
private String thisColumn;
|
||||
/**
|
||||
* 当前字段信息
|
||||
*/
|
||||
private String thisMapKey;
|
||||
/**
|
||||
* 映射实体类
|
||||
*/
|
||||
private final Class<?> joinClass;
|
||||
/**
|
||||
* 映射属性名
|
||||
*/
|
||||
private final String joinProperty;
|
||||
/**
|
||||
* 映射属性数据库列名
|
||||
*/
|
||||
private String joinColumn;
|
||||
/**
|
||||
* 映射属性字段
|
||||
*/
|
||||
private Field joinField;
|
||||
/**
|
||||
* fieldIsMap 为true时使用
|
||||
* 映射查询Map 的key
|
||||
* 默认为 关联字段的数据库列名
|
||||
*/
|
||||
private String joinMapKey;
|
||||
/**
|
||||
* 关联的mapper引用
|
||||
*/
|
||||
private MPJBaseMapper<?> joinMapper;
|
||||
/**
|
||||
* 关联查询条件配置
|
||||
*/
|
||||
private final MPJMappingWrapper wrapper;
|
||||
|
||||
/**
|
||||
* 初始化关联字段信息
|
||||
*/
|
||||
public MPJTableFieldInfo(Class<?> entityType, MPJMapping mapping, Field field) {
|
||||
field.setAccessible(true);
|
||||
this.entityType = entityType;
|
||||
this.field = field;
|
||||
this.joinClass = mapping.tag();
|
||||
this.isCollection = Collection.class.isAssignableFrom(field.getType());
|
||||
this.thisMapKey = StringUtils.isBlank(mapping.thisMapKey()) ? null : mapping.thisMapKey();
|
||||
this.joinMapKey = StringUtils.isBlank(mapping.joinMapKsy()) ? null : mapping.joinMapKsy();
|
||||
this.fieldIsMap = mapping.isMap();//TODO 应该可以自动检测
|
||||
this.wrapper = new MPJMappingWrapper(mapping);
|
||||
if (this.isCollection && field.getType() != List.class && field.getType() != ArrayList.class) {
|
||||
throw new MPJException("对多关系的数据结构目前只支持 <List> 暂不支持其他Collection实现 " + field.getType().getTypeName());
|
||||
}
|
||||
if (StringUtils.isNotBlank(mapping.joinField())) {
|
||||
this.joinProperty = mapping.joinField();
|
||||
} else {
|
||||
TableInfo info = getTableInfo(this.joinClass);
|
||||
Assert.isTrue(info.havePK(), "实体未定义主键 %s ", this.joinClass.getName());
|
||||
this.joinProperty = info.getKeyProperty();
|
||||
}
|
||||
if (StringUtils.isNotBlank(mapping.thisField())) {
|
||||
this.thisProperty = mapping.thisField();
|
||||
} else {
|
||||
TableInfo info = getTableInfo(this.entityType);
|
||||
Assert.isTrue(info.havePK(), "实体未定义主键 %s ", this.entityType.getName());
|
||||
this.thisProperty = info.getKeyProperty();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public Field getThisField() {
|
||||
if (this.thisField == null) {
|
||||
TableInfo tableInfo = getTableInfo(this.entityType);
|
||||
if (tableInfo.havePK() && this.thisProperty.equals(tableInfo.getKeyProperty())) {
|
||||
this.thisField = ReflectionKit.getFieldList(ClassUtils.getUserClass(entityType)).stream().filter(f ->
|
||||
f.getName().equals(tableInfo.getKeyProperty())).findFirst().orElse(null);
|
||||
Assert.notNull(this.thisField, "MPJMapping注解thisField不存在 %s , %s", entityType.getName(),
|
||||
StringUtils.isBlank(this.thisProperty) ? "主键" : this.thisProperty);
|
||||
this.thisColumn = tableInfo.getKeyColumn();
|
||||
} else {
|
||||
TableFieldInfo fieldInfo = tableInfo.getFieldList().stream().filter(f ->
|
||||
f.getField().getName().equals(this.thisProperty)).findFirst().orElse(null);
|
||||
Assert.notNull(fieldInfo, "MPJMapping注解thisField不存在 %s , %s", entityType.getName(),
|
||||
StringUtils.isBlank(this.thisProperty) ? "主键" : this.thisProperty);
|
||||
this.thisField = fieldInfo.getField();
|
||||
this.thisColumn = fieldInfo.getColumn();
|
||||
}
|
||||
this.thisField.setAccessible(true);
|
||||
}
|
||||
return this.thisField;
|
||||
}
|
||||
|
||||
public String getJoinColumn() {
|
||||
if (StringUtils.isBlank(this.joinColumn)) {
|
||||
TableInfo joinTableInfo = getTableInfo(this.joinClass);
|
||||
TableFieldInfo joinFieldInfo = joinTableInfo.getFieldList().stream().filter(f ->
|
||||
f.getField().getName().equals(this.joinProperty)).findFirst().orElse(null);
|
||||
if (joinFieldInfo == null) {
|
||||
if (joinTableInfo.havePK() && this.joinProperty.equals(joinTableInfo.getKeyProperty())) {
|
||||
this.joinColumn = joinTableInfo.getKeyColumn();
|
||||
this.joinField = ReflectionKit.getFieldList(this.joinClass).stream().filter(i ->
|
||||
i.getName().equals(joinTableInfo.getKeyProperty())).findFirst().orElse(null);
|
||||
}
|
||||
} else {
|
||||
this.joinColumn = joinFieldInfo.getColumn();
|
||||
this.joinField = joinFieldInfo.getField();
|
||||
}
|
||||
Assert.notNull(this.joinField, "MPJMapping注解thisField不存在 %s , %s", this.joinClass.getName(),
|
||||
StringUtils.isBlank(this.joinProperty) ? "主键" : this.joinProperty);
|
||||
Assert.notNull(this.joinColumn, "MPJMapping注解thisField不存在 %s , %s", this.joinClass.getName(),
|
||||
StringUtils.isBlank(this.joinProperty) ? "主键" : this.joinProperty);
|
||||
this.joinField.setAccessible(true);
|
||||
}
|
||||
return this.joinColumn;
|
||||
}
|
||||
|
||||
public String getThisMapKey() {
|
||||
if (this.thisMapKey == null) {
|
||||
this.thisMapKey = getJoinColumn();
|
||||
}
|
||||
return this.thisMapKey;
|
||||
}
|
||||
|
||||
public Field getJoinField() {
|
||||
if (this.joinField == null) {
|
||||
this.getJoinColumn();
|
||||
}
|
||||
return this.joinField;
|
||||
}
|
||||
|
||||
|
||||
public String getJoinMapKey() {
|
||||
if (this.joinMapKey == null) {
|
||||
this.joinMapKey = getJoinColumn();
|
||||
}
|
||||
return joinMapKey;
|
||||
}
|
||||
|
||||
public MPJBaseMapper<?> getJoinMapper() {
|
||||
if (this.joinMapper == null) {
|
||||
MPJTableInfo joinTableInfo = MPJTableInfoHelper.getTableInfos().stream().filter(table ->
|
||||
table.getTableInfo().getEntityType() == this.joinClass).findFirst().orElse(null);
|
||||
if (joinTableInfo == null) {
|
||||
throw new MPJException("未注册 mapper " + this.joinClass.getName());
|
||||
}
|
||||
this.joinMapper = (MPJBaseMapper<?>) SpringContentUtils.getApplicationContext().getBean(joinTableInfo.getMapperClass());
|
||||
}
|
||||
return this.joinMapper;
|
||||
}
|
||||
|
||||
private TableInfo getTableInfo(Class<?> clazz) {
|
||||
TableInfo tableInfo = TableInfoHelper.getTableInfo(clazz);
|
||||
if (tableInfo == null) {
|
||||
throw new MPJException("未注册 mapper " + clazz.getName());
|
||||
}
|
||||
return tableInfo;
|
||||
}
|
||||
|
||||
|
||||
public void fieldSet(Object o, Object val) {
|
||||
try {
|
||||
this.field.set(o, val);
|
||||
} catch (Exception e) {
|
||||
throw new MPJException("无法设置关联字段,请检查关联字段数据类型是否匹配 " + this.entityType.getName() +
|
||||
" , " + this.field.getName() + " , " + o.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
public Object thisFieldGet(Object o) {
|
||||
try {
|
||||
return getThisField().get(o);
|
||||
} catch (Exception e) {
|
||||
throw new MPJException("无法获取当前关联字段,请检查关联字段是否匹配 " + this.entityType.getName() + " , " +
|
||||
this.thisField.getName() + " , " + o.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
public Object joinFieldGet(Object o) {
|
||||
try {
|
||||
return getJoinField().get(o);
|
||||
} catch (Exception e) {
|
||||
throw new MPJException("无法设置关联字段,请检查关联字段数据类型是否匹配 " + this.joinClass.getName() + " , " +
|
||||
this.joinField.getName() + " , " + o.getClass().getName());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.baomidou.mybatisplus.core.metadata;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据库表反射信息
|
||||
*
|
||||
* @author yulichang
|
||||
* @see TableInfo
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Data
|
||||
@Setter(AccessLevel.PACKAGE)
|
||||
@Accessors(chain = true)
|
||||
public class MPJTableInfo {
|
||||
|
||||
private TableInfo tableInfo;
|
||||
|
||||
/**
|
||||
* 是否包含映射注解
|
||||
*/
|
||||
private boolean hasMapping;
|
||||
|
||||
/**
|
||||
* mapperClass
|
||||
*/
|
||||
private Class<?> mapperClass;
|
||||
|
||||
/**
|
||||
* 包含映射注解的字段列表
|
||||
*/
|
||||
private List<MPJTableFieldInfo> fieldList;
|
||||
}
|
@ -3,6 +3,8 @@ package com.baomidou.mybatisplus.core.metadata;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.baomidou.mybatisplus.core.config.GlobalConfig;
|
||||
import com.baomidou.mybatisplus.core.toolkit.*;
|
||||
import com.github.yulichang.annotation.MPJMapping;
|
||||
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
||||
import org.apache.ibatis.logging.Log;
|
||||
import org.apache.ibatis.logging.LogFactory;
|
||||
import org.apache.ibatis.mapping.ResultFlag;
|
||||
@ -38,7 +40,7 @@ public class MPJTableInfoHelper {
|
||||
/**
|
||||
* 储存反射类表信息
|
||||
*/
|
||||
private static final Map<Class<?>, TableInfo> TABLE_INFO_CACHE = new ConcurrentHashMap<>();
|
||||
private static final Map<Class<?>, MPJTableInfo> TABLE_INFO_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 默认表主键名称
|
||||
@ -54,13 +56,47 @@ public class MPJTableInfoHelper {
|
||||
* @param clazz 反射实体类
|
||||
* @return 数据库表反射信息
|
||||
*/
|
||||
public static TableInfo getTableInfo(Class<?> clazz) {
|
||||
public static MPJTableInfo getTableInfo(Class<?> clazz) {
|
||||
if (clazz == null || ReflectionKit.isPrimitiveOrWrapper(clazz) || clazz == String.class || clazz.isInterface()) {
|
||||
return null;
|
||||
}
|
||||
return TABLE_INFO_CACHE.get(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 实体类反射获取表信息【初始化】
|
||||
* </p>
|
||||
*
|
||||
* @param clazz 反射实体类
|
||||
* @param mapperClass mapperClass
|
||||
*/
|
||||
public synchronized static void initTableInfo(MapperBuilderAssistant builderAssistant, Class<?> clazz, Class<?> mapperClass) {
|
||||
MPJTableInfo targetTableInfo = TABLE_INFO_CACHE.get(clazz);
|
||||
final Configuration configuration = builderAssistant.getConfiguration();
|
||||
if (targetTableInfo != null) {
|
||||
Configuration oldConfiguration = targetTableInfo.getTableInfo().getConfiguration();
|
||||
if (!oldConfiguration.equals(configuration)) {
|
||||
// 不是同一个 Configuration,进行重新初始化
|
||||
initTableInfo(configuration, builderAssistant.getCurrentNamespace(), clazz, mapperClass);
|
||||
}
|
||||
return;
|
||||
}
|
||||
initTableInfo(configuration, builderAssistant.getCurrentNamespace(), clazz, mapperClass);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 获取所有实体映射表信息
|
||||
* </p>
|
||||
*
|
||||
* @return 数据库表反射信息集合
|
||||
*/
|
||||
public static List<MPJTableInfo> getTableInfos() {
|
||||
return Collections.unmodifiableList(new ArrayList<>(TABLE_INFO_CACHE.values()));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 实体类反射获取表信息【初始化】
|
||||
@ -69,13 +105,26 @@ public class MPJTableInfoHelper {
|
||||
* @param clazz 反射实体类
|
||||
* @return 数据库表反射信息
|
||||
*/
|
||||
public synchronized static TableInfo initTableInfo(Configuration configuration, String currentNamespace, Class<?> clazz) {
|
||||
TableInfo info = TABLE_INFO_CACHE.get(clazz);
|
||||
public synchronized static MPJTableInfo initTableInfo(Configuration configuration, String currentNamespace, Class<?> clazz, Class<?> mapperClass) {
|
||||
MPJTableInfo info = TABLE_INFO_CACHE.get(clazz);
|
||||
if (info != null) {
|
||||
return info;
|
||||
}
|
||||
/* 没有获取到缓存信息,则初始化 */
|
||||
TableInfo tableInfo = new TableInfo(clazz);
|
||||
MPJTableInfo mpjTableInfo = new MPJTableInfo();
|
||||
mpjTableInfo.setMapperClass(mapperClass);
|
||||
TableInfo tableInfo = TableInfoHelper.getTableInfo(clazz);
|
||||
if (tableInfo != null) {
|
||||
mpjTableInfo.setTableInfo(tableInfo);
|
||||
initMapping(mpjTableInfo);
|
||||
/* 添加缓存 */
|
||||
TABLE_INFO_CACHE.put(clazz, mpjTableInfo);
|
||||
return mpjTableInfo;
|
||||
}
|
||||
|
||||
|
||||
tableInfo = new TableInfo(clazz);
|
||||
mpjTableInfo.setTableInfo(tableInfo);
|
||||
tableInfo.setCurrentNamespace(currentNamespace);
|
||||
tableInfo.setConfiguration(configuration);
|
||||
GlobalConfig globalConfig = GlobalConfigUtils.getGlobalConfig(configuration);
|
||||
@ -86,17 +135,20 @@ public class MPJTableInfoHelper {
|
||||
List<String> excludePropertyList = excludeProperty != null && excludeProperty.length > 0 ? Arrays.asList(excludeProperty) : Collections.emptyList();
|
||||
|
||||
/* 初始化字段相关 */
|
||||
initTableFields(clazz, globalConfig, tableInfo, excludePropertyList);
|
||||
initTableFields(clazz, globalConfig, mpjTableInfo, excludePropertyList);
|
||||
|
||||
/* 自动构建 resultMap */
|
||||
initResultMapIfNeed(tableInfo);
|
||||
|
||||
/* 添加缓存 */
|
||||
TABLE_INFO_CACHE.put(clazz, tableInfo);
|
||||
TABLE_INFO_CACHE.put(clazz, mpjTableInfo);
|
||||
|
||||
/* 缓存 lambda */
|
||||
LambdaUtils.installCache(tableInfo);
|
||||
return tableInfo;
|
||||
|
||||
/* 初始化映射关系 */
|
||||
initMapping(mpjTableInfo);
|
||||
return mpjTableInfo;
|
||||
}
|
||||
|
||||
|
||||
@ -179,10 +231,6 @@ public class MPJTableInfoHelper {
|
||||
|
||||
tableInfo.setTableName(targetTableName);
|
||||
|
||||
/* 开启了自定义 KEY 生成器 */
|
||||
// if (CollectionUtils.isNotEmpty(dbConfig.getKeyGenerators())) {
|
||||
// tableInfo.setKeySequence(clazz.getAnnotation(KeySequence.class));
|
||||
// }
|
||||
return excludeProperty;
|
||||
}
|
||||
|
||||
@ -216,12 +264,12 @@ public class MPJTableInfoHelper {
|
||||
*
|
||||
* @param clazz 实体类
|
||||
* @param globalConfig 全局配置
|
||||
* @param tableInfo 数据库表反射信息
|
||||
* @param mpjTableInfo 数据库表反射信息
|
||||
*/
|
||||
private static void initTableFields(Class<?> clazz, GlobalConfig globalConfig, TableInfo tableInfo, List<String> excludeProperty) {
|
||||
private static void initTableFields(Class<?> clazz, GlobalConfig globalConfig, MPJTableInfo mpjTableInfo, List<String> excludeProperty) {
|
||||
/* 数据库全局配置 */
|
||||
GlobalConfig.DbConfig dbConfig = globalConfig.getDbConfig();
|
||||
ReflectorFactory reflectorFactory = tableInfo.getConfiguration().getReflectorFactory();
|
||||
ReflectorFactory reflectorFactory = mpjTableInfo.getTableInfo().getConfiguration().getReflectorFactory();
|
||||
Reflector reflector = reflectorFactory.findForClass(clazz);
|
||||
List<Field> list = getAllFields(clazz);
|
||||
// 标记是否读取到主键
|
||||
@ -244,31 +292,33 @@ public class MPJTableInfoHelper {
|
||||
if (isReadPK) {
|
||||
throw ExceptionUtils.mpe("@TableId can't more than one in Class: \"%s\".", clazz.getName());
|
||||
} else {
|
||||
initTableIdWithAnnotation(dbConfig, tableInfo, field, tableId, reflector);
|
||||
initTableIdWithAnnotation(dbConfig, mpjTableInfo.getTableInfo(), field, tableId, reflector);
|
||||
isReadPK = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else if (!isReadPK) {
|
||||
isReadPK = initTableIdWithoutAnnotation(dbConfig, tableInfo, field, reflector);
|
||||
isReadPK = initTableIdWithoutAnnotation(dbConfig, mpjTableInfo.getTableInfo(), 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));
|
||||
fieldList.add(new TableFieldInfo(dbConfig, mpjTableInfo.getTableInfo(), field, tableField, reflector, existTableLogic));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 无 @TableField 注解的字段初始化 */
|
||||
fieldList.add(new TableFieldInfo(dbConfig, tableInfo, field, reflector, existTableLogic));
|
||||
fieldList.add(new TableFieldInfo(dbConfig, mpjTableInfo.getTableInfo(), field, reflector, existTableLogic));
|
||||
}
|
||||
|
||||
/* 字段列表 */
|
||||
tableInfo.setFieldList(fieldList);
|
||||
mpjTableInfo.getTableInfo().setFieldList(fieldList);
|
||||
|
||||
|
||||
/* 未发现主键注解,提示警告信息 */
|
||||
if (!isReadPK) {
|
||||
@ -300,6 +350,10 @@ public class MPJTableInfoHelper {
|
||||
return list.stream().anyMatch(field -> field.isAnnotationPresent(TableLogic.class));
|
||||
}
|
||||
|
||||
private static boolean isExistMapping(Class<?> clazz) {
|
||||
return ReflectionKit.getFieldList(ClassUtils.getUserClass(clazz)).stream().anyMatch(field -> field.isAnnotationPresent(MPJMapping.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 主键属性初始化
|
||||
@ -430,4 +484,27 @@ public class MPJTableInfoHelper {
|
||||
return (tableField == null || tableField.exist());
|
||||
}).collect(toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化映射相关
|
||||
*/
|
||||
public static void initMapping(MPJTableInfo mpjTableInfo) {
|
||||
// 是否存在 @MPJMapping 注解
|
||||
boolean existMapping = isExistMapping(mpjTableInfo.getTableInfo().getEntityType());
|
||||
mpjTableInfo.setHasMapping(existMapping);
|
||||
/* 关系映射初始化 */
|
||||
List<MPJTableFieldInfo> mpjFieldList = new ArrayList<>();
|
||||
List<Field> fields = ReflectionKit.getFieldList(ClassUtils.getUserClass(mpjTableInfo.getTableInfo().getEntityType()));
|
||||
for (Field field : fields) {
|
||||
if (existMapping) {
|
||||
MPJMapping mapping = field.getAnnotation(MPJMapping.class);
|
||||
if (mapping != null) {
|
||||
mpjFieldList.add(new MPJTableFieldInfo(mpjTableInfo.getTableInfo().getEntityType(), mapping, field));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 映射字段列表 */
|
||||
mpjTableInfo.setFieldList(mpjFieldList);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,88 @@
|
||||
package com.github.yulichang.annotation;
|
||||
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 关系映射注解
|
||||
*
|
||||
* @author yulichang
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
|
||||
public @interface MPJMapping {
|
||||
|
||||
/**
|
||||
* 关联的数据库实体类
|
||||
*/
|
||||
Class<?> tag();
|
||||
|
||||
/**
|
||||
* 当前类的属性数据结构 是否是Map 或 List<Map>
|
||||
* 如果是 true 关联查询会调用 getMap() / listMaps() 等Map相关方法进行匹配
|
||||
* 如果是 false 关联查询会调用 getOne() / getById() / list() 等实体类相关方法进行匹配
|
||||
*/
|
||||
boolean isMap() default false;
|
||||
|
||||
/**
|
||||
* 当前类的关联的字段名称 (是实体类字段名称而不是数据库字段名称)
|
||||
* 默认获取当前类上定义的主键 @TableId
|
||||
*/
|
||||
String thisField() default "";
|
||||
|
||||
/**
|
||||
* 关联类的字段名称 (是实体类字段名称而不是数据库字段名称)
|
||||
* 默认获取关联类上定义的主键 @TableId
|
||||
*/
|
||||
String joinField() default "";
|
||||
|
||||
/**
|
||||
* 针对查询结果map的时候使用
|
||||
* 默认为thisField对应的数据库列名
|
||||
* <p>
|
||||
* 如果此类是以map方式查询的
|
||||
* 并且查询出来的map的key不是thisField对应的数据库列名就需要设置
|
||||
*/
|
||||
String thisMapKey() default "";
|
||||
|
||||
/**
|
||||
* isMap为true时生效
|
||||
* 针对查询结果map的时候使用
|
||||
* 默认为joinField对应的数据库列名
|
||||
* <p>
|
||||
* 如果此类是以map方式查询的
|
||||
* 并且查询出来的map的key不是thisField对应的数据库列名就需要设置
|
||||
*/
|
||||
String joinMapKsy() default "";
|
||||
|
||||
/**
|
||||
* 映射表查询条件之 select
|
||||
* 等效于 Wrappers.<T>query().select(xxx);
|
||||
*/
|
||||
String select() default "";
|
||||
|
||||
/**
|
||||
* 映射表查询条件之 first
|
||||
* 等效于 Wrappers.<T>query().first(xxx);
|
||||
*/
|
||||
String first() default "";
|
||||
|
||||
/**
|
||||
* 映射表查询条件之 apply
|
||||
* 等效于 Wrappers.<T>query().apply(xxx);
|
||||
*/
|
||||
MPJMappingApply[] apply() default {};
|
||||
|
||||
/**
|
||||
* 映射表查询条件
|
||||
*/
|
||||
MPJMappingCondition[] condition() default {};
|
||||
|
||||
/**
|
||||
* 映射表查询条件之 last
|
||||
* 等效于 Wrappers.<T>query().last(xxx);
|
||||
*/
|
||||
String last() default "";
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.github.yulichang.annotation;
|
||||
|
||||
/**
|
||||
* 映射表条件
|
||||
* 用法参考 mybatis plus wrapper 的 .apply()方法
|
||||
*
|
||||
* @author yulichang
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public @interface MPJMappingApply {
|
||||
|
||||
/**
|
||||
* sql片段
|
||||
*/
|
||||
String value();
|
||||
|
||||
/**
|
||||
* .apply() 对应的可变参数
|
||||
*/
|
||||
String[] args();
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.github.yulichang.annotation;
|
||||
|
||||
import com.baomidou.mybatisplus.core.enums.SqlKeyword;
|
||||
|
||||
/**
|
||||
* 映射表条件
|
||||
*
|
||||
* @author yulichang
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public @interface MPJMappingCondition {
|
||||
|
||||
/**
|
||||
* 条件枚举
|
||||
* 目前只实现了 = != > >= < <=
|
||||
* 其他的暂未实现 TODO
|
||||
*
|
||||
* @see SqlKeyword
|
||||
*/
|
||||
SqlKeyword keyWord() default SqlKeyword.EQ;
|
||||
|
||||
/**
|
||||
* 数据库列名
|
||||
*/
|
||||
String column();
|
||||
|
||||
/**
|
||||
* 对应的值
|
||||
* 一般是一个值
|
||||
* 如果条件是 between 会取前两个
|
||||
* 如果条件是 in 就会取全部
|
||||
*/
|
||||
String[] value();
|
||||
}
|
307
src/main/java/com/github/yulichang/base/MPJBaseDeepService.java
Normal file
307
src/main/java/com/github/yulichang/base/MPJBaseDeepService.java
Normal file
@ -0,0 +1,307 @@
|
||||
package com.github.yulichang.base;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.enums.SqlKeyword;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.metadata.MPJTableFieldInfo;
|
||||
import com.baomidou.mybatisplus.core.metadata.MPJTableInfo;
|
||||
import com.baomidou.mybatisplus.core.metadata.MPJTableInfoHelper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.github.yulichang.annotation.MPJMapping;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 深度查询
|
||||
* <p>
|
||||
* 对配置了@MPJMapping注解的字段进行查询
|
||||
* 目前查询深度只支持2级(只解析当前实体类的MPJMapping注解,不会对查询结果再次解析注解)
|
||||
* 多级查询可能存在循环引用的问题,也可能会导致全量查询
|
||||
*
|
||||
* @author yulichang
|
||||
* @see MPJMapping
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public interface MPJBaseDeepService<T> extends IService<T> {
|
||||
|
||||
Class<T> currentModelClass();
|
||||
|
||||
/**
|
||||
* 根据 ID 深度查询
|
||||
*
|
||||
* @param id 主键ID列表
|
||||
*/
|
||||
default <R> T getByIdDeep(Serializable id) {
|
||||
return queryMapping(getById(id));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询(根据ID 批量查询)
|
||||
*
|
||||
* @param idList 主键ID列表
|
||||
*/
|
||||
default List<T> listByIdsDeep(Collection<? extends Serializable> idList) {
|
||||
return queryMapping(listByIds(idList));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询(根据 columnMap 条件)
|
||||
*
|
||||
* @param columnMap 表字段 map 对象
|
||||
*/
|
||||
default List<T> listByMapDeep(Map<String, Object> columnMap) {
|
||||
return queryMapping(listByMap(columnMap));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据 Wrapper,查询一条记录 <br/>
|
||||
* <p>结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")</p>
|
||||
*
|
||||
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
|
||||
*/
|
||||
default T getOneDeep(Wrapper<T> queryWrapper) {
|
||||
return queryMapping(getOne(queryWrapper));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据 Wrapper,查询一条记录
|
||||
*
|
||||
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
|
||||
* @param throwEx 有多个 result 是否抛出异常
|
||||
*/
|
||||
default T getOneDeep(Wrapper<T> queryWrapper, boolean throwEx) {
|
||||
return queryMapping(getOne(queryWrapper, throwEx));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 Wrapper,查询一条记录
|
||||
*
|
||||
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
|
||||
*/
|
||||
default Map<String, Object> getMapDeep(Wrapper<T> queryWrapper) {
|
||||
Map<String, Object> map = getMap(queryWrapper);
|
||||
if (CollectionUtils.isNotEmpty(map)) {
|
||||
MPJTableInfo tableInfo = MPJTableInfoHelper.getTableInfo(currentModelClass());
|
||||
if (tableInfo.isHasMapping()) {
|
||||
for (MPJTableFieldInfo fieldInfo : tableInfo.getFieldList()) {
|
||||
Object o = map.get(fieldInfo.getThisMapKey());
|
||||
if (o != null) {
|
||||
map.put(fieldInfo.getField().getName(), fieldInfo.getJoinMapper()
|
||||
.mappingWrapperConstructor(fieldInfo.isCollection(), fieldInfo.isFieldIsMap(), SqlKeyword.EQ,
|
||||
fieldInfo.getJoinColumn(), o, fieldInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*
|
||||
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
|
||||
*/
|
||||
default List<T> listDeep(Wrapper<T> queryWrapper) {
|
||||
return queryMapping(list(queryWrapper));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有
|
||||
*
|
||||
* @see Wrappers#emptyWrapper()
|
||||
*/
|
||||
default List<T> listDeep() {
|
||||
return queryMapping(list());
|
||||
}
|
||||
|
||||
/**
|
||||
* 翻页查询
|
||||
*
|
||||
* @param page 翻页对象
|
||||
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
|
||||
*/
|
||||
default <E extends IPage<T>> E pageDeep(E page, Wrapper<T> queryWrapper) {
|
||||
E e = page(page, queryWrapper);
|
||||
if (CollectionUtils.isNotEmpty(e.getRecords())) {
|
||||
queryMapping(e.getRecords());
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* 无条件翻页查询
|
||||
*
|
||||
* @param page 翻页对象
|
||||
* @see Wrappers#emptyWrapper()
|
||||
*/
|
||||
default <E extends IPage<T>> E pageDeep(E page) {
|
||||
E e = page(page);
|
||||
if (CollectionUtils.isNotEmpty(e.getRecords())) {
|
||||
queryMapping(e.getRecords());
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*
|
||||
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
|
||||
*/
|
||||
default List<Map<String, Object>> listMapsDeep(Wrapper<T> queryWrapper) {
|
||||
return queryMapMapping(listMaps(queryWrapper));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有列表
|
||||
*
|
||||
* @see Wrappers#emptyWrapper()
|
||||
*/
|
||||
default List<Map<String, Object>> listMapsDeep() {
|
||||
return queryMapMapping(listMaps());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 翻页查询
|
||||
*
|
||||
* @param page 翻页对象
|
||||
* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
|
||||
*/
|
||||
default <E extends IPage<Map<String, Object>>> E pageMapsDeep(E page, Wrapper<T> queryWrapper) {
|
||||
E e = pageMaps(page, queryWrapper);
|
||||
if (CollectionUtils.isNotEmpty(e.getRecords())) {
|
||||
queryMapMapping(e.getRecords());
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* 无条件翻页查询
|
||||
*
|
||||
* @param page 翻页对象
|
||||
* @see Wrappers#emptyWrapper()
|
||||
*/
|
||||
default <E extends IPage<Map<String, Object>>> E pageMapsDeep(E page) {
|
||||
E e = pageMaps(page);
|
||||
if (CollectionUtils.isNotEmpty(e.getRecords())) {
|
||||
queryMapMapping(e.getRecords());
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询映射关系
|
||||
* 对结果进行二次查询
|
||||
* 可以自行查询然后在通过此方法进行二次查询
|
||||
*
|
||||
* @param t 第一次查询结果
|
||||
*/
|
||||
default T queryMapping(T t) {
|
||||
if (t == null) {
|
||||
return null;
|
||||
}
|
||||
MPJTableInfo tableInfo = MPJTableInfoHelper.getTableInfo(currentModelClass());
|
||||
if (tableInfo.isHasMapping()) {
|
||||
for (MPJTableFieldInfo fieldInfo : tableInfo.getFieldList()) {
|
||||
Object get = fieldInfo.thisFieldGet(t);
|
||||
if (get != null) {
|
||||
fieldInfo.fieldSet(t, fieldInfo.getJoinMapper().mappingWrapperConstructor(fieldInfo.isCollection(),
|
||||
fieldInfo.isFieldIsMap(), SqlKeyword.EQ, fieldInfo.getJoinColumn(),
|
||||
get, fieldInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询映射关系
|
||||
* 对结果进行二次查询
|
||||
* 可以自行查询然后在通过此方法进行二次查询
|
||||
*
|
||||
* @param list 第一次查询结果
|
||||
*/
|
||||
default List<T> queryMapping(List<T> list) {
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return list;
|
||||
}
|
||||
MPJTableInfo tableInfo = MPJTableInfoHelper.getTableInfo(currentModelClass());
|
||||
if (tableInfo.isHasMapping()) {
|
||||
for (MPJTableFieldInfo fieldInfo : tableInfo.getFieldList()) {
|
||||
List<Object> itemList = list.stream().map(fieldInfo::thisFieldGet).collect(Collectors.toList());
|
||||
if (CollectionUtils.isNotEmpty(itemList)) {
|
||||
List<?> joinList = (List<?>) fieldInfo.getJoinMapper().mappingWrapperConstructor(true,
|
||||
fieldInfo.isFieldIsMap(), SqlKeyword.IN, fieldInfo.getJoinColumn(), itemList, fieldInfo);
|
||||
list.forEach(i -> {
|
||||
Stream<?> stream = joinList.stream().filter(j ->
|
||||
fieldInfo.joinFieldGet(j).equals(fieldInfo.thisFieldGet(i)));
|
||||
fieldInfo.fieldSet(i, fieldInfo.isCollection() ? stream.collect(Collectors.toList()) :
|
||||
stream.findFirst().orElse(null));
|
||||
});
|
||||
} else {
|
||||
list.forEach(i -> fieldInfo.fieldSet(i, new ArrayList<>()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询映射关系
|
||||
* 对结果进行二次查询
|
||||
* 可以自行查询然后在通过此方法进行二次查询
|
||||
*
|
||||
* @param list 第一次查询结果
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
default List<Map<String, Object>> queryMapMapping(List<Map<String, Object>> list) {
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return list;
|
||||
}
|
||||
MPJTableInfo tableInfo = MPJTableInfoHelper.getTableInfo(currentModelClass());
|
||||
if (tableInfo.isHasMapping()) {
|
||||
for (MPJTableFieldInfo fieldInfo : tableInfo.getFieldList()) {
|
||||
List<Object> itemList = list.stream().map(m -> m.get(fieldInfo.getThisMapKey())).collect(Collectors.toList());
|
||||
if (CollectionUtils.isNotEmpty(itemList)) {
|
||||
if (fieldInfo.isFieldIsMap()) {
|
||||
List<Map<String, Object>> joinList = (List<Map<String, Object>>) fieldInfo.getJoinMapper().mappingWrapperConstructor(true,
|
||||
fieldInfo.isFieldIsMap(), SqlKeyword.IN, fieldInfo.getJoinColumn(), itemList, fieldInfo);
|
||||
list.forEach(i -> {
|
||||
Stream<Map<String, Object>> stream = joinList.stream().filter(j -> j.containsKey(fieldInfo.getJoinMapKey())
|
||||
&& j.get(fieldInfo.getJoinMapKey()).equals(i.get(fieldInfo.getThisMapKey())));
|
||||
i.put(fieldInfo.getField().getName(), fieldInfo.isCollection() ? stream.collect(Collectors.toList()) :
|
||||
stream.findFirst().orElse(null));
|
||||
});
|
||||
} else {
|
||||
List<?> joinList = (List<?>) fieldInfo.getJoinMapper().mappingWrapperConstructor(true,
|
||||
fieldInfo.isFieldIsMap(), SqlKeyword.IN, fieldInfo.getJoinColumn(), itemList, fieldInfo);
|
||||
list.forEach(i -> {
|
||||
Stream<?> stream = joinList.stream().filter(j -> {
|
||||
Object o = fieldInfo.joinFieldGet(j);
|
||||
return o != null && o.equals(i.get(fieldInfo.getThisMapKey()));
|
||||
});
|
||||
i.put(fieldInfo.getField().getName(), fieldInfo.isCollection() ? stream.collect(Collectors.toList()) :
|
||||
stream.findFirst().orElse(null));
|
||||
});
|
||||
}
|
||||
} else {
|
||||
list.forEach(i -> i.put(fieldInfo.getField().getName(), new ArrayList<>()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package com.github.yulichang.base;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.github.yulichang.interfaces.MPJBaseJoin;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author yulichang
|
||||
* @see IService
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public interface MPJBaseJoinService<T> extends IService<T> {
|
||||
|
||||
/**
|
||||
* 根据 Wrapper 条件,查询总记录数
|
||||
*/
|
||||
default Integer selectJoinCount(MPJBaseJoin wrapper) {
|
||||
return ((MPJBaseMapper<T>) getBaseMapper()).selectJoinCount(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接查询返回一条记录
|
||||
*/
|
||||
default <DTO> DTO selectJoinOne(Class<DTO> clazz, MPJBaseJoin wrapper) {
|
||||
return ((MPJBaseMapper<T>) getBaseMapper()).selectJoinOne(clazz, wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接查询返回集合
|
||||
*/
|
||||
default <DTO> List<DTO> selectJoinList(Class<DTO> clazz, MPJBaseJoin wrapper) {
|
||||
return ((MPJBaseMapper<T>) getBaseMapper()).selectJoinList(clazz, wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接查询返回集合并分页
|
||||
*/
|
||||
default <DTO, P extends IPage<?>> IPage<DTO> selectJoinListPage(P page, Class<DTO> clazz, MPJBaseJoin wrapper) {
|
||||
return ((MPJBaseMapper<T>) getBaseMapper()).selectJoinPage(page, clazz, wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接查询返回Map
|
||||
*/
|
||||
default Map<String, Object> selectJoinMap(MPJBaseJoin wrapper) {
|
||||
return ((MPJBaseMapper<T>) getBaseMapper()).selectJoinMap(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接查询返回Map集合
|
||||
*/
|
||||
default List<Map<String, Object>> selectJoinMaps(MPJBaseJoin wrapper) {
|
||||
return ((MPJBaseMapper<T>) getBaseMapper()).selectJoinMaps(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接查询返回Map集合并分页
|
||||
*/
|
||||
default <P extends IPage<Map<String, Object>>> IPage<Map<String, Object>> selectJoinMapsPage(P page, MPJBaseJoin wrapper) {
|
||||
return ((MPJBaseMapper<T>) getBaseMapper()).selectJoinMapsPage(page, wrapper);
|
||||
}
|
||||
}
|
@ -1,7 +1,11 @@
|
||||
package com.github.yulichang.base;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.enums.SqlKeyword;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.metadata.MPJMappingWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.MPJTableFieldInfo;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.github.yulichang.interfaces.MPJBaseJoin;
|
||||
import com.github.yulichang.toolkit.Constant;
|
||||
@ -73,4 +77,47 @@ public interface MPJBaseMapper<T> extends BaseMapper<T> {
|
||||
*/
|
||||
<P extends IPage<?>> IPage<Map<String, Object>> selectJoinMapsPage(P page,
|
||||
@Param(Constants.WRAPPER) MPJBaseJoin wrapper);
|
||||
|
||||
|
||||
/**
|
||||
* 映射 wrapper 构造器
|
||||
* 仅对使用 @MPJMapping 时使用
|
||||
*/
|
||||
default Object mappingWrapperConstructor(boolean isCollection, boolean selectMap, SqlKeyword keyword,
|
||||
String column, Object val, MPJTableFieldInfo fieldInfo) {
|
||||
MPJMappingWrapper infoWrapper = fieldInfo.getWrapper();
|
||||
MappingQuery<T> wrapper = new MappingQuery<>();
|
||||
if (infoWrapper.isHasCondition()) {
|
||||
infoWrapper.getConditionList().forEach(c -> wrapper.addCondition(true, c.getColumn(),
|
||||
c.getKeyword(), c.getVal()));
|
||||
}
|
||||
wrapper.eq(SqlKeyword.EQ == keyword, column, val)
|
||||
.first(infoWrapper.isHasFirst(), infoWrapper.getFirst())
|
||||
.last(infoWrapper.isHasLast(), infoWrapper.getLast());
|
||||
if (SqlKeyword.IN == keyword) {
|
||||
wrapper.in(column, (List<?>) val);
|
||||
}
|
||||
if (infoWrapper.isHasSelect()) {
|
||||
wrapper.select(infoWrapper.getSelect());
|
||||
}
|
||||
if (infoWrapper.isHasApply()) {
|
||||
infoWrapper.getApplyList().forEach(a -> wrapper.apply(a.getSql(), (Object[]) a.getVal()));
|
||||
}
|
||||
|
||||
|
||||
if (selectMap) {
|
||||
return isCollection ? selectMaps(wrapper) : selectMaps(wrapper).stream().findFirst().orElse(null);
|
||||
}
|
||||
return isCollection ? selectList(wrapper) : selectOne(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 公开 addCondition 方法
|
||||
*/
|
||||
class MappingQuery<T> extends QueryWrapper<T> {
|
||||
@Override
|
||||
public QueryWrapper<T> addCondition(boolean condition, String column, SqlKeyword sqlKeyword, Object val) {
|
||||
return super.addCondition(condition, column, sqlKeyword, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,50 +1,12 @@
|
||||
package com.github.yulichang.base;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.github.yulichang.interfaces.MPJBaseJoin;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 基础service
|
||||
* 目前包含两个模块 连表查询 和 关系映射
|
||||
*
|
||||
* @author yulichang
|
||||
* @see IService
|
||||
* @see MPJBaseJoinService
|
||||
* @see MPJBaseDeepService
|
||||
*/
|
||||
public interface MPJBaseService<T> extends IService<T> {
|
||||
|
||||
/**
|
||||
* 根据 Wrapper 条件,查询总记录数
|
||||
*/
|
||||
Integer selectJoinCount(MPJBaseJoin wrapper);
|
||||
|
||||
/**
|
||||
* 连接查询返回一条记录
|
||||
*/
|
||||
<DTO> DTO selectJoinOne(Class<DTO> clazz, MPJBaseJoin wrapper);
|
||||
|
||||
/**
|
||||
* 连接查询返回集合
|
||||
*/
|
||||
<DTO> List<DTO> selectJoinList(Class<DTO> clazz, MPJBaseJoin wrapper);
|
||||
|
||||
/**
|
||||
* 连接查询返回集合并分页
|
||||
*/
|
||||
<DTO, P extends IPage<?>> IPage<DTO> selectJoinListPage(P page, Class<DTO> clazz, MPJBaseJoin wrapper);
|
||||
|
||||
/**
|
||||
* 连接查询返回Map
|
||||
*/
|
||||
Map<String, Object> selectJoinMap(MPJBaseJoin wrapper);
|
||||
|
||||
/**
|
||||
* 连接查询返回Map集合
|
||||
*/
|
||||
List<Map<String, Object>> selectJoinMaps(MPJBaseJoin wrapper);
|
||||
|
||||
/**
|
||||
* 连接查询返回Map集合并分页
|
||||
*/
|
||||
<P extends IPage<Map<String, Object>>> IPage<Map<String, Object>> selectJoinMapsPage(P page, MPJBaseJoin wrapper);
|
||||
public interface MPJBaseService<T> extends MPJBaseJoinService<T>, MPJBaseDeepService<T> {
|
||||
}
|
||||
|
@ -1,76 +1,16 @@
|
||||
package com.github.yulichang.base;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.github.yulichang.interfaces.MPJBaseJoin;
|
||||
import com.github.yulichang.toolkit.ReflectionKit;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author yulichang
|
||||
* @see ServiceImpl
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings("unused")
|
||||
public class MPJBaseServiceImpl<M extends MPJBaseMapper<T>, T> extends ServiceImpl<M, T> implements MPJBaseService<T> {
|
||||
|
||||
/**
|
||||
* mybatis plus 3.4.3 bug
|
||||
* <p>
|
||||
* https://gitee.com/baomidou/mybatis-plus/issues/I3SE8R
|
||||
* <p>
|
||||
* https://gitee.com/baomidou/mybatis-plus/commit/7210b461b23211e6b95ca6de2d846aa392bdc28c
|
||||
*/
|
||||
@Override
|
||||
protected Class<T> currentMapperClass() {
|
||||
return (Class<T>) ReflectionKit.getSuperClassGenericType(this.getClass(), ServiceImpl.class, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* mybatis plus 3.4.3 bug
|
||||
* <p>
|
||||
* https://gitee.com/baomidou/mybatis-plus/issues/I3SE8R
|
||||
* <p>
|
||||
* https://gitee.com/baomidou/mybatis-plus/commit/7210b461b23211e6b95ca6de2d846aa392bdc28c
|
||||
*/
|
||||
@Override
|
||||
protected Class<T> currentModelClass() {
|
||||
return (Class<T>) ReflectionKit.getSuperClassGenericType(this.getClass(), ServiceImpl.class, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer selectJoinCount(MPJBaseJoin wrapper) {
|
||||
return baseMapper.selectJoinCount(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <DTO> DTO selectJoinOne(Class<DTO> clazz, MPJBaseJoin wrapper) {
|
||||
return baseMapper.selectJoinOne(clazz, wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <DTO> List<DTO> selectJoinList(Class<DTO> clazz, MPJBaseJoin wrapper) {
|
||||
return baseMapper.selectJoinList(clazz, wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <DTO, P extends IPage<?>> IPage<DTO> selectJoinListPage(P page, Class<DTO> clazz, MPJBaseJoin wrapper) {
|
||||
return baseMapper.selectJoinPage(page, clazz, wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> selectJoinMap(MPJBaseJoin wrapper) {
|
||||
return baseMapper.selectJoinMap(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> selectJoinMaps(MPJBaseJoin wrapper) {
|
||||
return baseMapper.selectJoinMaps(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <P extends IPage<Map<String, Object>>> IPage<Map<String, Object>> selectJoinMapsPage(P page, MPJBaseJoin wrapper) {
|
||||
return baseMapper.selectJoinMapsPage(page, wrapper);
|
||||
public Class<T> currentModelClass() {
|
||||
return super.currentModelClass();
|
||||
}
|
||||
}
|
||||
|
@ -2,20 +2,12 @@ package com.github.yulichang.injector;
|
||||
|
||||
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
|
||||
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
|
||||
import com.baomidou.mybatisplus.core.mapper.Mapper;
|
||||
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.GlobalConfigUtils;
|
||||
import com.baomidou.mybatisplus.core.metadata.MPJTableInfoHelper;
|
||||
import com.github.yulichang.method.*;
|
||||
import com.github.yulichang.toolkit.ReflectionKit;
|
||||
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
||||
import org.apache.ibatis.logging.Log;
|
||||
import org.apache.ibatis.logging.LogFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* SQL 注入器
|
||||
@ -25,7 +17,6 @@ import java.util.Set;
|
||||
*/
|
||||
@ConditionalOnMissingBean(DefaultSqlInjector.class)
|
||||
public class MPJSqlInjector extends DefaultSqlInjector {
|
||||
private static final Log logger = LogFactory.getLog(MPJSqlInjector.class);
|
||||
|
||||
@Override
|
||||
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
|
||||
@ -40,30 +31,9 @@ public class MPJSqlInjector extends DefaultSqlInjector {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* mybatis plus 3.4.3 bug
|
||||
* <p>
|
||||
* https://gitee.com/baomidou/mybatis-plus/issues/I3SE8R
|
||||
* <p>
|
||||
* https://gitee.com/baomidou/mybatis-plus/commit/7210b461b23211e6b95ca6de2d846aa392bdc28c
|
||||
*/
|
||||
@Override
|
||||
public void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {
|
||||
Class<?> modelClass = ReflectionKit.getSuperClassGenericType(mapperClass, Mapper.class, 0);
|
||||
if (modelClass != null) {
|
||||
String className = mapperClass.toString();
|
||||
Set<String> mapperRegistryCache = GlobalConfigUtils.getMapperRegistryCache(builderAssistant.getConfiguration());
|
||||
if (!mapperRegistryCache.contains(className)) {
|
||||
List<AbstractMethod> methodList = this.getMethodList(mapperClass);
|
||||
if (CollectionUtils.isNotEmpty(methodList)) {
|
||||
TableInfo tableInfo = TableInfoHelper.initTableInfo(builderAssistant, modelClass);
|
||||
// 循环注入自定义方法
|
||||
methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));
|
||||
} else {
|
||||
logger.debug(mapperClass + ", No effective injection method was found.");
|
||||
}
|
||||
mapperRegistryCache.add(className);
|
||||
}
|
||||
}
|
||||
super.inspectInject(builderAssistant, mapperClass);
|
||||
MPJTableInfoHelper.initTableInfo(builderAssistant, extractModelClass(mapperClass), mapperClass);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.github.yulichang.interceptor;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.MPJTableInfo;
|
||||
import com.baomidou.mybatisplus.core.metadata.MPJTableInfoHelper;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||
@ -116,13 +117,13 @@ public class MPJInterceptor implements Interceptor {
|
||||
if (tableInfo != null && tableInfo.isAutoInitResultMap() && tableInfo.getEntityType() == resultType) {
|
||||
return ms.getConfiguration().getResultMap(tableInfo.getResultMap());
|
||||
}
|
||||
TableInfo infoDTO = MPJTableInfoHelper.getTableInfo(resultType);
|
||||
MPJTableInfo infoDTO = MPJTableInfoHelper.getTableInfo(resultType);
|
||||
if (infoDTO == null) {
|
||||
infoDTO = MPJTableInfoHelper.initTableInfo(ms.getConfiguration(),
|
||||
ms.getId().substring(0, ms.getId().lastIndexOf(".")), resultType);
|
||||
ms.getId().substring(0, ms.getId().lastIndexOf(".")), resultType, null);
|
||||
}
|
||||
if (infoDTO.isAutoInitResultMap()) {
|
||||
return ms.getConfiguration().getResultMap(infoDTO.getResultMap());
|
||||
if (infoDTO.getTableInfo().isAutoInitResultMap()) {
|
||||
return ms.getConfiguration().getResultMap(infoDTO.getTableInfo().getResultMap());
|
||||
}
|
||||
return new ResultMap.Builder(ms.getConfiguration(), ms.getId(), resultType, EMPTY_RESULT_MAPPING).build();
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
package com.github.yulichang.toolkit;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
|
||||
/**
|
||||
* spring容器工具类
|
||||
*
|
||||
* @author yulichang
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class SpringContentUtils implements ApplicationContextAware {
|
||||
|
||||
private static ApplicationContext context;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
context = applicationContext;
|
||||
}
|
||||
|
||||
public static ApplicationContext getApplicationContext() {
|
||||
return context;
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.github.yulichang.interceptor.MPJInterceptor,\
|
||||
com.github.yulichang.injector.MPJSqlInjector,\
|
||||
com.github.yulichang.config.InterceptorConfig
|
||||
com.github.yulichang.config.InterceptorConfig,\
|
||||
com.github.yulichang.toolkit.SpringContentUtils
|
||||
|
Loading…
x
Reference in New Issue
Block a user