同步 mybatis plus 3.5.2 代码

This commit is contained in:
yulichang 2022-11-16 18:27:45 +08:00
parent efcccd2da0
commit 9464dea9f2
59 changed files with 1441 additions and 271 deletions

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--suppress ALL -->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
@ -8,6 +9,7 @@
<artifactId>mybatis-plus-join-root</artifactId>
<version>2.0.0</version>
</parent>
<version>2.0.0</version>
<artifactId>mybatis-plus-join-annotation</artifactId>
<name>mybatis-plus-join-annotation</name>

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--suppress ALL -->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
@ -8,6 +9,7 @@
<artifactId>mybatis-plus-join-root</artifactId>
<version>2.0.0</version>
</parent>
<version>2.0.0</version>
<artifactId>mybatis-plus-join-boot-starter</artifactId>
<name>mybatis-plus-join-boot-starter</name>
@ -45,7 +47,7 @@
<dependency>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-core</artifactId>
<version>${mybaits-plus-join.version}</version>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@ -9,6 +9,7 @@
<artifactId>mybatis-plus-join-root</artifactId>
<version>2.0.0</version>
</parent>
<version>2.0.0</version>
<artifactId>mybatis-plus-join-core</artifactId>
<name>mybatis-plus-join-core</name>
@ -46,7 +47,7 @@
<dependency>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-annotation</artifactId>
<version>${mybaits-plus-join.version}</version>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
@ -60,6 +61,12 @@
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<scope>provided</scope>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>

View File

