一对一 一对多 关系映射注解实现

This commit is contained in:
bjdys 2021-08-12 09:28:32 +08:00
parent 1f267b1cc2
commit 866bccff28
17 changed files with 1074 additions and 166 deletions

View File

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.github.yulichang</groupId> <groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join</artifactId> <artifactId>mybatis-plus-join</artifactId>
<version>1.1.8</version> <version>1.1.9-SNAPSHOT</version>
<name>mybatis-plus-join</name> <name>mybatis-plus-join</name>
<description>An enhanced toolkit of Mybatis-Plus to simplify development.</description> <description>An enhanced toolkit of Mybatis-Plus to simplify development.</description>
<url>https://github.com/yulichang/mybatis-plus-join</url> <url>https://github.com/yulichang/mybatis-plus-join</url>
@ -32,6 +32,9 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jdkVersion>1.8</jdkVersion> <jdkVersion>1.8</jdkVersion>
<jdkVersion.test>1.8</jdkVersion.test> <jdkVersion.test>1.8</jdkVersion.test>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties> </properties>
<dependencies> <dependencies>

View File

@ -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;
}
}

View File

@ -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());
}
}
}

View File

@ -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;
}

View File

@ -3,6 +3,8 @@ package com.baomidou.mybatisplus.core.metadata;
import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.core.config.GlobalConfig; import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.toolkit.*; 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.Log;
import org.apache.ibatis.logging.LogFactory; import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.mapping.ResultFlag; 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 反射实体类 * @param clazz 反射实体类
* @return 数据库表反射信息 * @return 数据库表反射信息
*/ */
public static TableInfo getTableInfo(Class<?> clazz) { public static MPJTableInfo getTableInfo(Class<?> clazz) {
if (clazz == null || ReflectionKit.isPrimitiveOrWrapper(clazz) || clazz == String.class || clazz.isInterface()) { if (clazz == null || ReflectionKit.isPrimitiveOrWrapper(clazz) || clazz == String.class || clazz.isInterface()) {
return null; return null;
} }
return TABLE_INFO_CACHE.get(clazz); 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> * <p>
* 实体类反射获取表信息初始化 * 实体类反射获取表信息初始化
@ -69,13 +105,26 @@ public class MPJTableInfoHelper {
* @param clazz 反射实体类 * @param clazz 反射实体类
* @return 数据库表反射信息 * @return 数据库表反射信息
*/ */
public synchronized static TableInfo initTableInfo(Configuration configuration, String currentNamespace, Class<?> clazz) { public synchronized static MPJTableInfo initTableInfo(Configuration configuration, String currentNamespace, Class<?> clazz, Class<?> mapperClass) {
TableInfo info = TABLE_INFO_CACHE.get(clazz); MPJTableInfo info = TABLE_INFO_CACHE.get(clazz);
if (info != null) { if (info != null) {
return info; 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.setCurrentNamespace(currentNamespace);
tableInfo.setConfiguration(configuration); tableInfo.setConfiguration(configuration);
GlobalConfig globalConfig = GlobalConfigUtils.getGlobalConfig(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(); List<String> excludePropertyList = excludeProperty != null && excludeProperty.length > 0 ? Arrays.asList(excludeProperty) : Collections.emptyList();
/* 初始化字段相关 */ /* 初始化字段相关 */
initTableFields(clazz, globalConfig, tableInfo, excludePropertyList); initTableFields(clazz, globalConfig, mpjTableInfo, excludePropertyList);
/* 自动构建 resultMap */ /* 自动构建 resultMap */
initResultMapIfNeed(tableInfo); initResultMapIfNeed(tableInfo);
/* 添加缓存 */ /* 添加缓存 */
TABLE_INFO_CACHE.put(clazz, tableInfo); TABLE_INFO_CACHE.put(clazz, mpjTableInfo);
/* 缓存 lambda */ /* 缓存 lambda */
LambdaUtils.installCache(tableInfo); LambdaUtils.installCache(tableInfo);
return tableInfo;
/* 初始化映射关系 */
initMapping(mpjTableInfo);
return mpjTableInfo;
} }
@ -179,10 +231,6 @@ public class MPJTableInfoHelper {
tableInfo.setTableName(targetTableName); tableInfo.setTableName(targetTableName);
/* 开启了自定义 KEY 生成器 */
// if (CollectionUtils.isNotEmpty(dbConfig.getKeyGenerators())) {
// tableInfo.setKeySequence(clazz.getAnnotation(KeySequence.class));
// }
return excludeProperty; return excludeProperty;
} }
@ -216,12 +264,12 @@ public class MPJTableInfoHelper {
* *
* @param clazz 实体类 * @param clazz 实体类
* @param globalConfig 全局配置 * @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(); GlobalConfig.DbConfig dbConfig = globalConfig.getDbConfig();
ReflectorFactory reflectorFactory = tableInfo.getConfiguration().getReflectorFactory(); ReflectorFactory reflectorFactory = mpjTableInfo.getTableInfo().getConfiguration().getReflectorFactory();
Reflector reflector = reflectorFactory.findForClass(clazz); Reflector reflector = reflectorFactory.findForClass(clazz);
List<Field> list = getAllFields(clazz); List<Field> list = getAllFields(clazz);
// 标记是否读取到主键 // 标记是否读取到主键
@ -244,31 +292,33 @@ public class MPJTableInfoHelper {
if (isReadPK) { if (isReadPK) {
throw ExceptionUtils.mpe("@TableId can't more than one in Class: \"%s\".", clazz.getName()); throw ExceptionUtils.mpe("@TableId can't more than one in Class: \"%s\".", clazz.getName());
} else { } else {
initTableIdWithAnnotation(dbConfig, tableInfo, field, tableId, reflector); initTableIdWithAnnotation(dbConfig, mpjTableInfo.getTableInfo(), field, tableId, reflector);
isReadPK = true; isReadPK = true;
continue; continue;
} }
} }
} else if (!isReadPK) { } else if (!isReadPK) {
isReadPK = initTableIdWithoutAnnotation(dbConfig, tableInfo, field, reflector); isReadPK = initTableIdWithoutAnnotation(dbConfig, mpjTableInfo.getTableInfo(), field, reflector);
if (isReadPK) { if (isReadPK) {
continue; continue;
} }
} }
final TableField tableField = field.getAnnotation(TableField.class); final TableField tableField = field.getAnnotation(TableField.class);
/* 有 @TableField 注解的字段初始化 */ /* 有 @TableField 注解的字段初始化 */
if (tableField != null) { 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; continue;
} }
/* 无 @TableField 注解的字段初始化 */ /* 无 @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) { if (!isReadPK) {
@ -300,6 +350,10 @@ public class MPJTableInfoHelper {
return list.stream().anyMatch(field -> field.isAnnotationPresent(TableLogic.class)); 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> * <p>
* 主键属性初始化 * 主键属性初始化
@ -430,4 +484,27 @@ public class MPJTableInfoHelper {
return (tableField == null || tableField.exist()); return (tableField == null || tableField.exist());
}).collect(toList()); }).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);
}
} }

View File

@ -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 "";
}

View File

@ -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();
}

View File

@ -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();
}

View 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;
}
}

View File

@ -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);
}
}

View File

@ -1,7 +1,11 @@
package com.github.yulichang.base; 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.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage; 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.baomidou.mybatisplus.core.toolkit.Constants;
import com.github.yulichang.interfaces.MPJBaseJoin; import com.github.yulichang.interfaces.MPJBaseJoin;
import com.github.yulichang.toolkit.Constant; 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, <P extends IPage<?>> IPage<Map<String, Object>> selectJoinMapsPage(P page,
@Param(Constants.WRAPPER) MPJBaseJoin wrapper); @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);
}
}
} }

View File

@ -1,50 +1,12 @@
package com.github.yulichang.base; 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 * @author yulichang
* @see IService * @see MPJBaseJoinService
* @see MPJBaseDeepService
*/ */
public interface MPJBaseService<T> extends IService<T> { public interface MPJBaseService<T> extends MPJBaseJoinService<T>, MPJBaseDeepService<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);
} }