@ -7,7 +7,6 @@ import com.baomidou.mybatisplus.core.toolkit.*;
import com.github.yulichang.interfaces.MPJBaseJoin;
import com.github.yulichang.method.MPJResultType;
import com.github.yulichang.toolkit.Constant;
import com.github.yulichang.toolkit.ReflectionKit;
import com.github.yulichang.toolkit.support.SelectColumn;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.github.yulichang.wrapper.resultmap.MybatisLabel;
@ -150,7 +149,6 @@ public class MPJInterceptor implements Interceptor {
TableInfo tableInfo = TableInfoHelper.getTableInfo(resultType);
String id = ms.getId() + StringPool.DOT + Constants.MYBATIS_PLUS + StringPool.UNDERSCORE + resultType.getName();
if (!(obj instanceof MPJLambdaWrapper) || Map.class.isAssignableFrom(resultType) ||
ReflectionKit.isPrimitiveOrWrapper(resultType) ||
Collection.class.isAssignableFrom(resultType)) {
result.add(getDefaultResultMap(tableInfo, ms, resultType, id));
return result;
@ -209,56 +207,86 @@ public class MPJInterceptor implements Interceptor {
//移除result中不存在的标签
resultMappings.removeIf(i -> !fieldMap.containsKey(i.getProperty()));
if (wrapper.isResultMap()) {
buildResult(ms, wrapper.getResultMapMybatisLabel(), columnSet, resultMappings, columnList);
for (Object o : wrapper.getResultMapMybatisLabel()) {
MybatisLabel<?, ?> label = (MybatisLabel<?, ?>) o;
resultMappings.add(buildResult(ms, label, columnSet, columnList));
}
}
result.add(new ResultMap.Builder(ms.getConfiguration(), id, resultType, resultMappings).build());
return result;
}
private void buildResult(MappedStatement ms, List<MybatisLabel<?, ?>> mybatisLabel, Set<String> columnSet,
List<ResultMapping> parentMappings, List<SelectColumn> columnList) {
for (MybatisLabel<?, ?> mpjColl : mybatisLabel) {
List<Result> list = mpjColl.getResultList();
if (CollectionUtils.isEmpty(list)) {
continue;
//fix 重上往下会有resultMap覆盖问题,应该从根节点开始,id向上传递
/**
* @return 返回节点id
*/
private ResultMapping buildResult(MappedStatement ms, MybatisLabel<?, ?> mybatisLabel, Set<String> columnSet,
List<SelectColumn> columnList) {
List<Result> resultList = mybatisLabel.getResultList();
if (CollectionUtils.isEmpty(resultList)) {
return null;
}
List<ResultMapping> childMapping = new ArrayList<>(resultList.size());
for (Result r : resultList) {
String columnName = r.getColumn();
//列名去重
columnName = getColumn(columnSet, columnName);
columnList.add(SelectColumn.of(mybatisLabel.getEntityClass(), r.getColumn(), null,
Objects.equals(columnName, r.getColumn()) ? null : columnName, null, null, true, null));
ResultMapping.Builder builder = new ResultMapping.Builder(ms.getConfiguration(), r.getProperty(),
StringUtils.getTargetColumn(columnName), r.getJavaType());
if (r.isId()) {//主键标记为id标签
builder.flags(Collections.singletonList(ResultFlag.ID));
}
List<ResultMapping> childMapping = new ArrayList<>(list.size());
for (Result r : list) {
String columnName = r.getColumn();
//列名去重
columnName = getColumn(columnSet, columnName);
columnList.add(SelectColumn.of(mpjColl.getEntityClass(), r.getColumn(), null,
Objects.equals(columnName, r.getColumn()) ? null : columnName, null, null, true, null));
ResultMapping.Builder builder = new ResultMapping.Builder(ms.getConfiguration(), r.getProperty(),
StringUtils.getTargetColumn(columnName), r.getJavaType());
if (r.isId()) {//主键标记为id标签
builder.flags(Collections.singletonList(ResultFlag.ID));
}
//TypeHandle
TableFieldInfo info = r.getTableFieldInfo();
if (info != null && info.getTypeHandler() != null && info.getTypeHandler() != UnknownTypeHandler.class) {
builder.typeHandler(getTypeHandler(ms, info));
}
childMapping.add(builder.build());
//TypeHandle
TableFieldInfo info = r.getTableFieldInfo();
if (info != null && info.getTypeHandler() != null && info.getTypeHandler() != UnknownTypeHandler.class) {
builder.typeHandler(getTypeHandler(ms, info));
}
//嵌套处理
if (CollectionUtils.isNotEmpty(mpjColl.getMybatisLabels())) {
this.buildResult(ms, mpjColl.getMybatisLabels(), columnSet, childMapping, columnList);
}
String childId = "MPJ_" + mpjColl.getEntityClass().getName() + StringPool.UNDERSCORE + mpjColl.getOfType().getName() +
childMapping.add(builder.build());
}
String childId;
if (CollectionUtils.isEmpty(mybatisLabel.getMybatisLabels())) {
childId = "MPJ_" + mybatisLabel.getEntityClass().getName() + StringPool.UNDERSCORE + mybatisLabel.getOfType().getName() +
StringPool.UNDERSCORE + childMapping.stream().map(i -> "(" + (CollectionUtils.isEmpty(i.getFlags()) ?
ResultFlag.CONSTRUCTOR : i.getFlags().get(0)) + "-" + i.getProperty() + "-" + i.getColumn() + ")")
.collect(Collectors.joining(StringPool.DASH));
parentMappings.add(new ResultMapping.Builder(ms.getConfiguration(), mpjColl.getProperty())
.javaType(mpjColl.getJavaType())
.nestedResultMapId(childId)
.build());
//双检
if (!ms.getConfiguration().getResultMapNames().contains(childId)) {
ResultMap build = new ResultMap.Builder(ms.getConfiguration(), childId, mpjColl.getOfType(), childMapping).build();
MPJInterceptor.addResultMap(ms, childId, build);
} else {
//递归调用
StringBuilder sb = new StringBuilder("MPJ_[");
for (MybatisLabel<?, ?> o : mybatisLabel.getMybatisLabels()) {
if (Objects.isNull(o)) {
continue;
}
ResultMapping result = buildResult(ms, o, columnSet, columnList);
if (Objects.isNull(result)) {
continue;
}
childMapping.add(result);
sb.append(result.getNestedResultMapId());
sb.append("]");
}
sb.append("_MPJ_")
.append(mybatisLabel.getEntityClass().getName())
.append(StringPool.UNDERSCORE)
.append(mybatisLabel.getOfType().getName())
.append(StringPool.UNDERSCORE);
childId = sb + childMapping.stream().map(i -> "(" + (CollectionUtils.isEmpty(i.getFlags()) ?
ResultFlag.CONSTRUCTOR : i.getFlags().get(0)) + "-" + i.getProperty() + "-" + i.getColumn() + ")")
.collect(Collectors.joining(StringPool.DASH));
}
//双检
if (!ms.getConfiguration().getResultMapNames().contains(childId)) {
ResultMap build = new ResultMap.Builder(ms.getConfiguration(), childId, mybatisLabel.getOfType(), childMapping).build();
MPJInterceptor.addResultMap(ms, childId, build);
}
return new ResultMapping.Builder(ms.getConfiguration(), mybatisLabel.getProperty())
.javaType(mybatisLabel.getJavaType())
.nestedResultMapId(childId)
.build();
}
/**

View File

@ -0,0 +1,267 @@
/*
* Copyright (c) 2011-2022, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.yulichang.toolkit;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import org.apache.ibatis.io.Resources;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
/**
* <p>
* ClassUtils
* </p>
*
* @author Caratacus
* @author HCL
* @since 2017/07/08
*/
@SuppressWarnings("All")
public final class ClassUtils {
private static ClassLoader systemClassLoader;
static {
try {
systemClassLoader = ClassLoader.getSystemClassLoader();
} catch (SecurityException ignored) {
// AccessControlException on Google App Engine
}
}
/**
* 代理 class 的名称
*/
private static final List<String> PROXY_CLASS_NAMES = Arrays.asList("net.sf.cglib.proxy.Factory"
// cglib
, "org.springframework.cglib.proxy.Factory"
, "javassist.util.proxy.ProxyObject"
// javassist
, "org.apache.ibatis.javassist.util.proxy.ProxyObject");
private ClassUtils() {
}
/**
* 判断传入的类型是否是布尔类型
*
* @param type 类型
* @return 如果是原生布尔或者包装类型布尔均返回 true
*/
public static boolean isBoolean(Class<?> type) {
return type == boolean.class || Boolean.class == type;
}
/**
* 判断是否为代理对象
*
* @param clazz 传入 class 对象
* @return 如果对象class是代理 class返回 true
*/
public static boolean isProxy(Class<?> clazz) {
if (clazz != null) {
for (Class<?> cls : clazz.getInterfaces()) {
if (PROXY_CLASS_NAMES.contains(cls.getName())) {
return true;
}
}
}
return false;
}
/**
* <p>
* 获取当前对象的 class
* </p>
*
* @param clazz 传入
* @return 如果是代理的class返回父 class否则返回自身
*/
public static Class<?> getUserClass(Class<?> clazz) {
Assert.notNull(clazz, "Class must not be null");
return isProxy(clazz) ? clazz.getSuperclass() : clazz;
}
/**
* <p>
* 获取当前对象的class
* </p>
*
* @param object 对象
* @return 返回对象的 user class
*/
public static Class<?> getUserClass(Object object) {
Assert.notNull(object, "Instance must not be null");
return getUserClass(object.getClass());
}
/**
* <p>
* 根据指定的 class 实例化一个对象根据构造参数来实例化
* </p>
* <p>
* java9 及其之后的版本 Class.newInstance() 方法已被废弃
* </p>
*
* @param clazz 需要实例化的对象
* @param <T> 类型由输入类型决定
* @return 返回新的实例
*/
public static <T> T newInstance(Class<T> clazz) {
try {
Constructor<T> constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
return constructor.newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
NoSuchMethodException e) {
throw ExceptionUtils.mpe("实例化对象时出现错误,请尝试给 %s 添加无参的构造方法", e, clazz.getName());
}
}
/**
* 实例化对象.
*
* @param clazzName 类名
* @param <T> 类型
* @return 实例
* @since 3.3.2
*/
@SuppressWarnings("unchecked")
public static <T> T newInstance(String clazzName) {
return (T) newInstance(toClassConfident(clazzName));
}
/**
* <p>
* 请仅在确定类存在的情况下调用该方法
* </p>
*
* @param name 类名称
* @return 返回转换后的 Class
*/
public static Class<?> toClassConfident(String name) {
return toClassConfident(name, null);
}
/**
* @param name
* @param classLoader
* @return
* @since 3.4.3
*/
public static Class<?> toClassConfident(String name, ClassLoader classLoader) {
try {
return loadClass(name, getClassLoaders(classLoader));
} catch (ClassNotFoundException e) {
throw ExceptionUtils.mpe("找不到指定的class请仅在明确确定会有 class 的时候,调用该方法", e);
}
}
private static Class<?> loadClass(String className, ClassLoader[] classLoaders) throws ClassNotFoundException {
for (ClassLoader classLoader : classLoaders) {
if (classLoader != null) {
try {
return Class.forName(className, true, classLoader);
} catch (ClassNotFoundException e) {
// ignore
}
}
}
throw new ClassNotFoundException("Cannot find class: " + className);
}
/**
* Determine the name of the package of the given class,
* e.g. "java.lang" for the {@code java.lang.String} class.
*
* @param clazz the class
* @return the package name, or the empty String if the class
* is defined in the default package
*/
public static String getPackageName(Class<?> clazz) {
Assert.notNull(clazz, "Class must not be null");
return getPackageName(clazz.getName());
}
/**
* Determine the name of the package of the given fully-qualified class name,
* e.g. "java.lang" for the {@code java.lang.String} class name.
*
* @param fqClassName the fully-qualified class name
* @return the package name, or the empty String if the class
* is defined in the default package
*/
public static String getPackageName(String fqClassName) {
Assert.notNull(fqClassName, "Class name must not be null");
int lastDotIndex = fqClassName.lastIndexOf(StringPool.DOT);
return (lastDotIndex != -1 ? fqClassName.substring(0, lastDotIndex) : StringPool.EMPTY);
}
/**
* Return the default ClassLoader to use: typically the thread context
* ClassLoader, if available; the ClassLoader that loaded the ClassUtils
* class will be used as fallback.
* <p>Call this method if you intend to use the thread context ClassLoader
* in a scenario where you clearly prefer a non-null ClassLoader reference:
* for example, for class path resource loading (but not necessarily for
* {@code Class.forName}, which accepts a {@code null} ClassLoader
* reference as well).
*
* @return the default ClassLoader (only {@code null} if even the system
* ClassLoader isn't accessible)
* @see Thread#getContextClassLoader()
* @see ClassLoader#getSystemClassLoader()
* @since 3.3.2
*/
@Deprecated
public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
} catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back...
}
if (cl == null) {
// No thread context class loader -> use class loader of this class.
cl = ClassUtils.class.getClassLoader();
if (cl == null) {
// getClassLoader() returning null indicates the bootstrap ClassLoader
try {
cl = ClassLoader.getSystemClassLoader();
} catch (Throwable ex) {
// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
}
}
}
return cl;
}
private static ClassLoader[] getClassLoaders(ClassLoader classLoader) {
return new ClassLoader[]{
classLoader,
Resources.getDefaultClassLoader(),
Thread.currentThread().getContextClassLoader(),
ClassUtils.class.getClassLoader(),
systemClassLoader};
}
}

View File

@ -13,7 +13,7 @@ import java.util.function.Predicate;
* 保证 MPJInterceptor 再最后一个第一个执行
*
* @author yulichang
* @since 1.2.5
* @since 1.3.0
*/
public class InterceptorList<E extends Interceptor> extends ArrayList<E> {

View File

@ -5,13 +5,13 @@ 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.support.SFunction;
import com.github.yulichang.toolkit.support.ColumnCache;
import com.github.yulichang.toolkit.support.SerializedLambda;
import com.github.yulichang.toolkit.support.*;
import org.apache.ibatis.reflection.property.PropertyNamer;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import static java.util.Locale.ENGLISH;
@ -19,50 +19,54 @@ import static java.util.Locale.ENGLISH;
/**
* copy {@link com.baomidou.mybatisplus.core.toolkit.LambdaUtils}
*/
@SuppressWarnings("unused")
public final class LambdaUtils {
/* ******* 自定义方法 *********** */
public static <T> String getName(SFunction<T, ?> fn) {
return PropertyNamer.methodToProperty(resolve(fn).getImplMethodName());
LambdaMeta extract = extract(fn);
String name = PropertyNamer.methodToProperty(extract.getImplMethodName());
if (Character.isUpperCase(name.charAt(0))) {
Map<String, Field> map = MPJReflectionKit.getFieldMap(extract.getInstantiatedClass());
if (map.containsKey(name)) {
return name;
} else {
return map.keySet().stream().filter(i -> i.equalsIgnoreCase(name)).findFirst().orElse(null);
}
}
return name;
}
@SuppressWarnings("unchecked")
public static <T> Class<T> getEntityClass(SFunction<T, ?> fn) {
return (Class<T>) resolve(fn).getInstantiatedType();
return (Class<T>) extract(fn).getInstantiatedClass();
}
/* ******* 自定义方法 结束 以下代码均为拷贝 *********** */
/**
* 字段映射
*/
private static final Map<String, Map<String, ColumnCache>> COLUMN_CACHE_MAP = new ConcurrentHashMap<>();
/**
* SerializedLambda 反序列化缓存
*/
private static final Map<String, WeakReference<SerializedLambda>> FUNC_CACHE = new ConcurrentHashMap<>();
/**
* 解析 lambda 表达式, 该方法只是调用了 {@link SerializedLambda#resolve(SFunction)} 中的方法在此基础上加了缓存
* 该缓存可能会在任意不定的时间被清除
*
* @param func 需要解析的 lambda 对象
* @param <T> 类型被调用的 Function 对象的目标类型
* @return 返回解析后的结果
* @see SerializedLambda#resolve(SFunction)
*/
public static <T> SerializedLambda resolve(SFunction<T, ?> func) {
Class<?> clazz = func.getClass();
String name = clazz.getName();
return Optional.ofNullable(FUNC_CACHE.get(name))
.map(WeakReference::get)
.orElseGet(() -> {
SerializedLambda lambda = SerializedLambda.resolve(func);
FUNC_CACHE.put(name, new WeakReference<>(lambda));
return lambda;
});
public static <T> LambdaMeta extract(SFunction<T, ?> func) {
// 1. IDEA 调试模式下 lambda 表达式是一个代理
if (func instanceof Proxy) {
return new IdeaProxyLambdaMeta((Proxy) func);
}
// 2. 反射读取
try {
Method method = func.getClass().getDeclaredMethod("writeReplace");
return new ReflectLambdaMeta((java.lang.invoke.SerializedLambda) ReflectionKit.setAccessible(method).invoke(func));
} catch (Throwable e) {
// 3. 反射失败使用序列化的方式读取
return new ShadowLambdaMeta(SerializedLambda.extract(func));
}
}
/**
@ -79,6 +83,14 @@ public final class LambdaUtils {
return key.toUpperCase(ENGLISH);
}
/**
* 将传入的表信息加入缓存
*
* @param tableInfo 表信息
*/
public static void installCache(TableInfo tableInfo) {
COLUMN_CACHE_MAP.put(tableInfo.getEntityType().getName(), createColumnCacheMap(tableInfo));
}
/**
* 缓存实体字段 MAP 信息
@ -115,5 +127,4 @@ public final class LambdaUtils {
return info == null ? null : createColumnCacheMap(info);
});
}
}

View File

@ -0,0 +1,61 @@
package com.github.yulichang.toolkit;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 反射工具类
*
* @author yulichang
* @since 2.0.0
*/
@SuppressWarnings("unused")
public final class MPJReflectionKit {
private static final Map<Class<?>, Map<String, Field>> CLASS_FIELD_CACHE = new ConcurrentHashMap<>();
/**
* Collection字段的泛型
*/
public static Class<?> getGenericType(Field field) {
Type type = field.getGenericType();
//没有写泛型
if (!(type instanceof ParameterizedType)) {
return Object.class;
}
ParameterizedType pt = (ParameterizedType) type;
Type[] actualTypeArguments = pt.getActualTypeArguments();
Type argument = actualTypeArguments[0];
//通配符泛型 ? , ? extends XXX , ? super XXX
if (argument instanceof WildcardType) {
//获取上界
Type[] types = ((WildcardType) argument).getUpperBounds();
return (Class<?>) types[0];
}
return (Class<?>) argument;
}
/**
* 获取该类的所有属性列表
*
* @param clazz 反射类
*/
public static Map<String, Field> getFieldMap(Class<?> clazz) {
if (clazz == null) {
return new HashMap<>();
}
Map<String, Field> fieldMap = CLASS_FIELD_CACHE.get(clazz);
if (fieldMap != null) {
return fieldMap;
}
Map<String, Field> map = ReflectionKit.getFieldMap(clazz);
CLASS_FIELD_CACHE.put(clazz, map);
return map;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011-2021, baomidou (jobob@qq.com).
* Copyright (c) 2011-2022, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -15,15 +15,16 @@
*/
package com.github.yulichang.toolkit;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import com.baomidou.mybatisplus.core.toolkit.*;
import com.baomidou.mybatisplus.core.toolkit.reflect.GenericTypeUtils;
import java.lang.reflect.*;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -37,14 +38,14 @@ import static java.util.stream.Collectors.toMap;
* @author hcl
* @since 2016-09-22
*/
@SuppressWarnings("unused")
@SuppressWarnings("All")
public final class ReflectionKit {
private static final Log logger = LogFactory.getLog(ReflectionKit.class);
/**
* class field cache
*/
private static final Map<Class<?>, List<Field>> CLASS_FIELD_CACHE = new ConcurrentHashMap<>();
@Deprecated
private static final Map<Class<?>, Class<?>> PRIMITIVE_WRAPPER_TYPE_MAP = new IdentityHashMap<>(8);
private static final Map<Class<?>, Class<?>> PRIMITIVE_TYPE_TO_WRAPPER_MAP = new IdentityHashMap<>(8);
@ -83,26 +84,20 @@ public final class ReflectionKit {
}
}
/**
* Collection字段的泛型
* <p>
* 反射对象获取泛型
* </p>
*
* @param clazz 对象
* @param genericIfc 所属泛型父类
* @param index 泛型所在位置
* @return Class
*/
public static Class<?> getGenericType(Field field) {
Type type = field.getGenericType();
//没有写泛型
if (!(type instanceof ParameterizedType)) {
return Object.class;
}
ParameterizedType pt = (ParameterizedType) type;
Type[] actualTypeArguments = pt.getActualTypeArguments();
Type argument = actualTypeArguments[0];
//通配符泛型 ? , ? extends XXX , ? super XXX
if (argument instanceof WildcardType) {
//获取上界
Type[] types = ((WildcardType) argument).getUpperBounds();
return (Class<?>) types[0];
}
return (Class<?>) argument;
public static Class<?> getSuperClassGenericType(final Class<?> clazz, final Class<?> genericIfc, final int index) {
//update by noear @2021-09-03
Class<?>[] typeArguments = GenericTypeUtils.resolveTypeArguments(ClassUtils.getUserClass(clazz), genericIfc);
return null == typeArguments ? null : typeArguments[index];
}
/**
@ -114,7 +109,7 @@ public final class ReflectionKit {
*/
public static Map<String, Field> getFieldMap(Class<?> clazz) {
List<Field> fieldList = getFieldList(clazz);
return CollectionUtils.isNotEmpty(fieldList) ? fieldList.stream().collect(Collectors.toMap(Field::getName, field -> field)) : Collections.emptyMap();
return CollectionUtils.isNotEmpty(fieldList) ? fieldList.stream().collect(Collectors.toMap(Field::getName, Function.identity())) : Collections.emptyMap();
}
/**
@ -145,11 +140,11 @@ public final class ReflectionKit {
* 中间表实体重写父类属性 ` private transient Date createTime; `
*/
return fieldMap.values().stream()
/* 过滤静态属性 */
.filter(f -> !Modifier.isStatic(f.getModifiers()))
/* 过滤 transient关键字修饰的属性 */
.filter(f -> !Modifier.isTransient(f.getModifiers()))
.collect(Collectors.toList());
/* 过滤静态属性 */
.filter(f -> !Modifier.isStatic(f.getModifiers()))
/* 过滤 transient关键字修饰的属性 */
.filter(f -> !Modifier.isTransient(f.getModifiers()))
.collect(Collectors.toList());
});
}
@ -164,12 +159,12 @@ public final class ReflectionKit {
public static Map<String, Field> excludeOverrideSuperField(Field[] fields, List<Field> superFieldList) {
// 子类属性
Map<String, Field> fieldMap = Stream.of(fields).collect(toMap(Field::getName, identity(),
(u, v) -> {
throw new IllegalStateException(String.format("Duplicate key %s", u));
},
LinkedHashMap::new));
(u, v) -> {
throw new IllegalStateException(String.format("Duplicate key %s", u));
},
LinkedHashMap::new));
superFieldList.stream().filter(field -> !fieldMap.containsKey(field.getName()))
.forEach(f -> fieldMap.put(f.getName(), f));
.forEach(f -> fieldMap.put(f.getName(), f));
return fieldMap;
}
@ -179,6 +174,7 @@ public final class ReflectionKit {
* @param clazz class
* @return 是否基本类型或基本包装类型
*/
@Deprecated
public static boolean isPrimitiveOrWrapper(Class<?> clazz) {
Assert.notNull(clazz, "Class must not be null");
return (clazz.isPrimitive() || PRIMITIVE_WRAPPER_TYPE_MAP.containsKey(clazz));
@ -187,4 +183,16 @@ public final class ReflectionKit {
public static Class<?> resolvePrimitiveIfNecessary(Class<?> clazz) {
return (clazz.isPrimitive() && clazz != void.class ? PRIMITIVE_TYPE_TO_WRAPPER_MAP.get(clazz) : clazz);
}
/**
* 设置可访问对象的可访问权限为 true
*
* @param object 可访问的对象
* @param <T> 类型
* @return 返回设置后的对象
*/
public static <T extends AccessibleObject> T setAccessible(T object) {
return AccessController.doPrivileged(new SetAccessibleAction<>(object));
}
}

View File

@ -8,7 +8,7 @@ import lombok.Getter;
*
* @author yulichang
* @see com.baomidou.mybatisplus.core.toolkit.support.ColumnCache
* @since 1.2.5
* @since 1.3.0
*/
public class ColumnCache extends com.baomidou.mybatisplus.core.toolkit.support.ColumnCache {

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2011-2022, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.yulichang.toolkit.support;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* IDEA Evaluate 中执行的 Lambda 表达式元数据需要使用该类处理元数据
* <p>
* Create by hcl at 2021/5/17
*/
public class IdeaProxyLambdaMeta implements LambdaMeta {
private static final Field FIELD_MEMBER_NAME;
private static final Field FIELD_MEMBER_NAME_CLAZZ;
private static final Field FIELD_MEMBER_NAME_NAME;
static {
try {
Class<?> classDirectMethodHandle = Class.forName("java.lang.invoke.DirectMethodHandle");
FIELD_MEMBER_NAME = ReflectionKit.setAccessible(classDirectMethodHandle.getDeclaredField("member"));
Class<?> classMemberName = Class.forName("java.lang.invoke.MemberName");
FIELD_MEMBER_NAME_CLAZZ = ReflectionKit.setAccessible(classMemberName.getDeclaredField("clazz"));
FIELD_MEMBER_NAME_NAME = ReflectionKit.setAccessible(classMemberName.getDeclaredField("name"));
} catch (ClassNotFoundException | NoSuchFieldException e) {
throw new MybatisPlusException(e);
}
}
private final Class<?> clazz;
private final String name;
public IdeaProxyLambdaMeta(Proxy func) {
InvocationHandler handler = Proxy.getInvocationHandler(func);
try {
Object dmh = ReflectionKit.setAccessible(handler.getClass().getDeclaredField("val$target")).get(handler);
Object member = FIELD_MEMBER_NAME.get(dmh);
clazz = (Class<?>) FIELD_MEMBER_NAME_CLAZZ.get(member);
name = (String) FIELD_MEMBER_NAME_NAME.get(member);
} catch (IllegalAccessException | NoSuchFieldException e) {
throw new MybatisPlusException(e);
}
}
@Override
public String getImplMethodName() {
return name;
}
@Override
public Class<?> getInstantiatedClass() {
return clazz;
}
@Override
public String toString() {
return clazz.getSimpleName() + "::" + name;
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2011-2022, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.yulichang.toolkit.support;
/**
* Lambda 信息
* <p>
* Created by hcl at 2021/5/14
*/
public interface LambdaMeta {
/**
* 获取 lambda 表达式实现方法的名称
*
* @return lambda 表达式对应的实现方法名称
*/
String getImplMethodName();
/**
* 实例化该方法的类
*
* @return 返回对应的类名称
*/
Class<?> getInstantiatedClass();
}

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2011-2022, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.yulichang.toolkit.support;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.github.yulichang.toolkit.ClassUtils;
import com.github.yulichang.toolkit.ReflectionKit;
import lombok.extern.slf4j.Slf4j;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
/**
* Created by hcl at 2021/5/14
*/
@Slf4j
public class ReflectLambdaMeta implements LambdaMeta {
private static final Field FIELD_CAPTURING_CLASS;
static {
Field fieldCapturingClass;
try {
Class<SerializedLambda> aClass = SerializedLambda.class;
fieldCapturingClass = ReflectionKit.setAccessible(aClass.getDeclaredField("capturingClass"));
} catch (Throwable e) {
// 解决高版本 jdk 的问题 gitee: https://gitee.com/baomidou/mybatis-plus/issues/I4A7I5
log.warn(e.getMessage());
fieldCapturingClass = null;
}
FIELD_CAPTURING_CLASS = fieldCapturingClass;
}
private final SerializedLambda lambda;
public ReflectLambdaMeta(SerializedLambda lambda) {
this.lambda = lambda;
}
@Override
public String getImplMethodName() {
return lambda.getImplMethodName();
}
@Override
public Class<?> getInstantiatedClass() {
String instantiatedMethodType = lambda.getInstantiatedMethodType();
String instantiatedType = instantiatedMethodType.substring(2, instantiatedMethodType.indexOf(StringPool.SEMICOLON)).replace(StringPool.SLASH, StringPool.DOT);
return ClassUtils.toClassConfident(instantiatedType, getCapturingClassClassLoader());
}
private ClassLoader getCapturingClassClassLoader() {
// 如果反射失败使用默认的 classloader
if (FIELD_CAPTURING_CLASS == null) {
return null;
}
try {
return ((Class<?>) FIELD_CAPTURING_CLASS.get(lambda)).getClassLoader();
} catch (IllegalAccessException e) {
throw new MybatisPlusException(e);
}
}
}

View File

@ -9,7 +9,7 @@ import lombok.Getter;
* MPJLambdaWrapper 查询字段
*
* @author yulichang
* @since 1.2.5
* @since 1.3.0
*/
@Getter
public class SelectColumn {

View File

@ -1,18 +1,31 @@
/*
* Copyright (c) 2011-2022, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.yulichang.toolkit.support;
import com.baomidou.mybatisplus.core.toolkit.ClassUtils;
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
import com.baomidou.mybatisplus.core.toolkit.SerializationUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import java.io.*;
/**
* copy mp before 3.4.3
* 当前类是 {@link java.lang.invoke.SerializedLambda } 的一个镜像
* <p>
* Create by hcl at 2020/7/17
*/
@SuppressWarnings("unused")
@SuppressWarnings("ALL")
public class SerializedLambda implements Serializable {
private static final long serialVersionUID = 8025925345765570181L;
private Class<?> capturingClass;
@ -26,98 +39,35 @@ public class SerializedLambda implements Serializable {
private String instantiatedMethodType;
private Object[] capturedArgs;
/**
* 通过反序列化转换 lambda 表达式该方法只能序列化 lambda 表达式不能序列化接口实现或者正常非 lambda 写法的对象
*
* @param lambda lambda对象
* @return 返回解析后的 SerializedLambda
*/
public static SerializedLambda resolve(SFunction<?, ?> lambda) {
if (!lambda.getClass().isSynthetic()) {
throw ExceptionUtils.mpe("该方法仅能传入 lambda 表达式产生的合成类");
}
try (ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(SerializationUtils.serialize(lambda))) {
@Override
protected Class<?> resolveClass(ObjectStreamClass objectStreamClass) throws IOException, ClassNotFoundException {
Class<?> clazz;
try {
clazz = ClassUtils.toClassConfident(objectStreamClass.getName());
} catch (Exception ex) {
clazz = super.resolveClass(objectStreamClass);
public static SerializedLambda extract(Serializable serializable) {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(serializable);
oos.flush();
try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())) {
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
Class<?> clazz = super.resolveClass(desc);
return clazz == java.lang.invoke.SerializedLambda.class ? SerializedLambda.class : clazz;
}
return clazz == java.lang.invoke.SerializedLambda.class ? SerializedLambda.class : clazz;
}) {
return (SerializedLambda) ois.readObject();
}
}) {
return (SerializedLambda) objIn.readObject();
} catch (ClassNotFoundException | IOException e) {
throw ExceptionUtils.mpe("This is impossible to happen", e);
} catch (IOException | ClassNotFoundException e) {
throw new MybatisPlusException(e);
}
}
/**
* 获取接口 class
*
* @return 返回 class 名称
*/
public String getFunctionalInterfaceClassName() {
return normalizedName(functionalInterfaceClass);
public String getInstantiatedMethodType() {
return instantiatedMethodType;
}
/**
* 获取实现的 class
*
* @return 实现类
*/
public Class<?> getImplClass() {
return ClassUtils.toClassConfident(getImplClassName());
public Class<?> getCapturingClass() {
return capturingClass;
}
/**
* 获取 class 的名称
*
* @return 类名
*/
public String getImplClassName() {
return normalizedName(implClass);
}
/**
* 获取实现者的方法名称
*
* @return 方法名称
*/
public String getImplMethodName() {
return implMethodName;
}
/**
* 正常化类名称将类名称中的 / 替换为 .
*
* @param name 名称
* @return 正常的类名
*/
private String normalizedName(String name) {
return name.replace('/', '.');
}
/**
* @return 获取实例化方法的类型
*/
public Class<?> getInstantiatedType() {
String instantiatedTypeName = normalizedName(instantiatedMethodType.substring(2, instantiatedMethodType.indexOf(';')));
return ClassUtils.toClassConfident(instantiatedTypeName);
}
/**
* @return 字符串形式
*/
@Override
public String toString() {
String interfaceName = getFunctionalInterfaceClassName();
String implName = getImplClassName();
return String.format("%s -> %s::%s",
interfaceName.substring(interfaceName.lastIndexOf('.') + 1),
implName.substring(implName.lastIndexOf('.') + 1),
implMethodName);
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2011-2022, baomidou (jobob@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.yulichang.toolkit.support;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.github.yulichang.toolkit.ClassUtils;
/**
* 基于 {@link com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda} 创建的元信息
* <p>
* Create by hcl at 2021/7/7
*/
public class ShadowLambdaMeta implements LambdaMeta {
private final SerializedLambda lambda;
public ShadowLambdaMeta(SerializedLambda lambda) {
this.lambda = lambda;
}
@Override
public String getImplMethodName() {
return lambda.getImplMethodName();
}
@Override
public Class<?> getInstantiatedClass() {
String instantiatedMethodType = lambda.getInstantiatedMethodType();
String instantiatedType = instantiatedMethodType.substring(2, instantiatedMethodType.indexOf(StringPool.SEMICOLON)).replace(StringPool.SLASH, StringPool.DOT);
return ClassUtils.toClassConfident(instantiatedType, lambda.getCapturingClass().getClassLoader());
}
}

View File

@ -10,11 +10,7 @@ import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.github.yulichang.exception.MPJException;
import com.github.yulichang.toolkit.Constant;
import com.github.yulichang.toolkit.LambdaUtils;
import com.github.yulichang.toolkit.MPJWrappers;
import com.github.yulichang.toolkit.ReflectionKit;
import com.github.yulichang.toolkit.*;
import com.github.yulichang.toolkit.support.ColumnCache;
import com.github.yulichang.toolkit.support.SelectColumn;
import com.github.yulichang.wrapper.enums.BaseFuncEnum;
@ -165,7 +161,7 @@ public class MPJLambdaWrapper<T> extends MPJAbstractLambdaWrapper<T, MPJLambdaWr
* <pre/>
* 会自动将 UserAddressDO类中相同属性的字段 以mybatis<collection>的方式映射到UserDTO.addressListDTO属性中
*
* @since 1.2.5
* @since 1.3.0
*
* @param child 连表数据库实体类
* @param dtoField 包装类对应的属性
@ -177,19 +173,16 @@ public class MPJLambdaWrapper<T> extends MPJAbstractLambdaWrapper<T, MPJLambdaWr
public <S, C, Z, F extends java.util.Collection<?>> MPJLambdaWrapper<T> selectCollection(Class<C> child, SFunction<S, F> dtoField) {
String dtoFieldName = LambdaUtils.getName(dtoField);
Class<S> dtoClass = LambdaUtils.getEntityClass(dtoField);
Map<String, Field> fieldMap = ReflectionKit.getFieldMap(dtoClass);
Map<String, Field> fieldMap = MPJReflectionKit.getFieldMap(dtoClass);
Field field = fieldMap.get(dtoFieldName);
this.resultMap = true;
Class<?> genericType = ReflectionKit.getGenericType(field);
Class<?> genericType = MPJReflectionKit.getGenericType(field);
MybatisLabel.Builder<C, Z> builder;
if (genericType == null || genericType.isAssignableFrom(child)) {
//找不到集合泛型 List List<?> List<Object> 直接查询数据库实体
builder = new MybatisLabel.Builder<>(dtoFieldName, child, field.getType());
} else {
Class<Z> ofType = (Class<Z>) genericType;
if (ReflectionKit.isPrimitiveOrWrapper(ofType)) {
throw new MPJException("collection 不支持基本数据类型");
}
builder = new MybatisLabel.Builder<>(dtoFieldName, child, field.getType(), ofType, true);
}
this.resultMapMybatisLabel.add(builder.build());
@ -214,7 +207,7 @@ public class MPJLambdaWrapper<T> extends MPJAbstractLambdaWrapper<T, MPJLambdaWr
*
* 会自动将 UserAddressDO类中指定的字段 以mybatis<collection>的方式映射到UserDTO.addressListDTO属性中
*
* @since 1.2.5
* @since 1.3.0
*
* @param child 连表数据库实体类
* @param dtoField 包装类对应的属性
@ -228,10 +221,10 @@ public class MPJLambdaWrapper<T> extends MPJAbstractLambdaWrapper<T, MPJLambdaWr
selectCollection(Class<C> child, SFunction<S, F> dtoField, MFunc<MybatisLabel.Builder<C, Z>> collection) {
String dtoFieldName = LambdaUtils.getName(dtoField);
Class<S> dtoClass = LambdaUtils.getEntityClass(dtoField);
Field field = ReflectionKit.getFieldMap(dtoClass).get(dtoFieldName);
Field field = MPJReflectionKit.getFieldMap(dtoClass).get(dtoFieldName);
this.resultMap = true;
//获取集合泛型
Class<?> genericType = ReflectionKit.getGenericType(field);
Class<?> genericType = MPJReflectionKit.getGenericType(field);
Class<Z> ofType = (Class<Z>) genericType;
MybatisLabel.Builder<C, Z> builder = new MybatisLabel.Builder<>(dtoFieldName, child, field.getType(), ofType, false);
this.resultMapMybatisLabel.add(collection.apply(builder).build());
@ -241,17 +234,14 @@ public class MPJLambdaWrapper<T> extends MPJAbstractLambdaWrapper<T, MPJLambdaWr
/**
* 对一查询 用法参考 selectCollection
*
* @since 1.2.5
* @since 1.3.0
*/
public <S, C, F> MPJLambdaWrapper<T> selectAssociation(Class<C> child, SFunction<S, F> dtoField) {
String dtoFieldName = LambdaUtils.getName(dtoField);
Class<S> dtoClass = LambdaUtils.getEntityClass(dtoField);
Map<String, Field> fieldMap = ReflectionKit.getFieldMap(dtoClass);
Map<String, Field> fieldMap = MPJReflectionKit.getFieldMap(dtoClass);
Field field = fieldMap.get(dtoFieldName);
Assert.isFalse(Collection.class.isAssignableFrom(field.getType()), "association 不支持集合类");
if (ReflectionKit.isPrimitiveOrWrapper(field.getType())) {
throw new MPJException("association 不支持基本数据类型");
}
this.resultMap = true;
MybatisLabel.Builder<C, F> builder;
builder = new MybatisLabel.Builder<>(dtoFieldName, child, field.getType(), (Class<F>) field.getType(), true);
@ -262,18 +252,15 @@ public class MPJLambdaWrapper<T> extends MPJAbstractLambdaWrapper<T, MPJLambdaWr
/**
* 对一查询 用法参考 selectCollection
*
* @since 1.2.5
* @since 1.3.0
*/
public <S, C, F> MPJLambdaWrapper<T> selectAssociation(Class<C> child, SFunction<S, F> dtoField,
MFunc<MybatisLabel.Builder<C, F>> collection) {
String dtoFieldName = LambdaUtils.getName(dtoField);
Class<S> dtoClass = LambdaUtils.getEntityClass(dtoField);
Field field = ReflectionKit.getFieldMap(dtoClass).get(dtoFieldName);
Field field = MPJReflectionKit.getFieldMap(dtoClass).get(dtoFieldName);
this.resultMap = true;
Assert.isFalse(Collection.class.isAssignableFrom(field.getType()), "association 不支持集合类");
if (ReflectionKit.isPrimitiveOrWrapper(field.getType())) {
throw new MPJException("association 不支持基本数据类型");
}
MybatisLabel.Builder<C, F> builder = new MybatisLabel.Builder<>(dtoFieldName, child, field.getType(), (Class<F>) child, false);
this.resultMapMybatisLabel.add(collection.apply(builder).build());
return typedThis;

View File

@ -6,9 +6,8 @@ import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.github.yulichang.exception.MPJException;
import com.github.yulichang.toolkit.LambdaUtils;
import com.github.yulichang.toolkit.ReflectionKit;
import com.github.yulichang.toolkit.MPJReflectionKit;
import lombok.Getter;
import java.lang.reflect.Field;
@ -23,7 +22,7 @@ import java.util.stream.Collectors;
* collection 标签 目前先支持这几个属性 后续在扩展
*
* @author yulichang
* @since 1.2.5
* @since 1.3.0
*/
@Getter
public class MybatisLabel<E, T> {
@ -120,18 +119,15 @@ public class MybatisLabel<E, T> {
public <A, R, B extends Collection<R>> Builder<E, T> collection(Class<A> entityClass, SFunction<T, B> func) {
String dtoFieldName = LambdaUtils.getName(func);
Class<T> dtoClass = LambdaUtils.getEntityClass(func);
Map<String, Field> fieldMap = ReflectionKit.getFieldMap(dtoClass);
Map<String, Field> fieldMap = MPJReflectionKit.getFieldMap(dtoClass);
Field field = fieldMap.get(dtoFieldName);
Class<?> genericType = ReflectionKit.getGenericType(field);
Class<?> genericType = MPJReflectionKit.getGenericType(field);
MybatisLabel.Builder<A, R> builder;
if (genericType == null || genericType.isAssignableFrom(entityClass)) {
//找不到集合泛型 List List<?> List<Object> 直接查询数据库实体
builder = new Builder<>(dtoFieldName, entityClass, field.getType());
} else {
Class<R> ofType = (Class<R>) genericType;
if (ReflectionKit.isPrimitiveOrWrapper(ofType)) {
throw new MPJException("collection 不支持基本数据类型");
}
builder = new Builder<>(dtoFieldName, entityClass, field.getType(), ofType, true);
}
mybatisLabel.mybatisLabels.add(builder.build());
@ -144,9 +140,9 @@ public class MybatisLabel<E, T> {
public <A, R, B extends Collection<R>> Builder<E, T> collection(Class<A> entityClass, SFunction<T, B> func, MFunc<Builder<A, R>> mFunc) {
String dtoFieldName = LambdaUtils.getName(func);
Class<T> dtoClass = LambdaUtils.getEntityClass(func);
Field field = ReflectionKit.getFieldMap(dtoClass).get(dtoFieldName);
Field field = MPJReflectionKit.getFieldMap(dtoClass).get(dtoFieldName);
//获取集合泛型
Class<?> genericType = ReflectionKit.getGenericType(field);
Class<?> genericType = MPJReflectionKit.getGenericType(field);
Class<R> ofType = (Class<R>) genericType;
MybatisLabel.Builder<A, R> builder = new MybatisLabel.Builder<>(dtoFieldName, entityClass, field.getType(), ofType, false);
mybatisLabel.mybatisLabels.add(mFunc.apply(builder).build());
@ -158,13 +154,10 @@ public class MybatisLabel<E, T> {
*/
public <A, B> Builder<E, T> association(Class<A> child, SFunction<T, B> dtoField) {
Class<T> dtoClass = LambdaUtils.getEntityClass(dtoField);
Map<String, Field> fieldMap = ReflectionKit.getFieldMap(dtoClass);
Map<String, Field> fieldMap = MPJReflectionKit.getFieldMap(dtoClass);
String dtoFieldName = LambdaUtils.getName(dtoField);
Field field = fieldMap.get(dtoFieldName);
Assert.isFalse(Collection.class.isAssignableFrom(field.getType()), "association 不支持集合类");
if (ReflectionKit.isPrimitiveOrWrapper(field.getType())) {
throw new MPJException("association 不支持基本数据类型");
}
MybatisLabel.Builder<A, B> builder;
builder = new MybatisLabel.Builder<>(dtoFieldName, child, field.getType(), (Class<B>) field.getType(), true);
mybatisLabel.mybatisLabels.add(builder.build());
@ -178,11 +171,8 @@ public class MybatisLabel<E, T> {
MFunc<MybatisLabel.Builder<A, B>> collection) {
String dtoFieldName = LambdaUtils.getName(dtoField);
Class<T> dtoClass = LambdaUtils.getEntityClass(dtoField);
Field field = ReflectionKit.getFieldMap(dtoClass).get(dtoFieldName);
Field field = MPJReflectionKit.getFieldMap(dtoClass).get(dtoFieldName);
Assert.isFalse(Collection.class.isAssignableFrom(field.getType()), "association 不支持集合类");
if (ReflectionKit.isPrimitiveOrWrapper(field.getType())) {
throw new MPJException("association 不支持基本数据类型");
}
MybatisLabel.Builder<A, B> builder = new MybatisLabel.Builder<>(dtoFieldName, child, field.getType(), (Class<B>) child, false);
mybatisLabel.mybatisLabels.add(collection.apply(builder).build());
return this;
@ -198,7 +188,7 @@ public class MybatisLabel<E, T> {
private void autoBuild(boolean auto, Class<E> entityClass, Class<T> tagClass) {
TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
Map<String, Field> tagMap = ReflectionKit.getFieldMap(tagClass);
Map<String, Field> tagMap = MPJReflectionKit.getFieldMap(tagClass);
if (auto && !tagMap.isEmpty()) {
Function<TableFieldInfo, Result> build = field -> {
Result result = new Result();

View File

@ -17,7 +17,7 @@ import org.apache.ibatis.type.TypeHandler;
* result 标签
*
* @author yulichang
* @since 1.2.5
* @since 1.3.0
*/
@Getter
@Setter(AccessLevel.PACKAGE)

View File

@ -9,6 +9,7 @@
<artifactId>mybatis-plus-join-root</artifactId>
<version>2.0.0</version>
</parent>
<version>2.0.0</version>
<artifactId>mybatis-plus-join-test</artifactId>
<name>mybatis-plus-join-test</name>
@ -70,24 +71,35 @@
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
<!-- <version>${mybatis-plus.version}</version>-->
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-boot-starter</artifactId>
<version>${mybaits-plus-join.version}</version>
<version>2.0.0</version>
</dependency>
<!-- PageHelper 兼容性测试 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.5</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.github.pagehelper</groupId>-->
<!-- <artifactId>pagehelper-spring-boot-starter</artifactId>-->
<!-- <version>1.4.5</version>-->
<!-- </dependency>-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.4</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>jsqlparser</groupId>-->
<!-- <artifactId>jsqlparser</artifactId>-->
<!-- <version>0.7.0</version>-->
<!-- </dependency>-->
</dependencies>
</project>

View File

@ -0,0 +1,9 @@
package com.github.yulichang.test.collection;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
}

View File

@ -0,0 +1,47 @@
package com.github.yulichang.test.collection;
import com.github.yulichang.test.collection.dto.TableADTO;
import com.github.yulichang.test.collection.dto.TableBDTO;
import com.github.yulichang.test.collection.dto.TableCDTO;
import com.github.yulichang.test.collection.dto.TableDDTO;
import com.github.yulichang.test.collection.entity.*;
import com.github.yulichang.test.collection.mapper.TableAMapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.util.List;
/**
* 连表测试类
* <p>
* 支持mybatis-plus 查询枚举字段
* 支持mybatis-plus typeHandle功能
* <p>
* 移除了mybatis-plus 逻辑删除支持逻辑删除需要在连表查询时自己添加对应的条件
*/
@SuppressWarnings("unused")
@SpringBootTest(properties = "spring.profiles.active=collection")
class CollectionTest {
@Resource
private TableAMapper tableAMapper;
@Test
void testJoinCollection() {
//4层嵌套 a对多b b对多c c对多d d对多e
MPJLambdaWrapper<TableA> wrapper = new MPJLambdaWrapper<TableA>()
.selectAll(TableA.class)
.selectCollection(TableB.class, TableADTO::getBList, b -> b
.collection(TableC.class, TableBDTO::getCcList, c -> c
.collection(TableD.class, TableCDTO::getDList, d -> d
.collection(TableE.class, TableDDTO::getEList))))
.leftJoin(TableB.class, TableB::getAid, TableA::getId)
.leftJoin(TableC.class, TableC::getBid, TableB::getId)
.leftJoin(TableD.class, TableD::getCid, TableC::getId)
.leftJoin(TableE.class, TableE::getDid, TableD::getId);
List<TableADTO> dtos = tableAMapper.selectJoinList(TableADTO.class, wrapper);
System.out.println(dtos);
}
}

View File

@ -0,0 +1,24 @@
package com.github.yulichang.test.collection.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* mybatis-plus配置
*/
@Configuration
public class MybatisPlusConfig {
/**
* 分页插件
*/
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor page = new PaginationInnerInterceptor();
interceptor.addInnerInterceptor(page);
return interceptor;
}
}

View File

@ -0,0 +1,17 @@
package com.github.yulichang.test.collection.dto;
import lombok.Data;
import lombok.ToString;
import java.util.List;
@Data
@ToString
public class TableADTO {
private Integer id;
private String name;
private List<TableBDTO> bList;
}

View File

@ -0,0 +1,19 @@
package com.github.yulichang.test.collection.dto;
import lombok.Data;
import lombok.ToString;
import java.util.List;
@Data
@ToString
public class TableBDTO {
private Integer id;
private Integer aid;
private String name;
private List<TableCDTO> ccList;
}

View File

@ -0,0 +1,19 @@
package com.github.yulichang.test.collection.dto;
import lombok.Data;
import lombok.ToString;
import java.util.List;
@Data
@ToString
public class TableCDTO {
private Integer id;
private Integer bid;
private String name;
private List<TableDDTO> dList;
}

View File

@ -0,0 +1,19 @@
package com.github.yulichang.test.collection.dto;
import lombok.Data;
import lombok.ToString;
import java.util.List;
@Data
@ToString
public class TableDDTO {
private Integer id;
private Integer cid;
private String name;
private List<TableEDTO> eList;
}

View File

@ -0,0 +1,15 @@
package com.github.yulichang.test.collection.dto;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class TableEDTO {
private Integer id;
private Integer did;
private String name;
}

View File

@ -0,0 +1,15 @@
package com.github.yulichang.test.collection.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("table_a")
public class TableA {
@TableId
private Integer id;
private String name;
}

View File

@ -0,0 +1,17 @@
package com.github.yulichang.test.collection.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("table_b")
public class TableB {
@TableId
private Integer id;
private Integer aid;
private String name;
}

View File

@ -0,0 +1,17 @@
package com.github.yulichang.test.collection.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("table_c")
public class TableC {
@TableId
private Integer id;
private Integer bid;
private String name;
}

View File

@ -0,0 +1,17 @@
package com.github.yulichang.test.collection.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("table_d")
public class TableD {
@TableId
private Integer id;
private Integer cid;
private String name;
}

View File

@ -0,0 +1,17 @@
package com.github.yulichang.test.collection.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("table_e")
public class TableE {
@TableId
private Integer id;
private Integer did;
private String name;
}

View File

@ -0,0 +1,24 @@
package com.github.yulichang.test.collection.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.Getter;
import lombok.ToString;
@Getter
@ToString
public enum Sex {
MAN(0, ""),
WOMAN(1, "");
@EnumValue
private final int code;
private final String des;
Sex(int code, String des) {
this.code = code;
this.des = des;
}
}

View File

@ -0,0 +1,10 @@
package com.github.yulichang.test.collection.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import com.github.yulichang.test.collection.entity.TableA;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface TableAMapper extends MPJBaseMapper<TableA> {
}

View File

@ -0,0 +1,11 @@
package com.github.yulichang.test.collection.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import com.github.yulichang.test.collection.entity.TableB;
import org.apache.ibatis.annotations.Mapper;
@Mapper
@SuppressWarnings("unused")
public interface TableBMapper extends MPJBaseMapper<TableB> {
}

View File

@ -0,0 +1,11 @@
package com.github.yulichang.test.collection.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import com.github.yulichang.test.collection.entity.TableC;
import org.apache.ibatis.annotations.Mapper;
@Mapper
@SuppressWarnings("unused")
public interface TableCMapper extends MPJBaseMapper<TableC> {
}

View File

@ -0,0 +1,11 @@
package com.github.yulichang.test.collection.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import com.github.yulichang.test.collection.entity.TableD;
import org.apache.ibatis.annotations.Mapper;
@Mapper
@SuppressWarnings("unused")
public interface TableDMapper extends MPJBaseMapper<TableD> {
}

View File

@ -0,0 +1,11 @@
package com.github.yulichang.test.collection.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import com.github.yulichang.test.collection.entity.TableE;
import org.apache.ibatis.annotations.Mapper;
@Mapper
@SuppressWarnings("unused")
public interface TableEMapper extends MPJBaseMapper<TableE> {
}

View File

@ -11,7 +11,6 @@ import com.github.yulichang.test.join.entity.UserDO;
import com.github.yulichang.test.join.mapper.UserMapper;
import com.github.yulichang.toolkit.MPJWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@ -32,16 +31,9 @@ import java.util.Map;
class LambdaWrapperTest {
@Resource
private UserMapper userMapper;
@Resource
private SqlSessionFactory sqlSessionFactory;
/**
* 一对多
*/
@Test
void testJoin() {
userMapper.selectListDeep(new QueryWrapper<>());
MPJLambdaWrapper<UserDO> wrapper = new MPJLambdaWrapper<UserDO>()
.selectAll(UserDO.class)
.selectCollection(AddressDO.class, UserDTO::getAddressList, addr -> addr
@ -109,6 +101,7 @@ class LambdaWrapperTest {
*/
@Test
void test6() {
userMapper.selectPage(new Page<>(1, 10),new QueryWrapper<>());
IPage<UserDTO> page = userMapper.selectJoinPage(new Page<>(1, 10), UserDTO.class,
MPJWrappers.<UserDO>lambdaJoin()
.selectAll(UserDO.class)

View File

@ -0,0 +1,61 @@
package com.github.yulichang.test.join.dto;
import lombok.Data;
import java.util.List;
@Data
public class TableDTO {
private Integer id;
private String name;
private List<TableBDTO> bbList;
@Data
public static class TableBDTO {
private Integer id;
private Integer aid;
private String name;
private List<TableCDTO> ccList;
}
@Data
public static class TableCDTO {
private Integer id;
private Integer bid;
private String name;
private List<TableDDTO> ddList;
}
@Data
public static class TableDDTO {
private Integer id;
private Integer cid;
private String name;
private List<TableEDTO> eeList;
}
@Data
public static class TableEDTO {
private Integer id;
private Integer did;
private String name;
}
}

View File

@ -0,0 +1,15 @@
package com.github.yulichang.test.join.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("table_a")
public class TableA {
@TableId
private Integer id;
private String name;
}

View File

@ -0,0 +1,17 @@
package com.github.yulichang.test.join.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("table_b")
public class TableB {
@TableId
private Integer id;
private Integer aid;
private String name;
}

View File

@ -0,0 +1,17 @@
package com.github.yulichang.test.join.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("table_c")
public class TableC {
@TableId
private Integer id;
private Integer bid;
private String name;
}

View File

@ -0,0 +1,17 @@
package com.github.yulichang.test.join.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("table_d")
public class TableD {
@TableId
private Integer id;
private Integer cid;
private String name;
}

View File

@ -0,0 +1,17 @@
package com.github.yulichang.test.join.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("table_e")
public class TableE {
@TableId
private Integer id;
private Integer did;
private String name;
}

View File

@ -24,7 +24,7 @@ public class UserDO {
private Integer id;
@TableField(value = "`name`", typeHandler = JacksonTypeHandler.class)
private Map<String,String> name;
private Map<String,String> aName;
private Sex sex;

View File

@ -0,0 +1,11 @@
package com.github.yulichang.test.join.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import com.github.yulichang.test.join.entity.TableA;
import org.apache.ibatis.annotations.Mapper;
@Mapper
@SuppressWarnings("unused")
public interface TableAMapper extends MPJBaseMapper<TableA> {
}

View File

@ -0,0 +1,11 @@
package com.github.yulichang.test.join.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import com.github.yulichang.test.join.entity.TableB;
import org.apache.ibatis.annotations.Mapper;
@Mapper
@SuppressWarnings("unused")
public interface TableBMapper extends MPJBaseMapper<TableB> {
}

View File

@ -0,0 +1,11 @@
package com.github.yulichang.test.join.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import com.github.yulichang.test.join.entity.TableC;
import org.apache.ibatis.annotations.Mapper;
@Mapper
@SuppressWarnings("unused")
public interface TableCMapper extends MPJBaseMapper<TableC> {
}

View File

@ -0,0 +1,11 @@
package com.github.yulichang.test.join.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import com.github.yulichang.test.join.entity.TableD;
import org.apache.ibatis.annotations.Mapper;
@Mapper
@SuppressWarnings("unused")
public interface TableDMapper extends MPJBaseMapper<TableD> {
}

View File

@ -0,0 +1,11 @@
package com.github.yulichang.test.join.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import com.github.yulichang.test.join.entity.TableE;
import org.apache.ibatis.annotations.Mapper;
@Mapper
@SuppressWarnings("unused")
public interface TableEMapper extends MPJBaseMapper<TableE> {
}

View File

@ -18,7 +18,6 @@ public class MybatisPlusConfig {
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor page = new PaginationInnerInterceptor();
page.setOptimizeJoin(false);
interceptor.addInnerInterceptor(page);
return interceptor;
}

View File

@ -0,0 +1,5 @@
spring:
sql:
init:
schema-locations: classpath:db/collection/schema.sql
data-locations: classpath:db/collection/data.sql

View File

@ -6,6 +6,7 @@ spring:
password: test
mybatis-plus:
typeEnumsPackage: com.github.yulichang.test
global-config:
db-config:
logic-delete-field: del

View File

@ -0,0 +1,29 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
DELETE FROM table_a;
insert into table_a (id, `name`) values (1, 'tableA1');
insert into table_a (id, `name`) values (2, 'tableA2');
insert into table_a (id, `name`) values (3, 'tableA3');
DELETE FROM table_b;
insert into table_b (id, aid, `name`) values (1, 1, 'tableB1');
insert into table_b (id, aid, `name`) values (2, 1, 'tableB2');
insert into table_b (id, aid, `name`) values (3, 2, 'tableB3');
DELETE FROM table_c;
insert into table_c (id, bid, `name`) values (1, 1, 'tableC1');
insert into table_c (id, bid, `name`) values (2, 1, 'tableC2');
insert into table_c (id, bid, `name`) values (3, 2, 'tableC3');
DELETE FROM table_d;
insert into table_d (id, cid, `name`) values (1, 1, 'tableD1');
insert into table_d (id, cid, `name`) values (2, 1, 'tableD2');
insert into table_d (id, cid, `name`) values (3, 2, 'tableD3');
DELETE FROM table_e;
insert into table_e (id, did, `name`) values (1, 1, 'tableE1');
insert into table_e (id, did, `name`) values (2, 1, 'tableE2');
insert into table_e (id, did, `name`) values (3, 2, 'tableE3');

View File

@ -0,0 +1,48 @@
-- noinspection SqlDialectInspectionForFile
-- noinspection SqlNoDataSourceInspectionForFile
DROP TABLE IF EXISTS table_a;
create table table_a
(
id int auto_increment
primary key,
`name` varchar(255) null
);
DROP TABLE IF EXISTS table_b;
create table table_b
(
id int auto_increment
primary key,
`aid` int not null,
`name` varchar(255) null
);
DROP TABLE IF EXISTS table_c;
create table table_c
(
id int auto_increment
primary key,
`bid` int not null,
`name` varchar(255) null
);
DROP TABLE IF EXISTS table_d;
create table table_d
(
id int auto_increment
primary key,
`cid` int not null,
`name` varchar(255) null
);
DROP TABLE IF EXISTS table_e;
create table table_e
(
id int auto_increment
primary key,
`did` int not null,
`name` varchar(255) null
);

View File

@ -76,4 +76,5 @@ INSERT INTO address (id, user_id, area_id, tel, address, del) VALUES (18,18, 100
INSERT INTO address (id, user_id, area_id, tel, address, del) VALUES (19,19, 10019, '10000000019', '曹县19', false);
INSERT INTO address (id, user_id, area_id, tel, address, del) VALUES (20,20, 10020, '10000000020', '曹县20', false);
INSERT INTO address (id, user_id, area_id, tel, address, del) VALUES (21,21, 10021, '10000000021', '曹县21', false);
INSERT INTO address (id, user_id, area_id, tel, address, del) VALUES (22,22, 10022, '10000000022', '曹县22', false);
INSERT INTO address (id, user_id, area_id, tel, address, del) VALUES (22,22, 10022, '10000000022', '曹县22', false);

View File

@ -12,20 +12,20 @@ create table area
city varchar(255) null,
area varchar(255) null,
postcode varchar(255) null,
del bit
del bit
);
DROP TABLE IF EXISTS `user`;
create table `user`
(
id int auto_increment
id int auto_increment
primary key,
`name` varchar(255) not null,
`address_id` int not null,
sex tinyint not null,
head_img varchar(255) not null,
del bit
`name` varchar(255) not null,
`address_id` int not null,
sex tinyint not null,
head_img varchar(255) not null,
del bit
);
DROP TABLE IF EXISTS address;
@ -34,9 +34,9 @@ create table address
(
id int auto_increment
primary key,
user_id int null,
area_id int null,
user_id int null,
area_id int null,
tel varchar(255) null,
address varchar(255) null,
del bit
del bit
);