View File

@ -1,76 +1,16 @@
package com.github.yulichang.base; package com.github.yulichang.base;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 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 * @author yulichang
* @see ServiceImpl * @see ServiceImpl
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unused")
public class MPJBaseServiceImpl<M extends MPJBaseMapper<T>, T> extends ServiceImpl<M, T> implements MPJBaseService<T> { 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 @Override
protected Class<T> currentMapperClass() { public Class<T> currentModelClass() {
return (Class<T>) ReflectionKit.getSuperClassGenericType(this.getClass(), ServiceImpl.class, 0); return super.currentModelClass();
}
/**
* 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);
} }
} }

View File

@ -2,20 +2,12 @@ package com.github.yulichang.injector;
import com.baomidou.mybatisplus.core.injector.AbstractMethod; import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector; import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.mapper.Mapper; import com.baomidou.mybatisplus.core.metadata.MPJTableInfoHelper;
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.github.yulichang.method.*; import com.github.yulichang.method.*;
import com.github.yulichang.toolkit.ReflectionKit;
import org.apache.ibatis.builder.MapperBuilderAssistant; 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 org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* SQL 注入器 * SQL 注入器
@ -25,7 +17,6 @@ import java.util.Set;
*/ */
@ConditionalOnMissingBean(DefaultSqlInjector.class) @ConditionalOnMissingBean(DefaultSqlInjector.class)
public class MPJSqlInjector extends DefaultSqlInjector { public class MPJSqlInjector extends DefaultSqlInjector {
private static final Log logger = LogFactory.getLog(MPJSqlInjector.class);
@Override @Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) { public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
@ -40,30 +31,9 @@ public class MPJSqlInjector extends DefaultSqlInjector {
return list; 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 @Override
public void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) { public void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {
Class<?> modelClass = ReflectionKit.getSuperClassGenericType(mapperClass, Mapper.class, 0); super.inspectInject(builderAssistant, mapperClass);
if (modelClass != null) { MPJTableInfoHelper.initTableInfo(builderAssistant, extractModelClass(mapperClass), mapperClass);
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);
}
}
} }
} }

View File

@ -1,5 +1,6 @@
package com.github.yulichang.interceptor; 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.MPJTableInfoHelper;
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;
@ -116,13 +117,13 @@ public class MPJInterceptor implements Interceptor {
if (tableInfo != null && tableInfo.isAutoInitResultMap() && tableInfo.getEntityType() == resultType) { if (tableInfo != null && tableInfo.isAutoInitResultMap() && tableInfo.getEntityType() == resultType) {
return ms.getConfiguration().getResultMap(tableInfo.getResultMap()); return ms.getConfiguration().getResultMap(tableInfo.getResultMap());
} }
TableInfo infoDTO = MPJTableInfoHelper.getTableInfo(resultType); MPJTableInfo infoDTO = MPJTableInfoHelper.getTableInfo(resultType);
if (infoDTO == null) { if (infoDTO == null) {
infoDTO = MPJTableInfoHelper.initTableInfo(ms.getConfiguration(), 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()) { if (infoDTO.getTableInfo().isAutoInitResultMap()) {
return ms.getConfiguration().getResultMap(infoDTO.getResultMap()); return ms.getConfiguration().getResultMap(infoDTO.getTableInfo().getResultMap());
} }
return new ResultMap.Builder(ms.getConfiguration(), ms.getId(), resultType, EMPTY_RESULT_MAPPING).build(); return new ResultMap.Builder(ms.getConfiguration(), ms.getId(), resultType, EMPTY_RESULT_MAPPING).build();
} }

View File

@ -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;
}
}

View File

@ -1,4 +1,5 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.github.yulichang.interceptor.MPJInterceptor,\ com.github.yulichang.interceptor.MPJInterceptor,\
com.github.yulichang.injector.MPJSqlInjector,\ com.github.yulichang.injector.MPJSqlInjector,\
com.github.yulichang.config.InterceptorConfig com.github.yulichang.config.InterceptorConfig,\
com.github.yulichang.toolkit.SpringContentUtils