Merge branch '2.0'

# Conflicts:
#	README.md
#	pom.xml
This commit is contained in:
yulichang 2022-11-28 00:58:24 +08:00
commit de2e1d8e09
146 changed files with 2989 additions and 649 deletions

View File

@ -14,13 +14,13 @@ QQ群:1022221898
```xml
<dependency>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join</artifactId>
<version>1.3.5</version>
<artifactId>mybatis-plus-join-boot-starter</artifactId>
<version>1.3.8</version>
</dependency>
```
- Gradle
```
implementation 'com.github.yulichang:mybatis-plus-join:1.3.5'
implementation 'com.github.yulichang:mybatis-plus-join-boot-starter:1.3.8'
```
或者clone代码到本地执行 mvn install, 再引入以上依赖
<br>

View File

@ -0,0 +1,54 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-root</artifactId>
<version>1.3.8</version>
</parent>
<version>1.3.8</version>
<artifactId>mybatis-plus-join-annotation</artifactId>
<name>mybatis-plus-join-annotation</name>
<description>An enhanced toolkit of Mybatis-Plus to simplify development.</description>
<url>https://github.com/yulichang/mybatis-plus-join</url>
<licenses>
<license>
<name>The Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<developers>
<developer>
<id>mybatis-plus-join</id>
<name>yulichang</name>
<email>yu_lichang@qq.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:https://github.com/yulichang/mybatis-plus-join.git</connection>
<developerConnection>scm:git:https://github.com/yulichang/mybatis-plus-join.git</developerConnection>
<url>https://github.com/yulichang/mybatis-plus-join</url>
</scm>
<properties>
<jdkVersion>1.8</jdkVersion>
<jdkVersion.test>1.8</jdkVersion.test>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<github.global.server>github</github.global.server>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-core</artifactId>
<version>3.5.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -10,6 +10,7 @@ import java.lang.annotation.*;
* @since 1.2.0
*/
@Documented
@SuppressWarnings("unused")
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface EntityMapping {

View File

@ -10,6 +10,7 @@ import java.lang.annotation.*;
* @since 1.2.0
*/
@Documented
@SuppressWarnings("unused")
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface FieldMapping {

View File

@ -7,6 +7,7 @@ package com.github.yulichang.annotation;
* @author yulichang
* @since 1.2.0
*/
@SuppressWarnings("unused")
public @interface MPJMappingApply {
/**

View File

@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.core.enums.SqlKeyword;
* @author yulichang
* @since 1.2.0
*/
@SuppressWarnings("unused")
public @interface MPJMappingCondition {
/**

View File

@ -0,0 +1,71 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-root</artifactId>
<version>1.3.8</version>
</parent>
<version>1.3.8</version>
<artifactId>mybatis-plus-join-boot-starter</artifactId>
<name>mybatis-plus-join-boot-starter</name>
<description>An enhanced toolkit of Mybatis-Plus to simplify development.</description>
<url>https://github.com/yulichang/mybatis-plus-join</url>
<licenses>
<license>
<name>The Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<developers>
<developer>
<id>mybatis-plus-join</id>
<name>yulichang</name>
<email>yu_lichang@qq.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:https://github.com/yulichang/mybatis-plus-join.git</connection>
<developerConnection>scm:git:https://github.com/yulichang/mybatis-plus-join.git</developerConnection>
<url>https://github.com/yulichang/mybatis-plus-join</url>
</scm>
<properties>
<jdkVersion>1.8</jdkVersion>
<jdkVersion.test>1.8</jdkVersion.test>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<github.global.server>github</github.global.server>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-core</artifactId>
<version>1.3.8</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,128 @@
package com.github.yulichang.autoconfigure;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration;
import com.baomidou.mybatisplus.core.injector.AbstractSqlInjector;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.github.yulichang.config.ConfigProperties;
import com.github.yulichang.config.InterceptorConfig;
import com.github.yulichang.injector.MPJSqlInjector;
import com.github.yulichang.interceptor.MPJInterceptor;
import com.github.yulichang.toolkit.SpringContentUtils;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import javax.sql.DataSource;
import java.util.List;
/**
* springboot 自动配置类
*
* @author yulichang
* @since 1.3.7
*/
@SuppressWarnings("unused")
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisPlusJoinProperties.class)
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisPlusLanguageDriverAutoConfiguration.class})
public class MybatisPlusJoinAutoConfiguration {
private static final Logger logger = LoggerFactory.getLogger(MybatisPlusJoinAutoConfiguration.class);
@SuppressWarnings("FieldCanBeLocal")
private final MybatisPlusJoinProperties properties;
public MybatisPlusJoinAutoConfiguration(MybatisPlusJoinProperties properties) {
this.properties = properties;
ConfigProperties.subTableLogic = properties.getSubTableLogic();
}
/**
* mybatis plus join 拦截器
*/
@Bean
public MPJInterceptor mpjInterceptor() {
return new MPJInterceptor();
}
/**
* mybatis plus 拦截器配置
*/
@Bean
@ConditionalOnBean(SqlSessionFactory.class)
public InterceptorConfig interceptorConfig(List<SqlSessionFactory> sqlSessionFactoryList) {
return new InterceptorConfig(sqlSessionFactoryList, properties.getBanner());
}
/**
* mybatis plus join 自定义方法
*/
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnMissingBean({DefaultSqlInjector.class, AbstractSqlInjector.class, ISqlInjector.class})
public MPJSqlInjector mpjSqlInjector() {
return new MPJSqlInjector();
}
/**
* springboot content 工具类
*/
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
@SuppressWarnings("InstantiationOfUtilityClass")
public SpringContentUtils springContentUtils(SpringContext springContext) {
return new SpringContentUtils(springContext);
}
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnBean(SqlSessionFactory.class)
public static class MappingConfig implements ApplicationListener<ApplicationReadyEvent> {
@Override
@SuppressWarnings("NullableProblems")
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
new com.github.yulichang.config.MappingConfig();
}
}
@Configuration
@ConditionalOnBean(SqlSessionFactory.class)
public static class SpringContext implements SpringContentUtils.SpringContext, ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public <T> T getBean(Class<T> clazz) {
return this.applicationContext.getBean(clazz);
}
@Override
@SuppressWarnings("NullableProblems")
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
}

View File

@ -0,0 +1,27 @@
package com.github.yulichang.autoconfigure;
import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 配置类
*
* @author yulichang
* @since 1.3.7
*/
@Data
@Accessors(chain = true)
@ConfigurationProperties(prefix = "mybatis-plus-join")
public class MybatisPlusJoinProperties {
/**
* 打印banner
*/
private Boolean banner = true;
/**
* 连表查询副表是否启用逻辑删除(前提是MP配置了逻辑删除)
*/
private Boolean subTableLogic = true;
}

View File

@ -0,0 +1,23 @@
{
"groups": [
{
"sourceType": "com.github.yulichang.autoconfigure.MybatisPlusJoinProperties",
"name": "mybatis-plus-join",
"type": "com.github.yulichang.autoconfigure.MybatisPlusJoinProperties"
}
],
"properties": [
{
"name": "mybatis-plus-join.banner",
"defaultValue": true,
"type": "java.lang.Boolean",
"description": "打印 banner."
},
{
"name": "mybatis-plus-join.sub-table-logic",
"defaultValue": true,
"type": "java.lang.Boolean",
"description": "连表查询副表是否启用逻辑删除(前提是MP配置了逻辑删除)."
}
]
}

View File

@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.github.yulichang.autoconfigure.MybatisPlusJoinAutoConfiguration

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--suppress VulnerableLibrariesLocal -->
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-root</artifactId>
<version>1.3.8</version>
</parent>
<version>1.3.8</version>
<artifactId>mybatis-plus-join-core</artifactId>
<name>mybatis-plus-join-core</name>
<description>An enhanced toolkit of Mybatis-Plus to simplify development.</description>
<url>https://github.com/yulichang/mybatis-plus-join</url>
<licenses>
<license>
<name>The Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<developers>
<developer>
<id>mybatis-plus-join</id>
<name>yulichang</name>
<email>yu_lichang@qq.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:https://github.com/yulichang/mybatis-plus-join.git</connection>
<developerConnection>scm:git:https://github.com/yulichang/mybatis-plus-join.git</developerConnection>
<url>https://github.com/yulichang/mybatis-plus-join</url>
</scm>
<properties>
<jdkVersion>1.8</jdkVersion>
<jdkVersion.test>1.8</jdkVersion.test>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<github.global.server>github</github.global.server>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-annotation</artifactId>
<version>1.3.8</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
<version>3.5.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<scope>provided</scope>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.23</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,9 @@
package com.github.yulichang.config;
/**
* @author yulichang
* @since 1.3.7
*/
public class ConfigProperties {
public static boolean subTableLogic = true;
}

View File

@ -8,8 +8,6 @@ import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.InterceptorChain;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Configuration;
import java.lang.reflect.Field;
import java.util.List;
@ -19,16 +17,19 @@ import java.util.List;
*
* @author yulichang
*/
@Configuration
@ConditionalOnBean(SqlSessionFactory.class)
@SuppressWarnings("unused")
public class InterceptorConfig {
private static final Log logger = LogFactory.getLog(InterceptorConfig.class);
public InterceptorConfig(List<SqlSessionFactory> sqlSessionFactoryList) {
public InterceptorConfig(List<SqlSessionFactory> sqlSessionFactoryList, Boolean banner) {
replaceInterceptorChain(sqlSessionFactoryList);
if (banner) {
//打印banner
System.out.println(" _ _ |_ _ _|_. ___ _ | _ . _ . _ \n" +
"| | |\\/|_)(_| | |_\\ |_)||_|_\\ | (_) | | | \n" +
" / | / 1.3.8");
}
}
@SuppressWarnings("unchecked")

View File

@ -1,12 +1,8 @@
package com.github.yulichang.config;
import com.baomidou.mybatisplus.core.metadata.MPJTableInfoHelper;
import com.github.yulichang.mapper.MPJTableMapperHelper;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import com.github.yulichang.mapper.MPJTableMapperHelper;
/**
* 关系映射配置
@ -14,13 +10,11 @@ import org.springframework.core.annotation.Order;
* @author yulichang
* @since 1.2.0
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MappingConfig implements ApplicationListener<ApplicationReadyEvent> {
public class MappingConfig {
@Override
@SuppressWarnings("NullableProblems")
public void onApplicationEvent(ApplicationReadyEvent event) {
public MappingConfig() {
TableInfoHelper.getTableInfos().forEach(i ->
MPJTableInfoHelper.initTableInfo(i.getEntityType(), MPJTableMapperHelper.get(i.getEntityType())));
}
}

View File

@ -2,27 +2,16 @@ package com.github.yulichang.injector;
import com.baomidou.mybatisplus.core.MybatisPlusVersion;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.AbstractSqlInjector;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.core.injector.methods.*;
import com.baomidou.mybatisplus.core.mapper.Mapper;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.toolkit.ClassUtils;
import com.github.yulichang.mapper.MPJTableMapperHelper;
import com.github.yulichang.method.*;
import com.github.yulichang.method.mp.SelectCount;
import com.github.yulichang.method.mp.SelectList;
import com.github.yulichang.method.mp.SelectMaps;
import com.github.yulichang.method.mp.SelectMapsPage;
import com.github.yulichang.method.mp.SelectObjs;
import com.github.yulichang.method.mp.SelectOne;
import com.github.yulichang.method.mp.SelectPage;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import java.util.ArrayList;
import java.util.Arrays;
@ -37,13 +26,8 @@ import static java.util.stream.Collectors.toList;
* @author yulichang
* @see DefaultSqlInjector
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnMissingBean({DefaultSqlInjector.class, AbstractSqlInjector.class, ISqlInjector.class})
public class MPJSqlInjector extends DefaultSqlInjector {
private static final List<String> METHOD_LIST = Arrays.asList("SelectOne", "SelectCount",
"SelectMaps", "SelectMapsPage", "SelectObjs", "SelectList", "SelectPage");
/**
* 升级到 mybatis plus 3.4.3.2 后对之前的版本兼容
@ -72,8 +56,10 @@ public class MPJSqlInjector extends DefaultSqlInjector {
*/
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
List<String> methodList = Arrays.asList("SelectOne", "SelectCount",
"SelectMaps", "SelectMapsPage", "SelectObjs", "SelectList", "SelectPage");
List<AbstractMethod> list = super.getMethodList(mapperClass, tableInfo);
list.removeIf(i -> METHOD_LIST.contains(i.getClass().getSimpleName()));
list.removeIf(i -> methodList.contains(i.getClass().getSimpleName()));
list.addAll(getSelectMethod());
list.addAll(getJoinMethod());
return list;
@ -115,12 +101,12 @@ public class MPJSqlInjector extends DefaultSqlInjector {
private List<AbstractMethod> getSelectMethod() {
List<AbstractMethod> list = new ArrayList<>();
list.add(new SelectOne());
list.add(new SelectCount());
list.add(new SelectMaps());
list.add(new SelectMapsPage());
list.add(new SelectObjs());
list.add(new SelectList());
list.add(new SelectPage());
list.add(new com.github.yulichang.method.mp.SelectCount());
list.add(new com.github.yulichang.method.mp.SelectMaps());
list.add(new com.github.yulichang.method.mp.SelectMapsPage());
list.add(new com.github.yulichang.method.mp.SelectObjs());
list.add(new com.github.yulichang.method.mp.SelectList());
list.add(new com.github.yulichang.method.mp.SelectPage());
return list;
}

View File

@ -95,7 +95,7 @@ public class MPJInterceptor implements Interceptor {
public MappedStatement getMappedStatement(MappedStatement ms, Class<?> resultType, Object ew) {
String id = ms.getId() + StringPool.UNDERSCORE + resultType.getName();
if (ew instanceof MPJLambdaWrapper) {
if (ew instanceof MPJLambdaWrapper && ((MPJLambdaWrapper<?>) ew).isResultMap()) {
//不走缓存
return buildMappedStatement(ms, resultType, ew, id);
}
@ -200,7 +200,8 @@ public class MPJInterceptor implements Interceptor {
} else {
// 主键列
resultMappings.add(new ResultMapping.Builder(ms.getConfiguration(), i.getTagProperty(),
StringUtils.getTargetColumn(i.getColumnName()), i.getKeyType()).build());
StringUtils.getTargetColumn(i.getColumnName()), i.getKeyType())
.flags(Collections.singletonList(ResultFlag.ID)).build());
}
}
Set<String> columnSet = resultMappings.stream().map(ResultMapping::getColumn).collect(Collectors.toSet());
@ -310,13 +311,12 @@ public class MPJInterceptor implements Interceptor {
* @return 唯一列名
*/
private String getColumn(Set<String> pool, String columnName) {
String tagName = StringUtils.getTargetColumn(columnName);
if (!pool.contains(tagName)) {
pool.add(tagName);
return tagName;
if (!pool.contains(columnName)) {
pool.add(columnName);
return columnName;
}
tagName = "mpj_" + tagName;
return getColumn(pool, tagName);
columnName = "join_" + StringUtils.getTargetColumn(columnName);
return getColumn(pool, columnName);
}
/**

View File

@ -279,7 +279,7 @@ public class MPJTableFieldInfo {
if (joinTableInfo == null) {
throw new MPJException("未注册 mapper " + this.joinClass.getName());
}
this.joinMapper = (BaseMapper<?>) SpringContentUtils.getApplicationContext().getBean(joinTableInfo.getMapperClass());
this.joinMapper = (BaseMapper<?>) SpringContentUtils.getBean(joinTableInfo.getMapperClass());
}
return this.joinMapper;
}

View File

@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils;
import com.github.yulichang.config.ConfigProperties;
import com.github.yulichang.toolkit.Constant;
import java.util.Objects;
@ -26,6 +27,9 @@ public interface MPJBaseMethod extends Constants {
sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", WRAPPER_ENTITY), true);
sqlScript += NEWLINE;
sqlScript += (NEWLINE + getLogicDeleteSql(table, true, true) + NEWLINE);
if (ConfigProperties.subTableLogic) {
sqlScript += (String.format("${%s.logicSql}", WRAPPER));
}
String normalSqlScript = SqlScriptUtils.convertIf(String.format("AND ${%s}", WRAPPER_SQLSEGMENT), String.format("%s != null and %s != '' and %s", WRAPPER_SQLSEGMENT, WRAPPER_SQLSEGMENT, WRAPPER_NONEMPTYOFNORMAL), true);
normalSqlScript += NEWLINE;
normalSqlScript += SqlScriptUtils.convertIf(String.format(" ${%s}", WRAPPER_SQLSEGMENT), String.format("%s != null and %s != '' and %s", WRAPPER_SQLSEGMENT, WRAPPER_SQLSEGMENT, WRAPPER_EMPTYOFNORMAL), true);
@ -37,7 +41,10 @@ public interface MPJBaseMethod extends Constants {
String sqlScript = getAllSqlWhere(table, false, true, WRAPPER_ENTITY_DOT);
sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", WRAPPER_ENTITY), true);
sqlScript += NEWLINE;
sqlScript += SqlScriptUtils.convertIf(String.format("${%s}", WRAPPER_SQLSEGMENT), String.format("%s != null and %s != '' and %s", WRAPPER_SQLSEGMENT, WRAPPER_SQLSEGMENT, WRAPPER_NONEMPTYOFWHERE), true);
if (ConfigProperties.subTableLogic) {
sqlScript += (String.format("${%s.logicSql}", WRAPPER) + NEWLINE);
}
sqlScript += SqlScriptUtils.convertIf(String.format("AND ${%s}", WRAPPER_SQLSEGMENT), String.format("%s != null and %s != '' and %s", WRAPPER_SQLSEGMENT, WRAPPER_SQLSEGMENT, WRAPPER_NONEMPTYOFWHERE), true);
sqlScript = SqlScriptUtils.convertWhere(sqlScript) + NEWLINE;
sqlScript += SqlScriptUtils.convertIf(String.format(" ${%s}", WRAPPER_SQLSEGMENT), String.format("%s != null and %s != '' and %s", WRAPPER_SQLSEGMENT, WRAPPER_SQLSEGMENT, WRAPPER_EMPTYOFWHERE), true);
sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", WRAPPER), true);

View File

@ -7,14 +7,10 @@ import com.baomidou.mybatisplus.core.conditions.segments.MergeSegments;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.*;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.github.yulichang.query.interfaces.MPJJoin;
import com.github.yulichang.toolkit.Constant;
import org.springframework.util.Assert;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

View File

@ -204,6 +204,13 @@ public class MPJQueryWrapper<T> extends AbstractWrapper<T, String, MPJQueryWrapp
return this;
}
/**
* 逻辑删除
*/
public String getLogicSql() {
return StringPool.EMPTY;
}
/**
* 返回一个支持 lambda 函数写法的 wrapper
*/
@ -223,6 +230,7 @@ public class MPJQueryWrapper<T> extends AbstractWrapper<T, String, MPJQueryWrapp
null, null, SharedString.emptyString(), SharedString.emptyString(), SharedString.emptyString(), null, null);
}
@Override
public void clear() {
super.clear();

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,45 @@
package com.github.yulichang.toolkit;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
* 逻辑删除信息类
*
* @author yulichang
* @since 1.3.7
*/
public class LogicInfoUtils implements Constants {
private static final Map<Class<?>, String> LOGIC_CACHE = new ConcurrentHashMap<>();
@SuppressWarnings("ConstantConditions")
public static String getLogicInfo(int tableIndex, Class<?> clazz) {
String logicStr = LOGIC_CACHE.get(clazz);
if (Objects.nonNull(logicStr)) {
return logicStr;
}
TableInfo tableInfo = TableInfoHelper.getTableInfo(clazz);
Assert.notNull(tableInfo, "%s 不是数据库实体或没有注册到mybatis plus中", clazz.getName());
if (tableInfo.isWithLogicDelete() && Objects.nonNull(tableInfo.getLogicDeleteFieldInfo())) {
final String value = tableInfo.getLogicDeleteFieldInfo().getLogicNotDeleteValue();
if (NULL.equalsIgnoreCase(value)) {
logicStr = " AND " + Constant.TABLE_ALIAS + tableIndex + DOT + tableInfo.getLogicDeleteFieldInfo().getColumn() + " IS NULL";
} else {
logicStr = " AND " + Constant.TABLE_ALIAS + tableIndex + DOT + tableInfo.getLogicDeleteFieldInfo().getColumn() + EQUALS + String.format(tableInfo.getLogicDeleteFieldInfo().isCharSequence() ? "'%s'" : "%s", value);
}
} else {
logicStr = StringPool.EMPTY;
}
LOGIC_CACHE.put(clazz, logicStr);
return logicStr;
}
}

View File

@ -0,0 +1,62 @@
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 1.3.7
*/
@SuppressWarnings("unused")
public final class MPJReflectionKit {
private static final Map<Class<?>, Map<String, Field>> CLASS_FIELD_CACHE = new ConcurrentHashMap<>();
private static final Map<String, Field> EMPTY_MAP = new HashMap<>();
/**
* 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 EMPTY_MAP;
}
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,17 +15,16 @@
*/
package com.github.yulichang.toolkit;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.ClassUtils;
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 org.springframework.core.GenericTypeResolver;
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;
@ -39,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);
@ -96,32 +95,11 @@ public final class ReflectionKit {
* @return Class
*/
public static Class<?> getSuperClassGenericType(final Class<?> clazz, final Class<?> genericIfc, final int index) {
Class<?>[] typeArguments = GenericTypeResolver.resolveTypeArguments(ClassUtils.getUserClass(clazz), genericIfc);
//update by noear @2021-09-03
Class<?>[] typeArguments = GenericTypeUtils.resolveTypeArguments(ClassUtils.getUserClass(clazz), genericIfc);
return null == typeArguments ? null : typeArguments[index];
}
/**
* 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;
}
/**
* <p>
* 获取该类的所有属性列表
@ -131,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();
}
/**
@ -162,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());
});
}
@ -181,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;
}
@ -196,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));
@ -204,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

@ -0,0 +1,26 @@
package com.github.yulichang.toolkit;
/**
* spring容器工具类
*
* @author yulichang
* @since 1.2.0
*/
public class SpringContentUtils {
private static SpringContext springContext;
public SpringContentUtils(SpringContext springContext) {
SpringContentUtils.springContext = springContext;
}
public static <T> T getBean(Class<T> clazz) {
return SpringContentUtils.springContext.getBean(clazz);
}
public interface SpringContext {
<T> T getBean(Class<T> clazz);
}
}

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

@ -0,0 +1,73 @@
/*
* 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 java.io.*;
/**
* 当前类是 {@link java.lang.invoke.SerializedLambda } 的一个镜像
* <p>
* Create by hcl at 2020/7/17
*/
@SuppressWarnings("ALL")
public class SerializedLambda implements Serializable {
private static final long serialVersionUID = 8025925345765570181L;
private Class<?> capturingClass;
private String functionalInterfaceClass;
private String functionalInterfaceMethodName;
private String functionalInterfaceMethodSignature;
private String implClass;
private String implMethodName;
private String implMethodSignature;
private int implMethodKind;
private String instantiatedMethodType;
private Object[] capturedArgs;
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 (SerializedLambda) ois.readObject();
}
} catch (IOException | ClassNotFoundException e) {
throw new MybatisPlusException(e);
}
}
public String getInstantiatedMethodType() {
return instantiatedMethodType;
}
public Class<?> getCapturingClass() {
return capturingClass;
}
public String getImplMethodName() {
return 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

@ -5,16 +5,12 @@ import com.baomidou.mybatisplus.core.conditions.segments.MergeSegments;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
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.*;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.github.yulichang.exception.MPJException;
import com.github.yulichang.toolkit.Constant;
import com.github.yulichang.config.ConfigProperties;
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;
@ -37,8 +33,6 @@ import java.util.stream.Collectors;
/**
* 参考 {@link com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper}
* Lambda 语法使用 Wrapper
* <p>
* 推荐使用 MPJWrappers.<UserDO>lambdaJoin();构造
*
* @author yulichang
* @see MPJWrappers
@ -154,18 +148,18 @@ public class MPJLambdaWrapper<T> extends MPJAbstractLambdaWrapper<T, MPJLambdaWr
/**
* 一对多查询 调用此方法发必需要调用对应的 left join / right join ... 连表方法否则会报错
* <p>
* 举例 UserDO UserAddressDO 为一对多关系 UserDTO 为结果类
* 举例 UserDO AddressDO 为一对多关系 UserDTO 为结果类
* <pre>
* MPJLambdaQueryWrapper<UserDO> wrapper = new MPJLambdaQueryWrapper<UserDO>();
* wrapper.selectAll(UserDO.class)
* .selectCollection(UserAddressDO.class, UserDTO::getAddressListDTO)
* .leftJoin(UserAddressDO.class, ...... )
* .selectCollection(AddressDO.class, UserDTO::getAddressListDTO)
* .leftJoin(AddressDO.class, ...... )
* .eq(...)
* ...
* <pre/>
* 会自动将 UserAddressDO类中相同属性的字段 以mybatis<collection>的方式映射到UserDTO.addressListDTO属性中
* 会自动将 AddressDO类中相同属性的字段 以mybatis<collection>的方式映射到UserDTO.addressListDTO属性中
*
* @since 1.2.5
* @since 1.3.0
*
* @param child 连表数据库实体类
* @param dtoField 包装类对应的属性
@ -177,19 +171,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());
@ -199,22 +190,22 @@ public class MPJLambdaWrapper<T> extends MPJAbstractLambdaWrapper<T, MPJLambdaWr
/**
* 一对多查询 调用此方法发必需要调用对应的 left join / right join ... 连表方法否则会报错
* <p>
* 举例 UserDO UserAddressDO 为一对多关系 UserDTO 为结果类
* 举例 UserDO AddressDO 为一对多关系 UserDTO 为结果类
* <pre>
* MPJLambdaQueryWrapper<UserDO> wrapper = new MPJLambdaQueryWrapper();
* wrapper.selectAll(UserDO.class)
* .selectCollection(UserAddressDO.class, UserDTO::getAddressListDTO, map -> map
* .id(UserAddressDO::getId, AddressDTO::getId) //如果属性名一致 可以传一个
* .result(UserAddressDO::getUserId) //如果属性名一致 可以传一个
* .result(UserAddressDO::getAddress, AddressDTO::getAddress))) //如果属性名一致 可以传一个
* .leftJoin(UserAddressDO.class, ...... )
* .eq(...)
* ...
* MPJLambdaQueryWrapper<UserDO> wrapper = new MPJLambdaQueryWrapper();
* wrapper.selectAll(UserDO.class)
* .selectCollection(AddressDO.class, UserDTO::getAddressListDTO, map -> map
* .id(AddressDO::getId, AddressDTO::getId) //如果属性名一致 可以传一个
* .result(AddressDO::getUserId) //如果属性名一致 可以传一个
* .result(AddressDO::getAddress, AddressDTO::getAddress))) //如果属性名一致 可以传一个
* .leftJoin(AddressDO.class, ...... )
* .eq(...)
* ...
* <pre/>
*
* 会自动将 UserAddressDO类中指定的字段 以mybatis<collection>的方式映射到UserDTO.addressListDTO属性中
* 会自动将 AddressDO类中指定的字段 以mybatis<collection>的方式映射到UserDTO.addressListDTO属性中
*
* @since 1.2.5
* @since 1.3.0
*
* @param child 连表数据库实体类
* @param dtoField 包装类对应的属性
@ -228,10 +219,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 +232,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 +250,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;
@ -314,20 +299,16 @@ public class MPJLambdaWrapper<T> extends MPJAbstractLambdaWrapper<T, MPJLambdaWr
return typedThis;
}
public <S> MPJLambdaWrapper<T> selectFunc(boolean condition, BaseFuncEnum funcEnum, SFunction<S, ?> column, String alias) {
if (condition) {
ColumnCache cache = getCache(column);
selectColumns.add(SelectColumn.of(LambdaUtils.getEntityClass(column), cache.getColumn(),
cache.getTableFieldInfo(), alias, alias, cache.getKeyType(), false, funcEnum));
}
public <S> MPJLambdaWrapper<T> selectFunc(BaseFuncEnum funcEnum, SFunction<S, ?> column, String alias) {
ColumnCache cache = getCache(column);
selectColumns.add(SelectColumn.of(LambdaUtils.getEntityClass(column), cache.getColumn(),
cache.getTableFieldInfo(), alias, alias, cache.getKeyType(), false, funcEnum));
return typedThis;
}
@Override
public MPJLambdaWrapper<T> selectFunc(boolean condition, BaseFuncEnum funcEnum, Object column, String alias) {
if (condition) {
selectColumns.add(SelectColumn.of(null, column.toString(), null, alias, alias, null, false, funcEnum));
}
public MPJLambdaWrapper<T> selectFunc(BaseFuncEnum funcEnum, Object column, String alias) {
selectColumns.add(SelectColumn.of(null, column.toString(), null, alias, alias, null, false, funcEnum));
return typedThis;
}
@ -348,7 +329,7 @@ public class MPJLambdaWrapper<T> extends MPJAbstractLambdaWrapper<T, MPJLambdaWr
*/
@Override
public String getSqlSelect() {
if (StringUtils.isBlank(sqlSelect.getStringValue())) {
if (StringUtils.isBlank(sqlSelect.getStringValue()) && CollectionUtils.isNotEmpty(selectColumns)) {
String s = selectColumns.stream().map(i -> {
String str = Constant.TABLE_ALIAS + getDefault(subTable.get(i.getClazz())) + StringPool.DOT + i.getColumnName();
return (i.getFuncEnum() == null ? str : String.format(i.getFuncEnum().getSql(), str)) +
@ -412,14 +393,26 @@ public class MPJLambdaWrapper<T> extends MPJAbstractLambdaWrapper<T, MPJLambdaWr
subTable.clear();
}
@Override
public <R> MPJLambdaWrapper<T> join(String keyWord, boolean condition, Class<R> clazz, OnFunction function) {
if (condition) {
MPJLambdaWrapper<?> apply = function.apply(instance(keyWord, clazz));
onWrappers.add(apply);
subTable.put(clazz, tableIndex);
tableIndex++;
/**
* 副表部分逻辑删除支持
*/
public String getLogicSql() {
if (ConfigProperties.subTableLogic) {
if (CollectionUtils.isEmpty(subTable)) {
return StringPool.EMPTY;
}
return subTable.entrySet().stream().map(entry -> LogicInfoUtils.getLogicInfo(entry.getValue(),
entry.getKey())).collect(Collectors.joining(StringPool.SPACE));
}
return StringPool.EMPTY;
}
@Override
public <R> MPJLambdaWrapper<T> join(String keyWord, Class<R> clazz, OnFunction function) {
MPJLambdaWrapper<?> apply = function.apply(instance(keyWord, clazz));
subTable.put(clazz, tableIndex);
onWrappers.add(apply);
tableIndex++;
return typedThis;
}
}
}

View File

@ -0,0 +1,88 @@
package com.github.yulichang.wrapper.interfaces;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.github.yulichang.interfaces.MPJBaseJoin;
import com.github.yulichang.toolkit.Constant;
import com.github.yulichang.wrapper.interfaces.on.OnFunction;
/**
* @author yulichang
*/
@SuppressWarnings("unused")
public interface LambdaJoin<Children, Entity> extends MPJBaseJoin<Entity> {
/**
* left join
*
* @param clazz 关联的实体类
* @param left 条件
* @param right 条件
*/
default <T, X> Children leftJoin(Class<T> clazz, SFunction<T, ?> left, SFunction<X, ?> right) {
return leftJoin(clazz, on -> on.eq(left, right));
}
/**
* left join
* <p>
* leftJoin(UserDO.class, on -> on.eq(UserDO::getId,UserAddressDO::getUserId).le().gt()...)
*
* @param clazz 关联实体类
* @param function 条件
*/
default <T> Children leftJoin(Class<T> clazz, OnFunction function) {
return join(Constant.LEFT_JOIN, clazz, function);
}
/**
* ignore 参考 left join
*/
default <T, X> Children rightJoin(Class<T> clazz, SFunction<T, ?> left, SFunction<X, ?> right) {
return rightJoin(clazz, on -> on.eq(left, right));
}
/**
* ignore 参考 left join
*/
default <T> Children rightJoin(Class<T> clazz, OnFunction function) {
return join(Constant.RIGHT_JOIN, clazz, function);
}
/**
* ignore 参考 left join
*/
default <T, X> Children innerJoin(Class<T> clazz, SFunction<T, ?> left, SFunction<X, ?> right) {
return innerJoin(clazz, on -> on.eq(left, right));
}
/**
* ignore 参考 left join
*/
default <T> Children innerJoin(Class<T> clazz, OnFunction function) {
return join(Constant.INNER_JOIN, clazz, function);
}
/**
* ignore 参考 left join
*/
default <T, X> Children fullJoin(Class<T> clazz, SFunction<T, ?> left, SFunction<X, ?> right) {
return fullJoin(clazz, on -> on.eq(left, right));
}
/**
* ignore 参考 left join
*/
default <T> Children fullJoin(Class<T> clazz, OnFunction function) {
return join(Constant.FULL_JOIN, clazz, function);
}
/**
* 查询基类 可以直接调用此方法实现以上所有功能
*
* @param keyWord 连表关键字
* @param clazz 连表实体类
* @param function 关联条件
*/
<T> Children join(String keyWord, Class<T> clazz, OnFunction function);
}

View File

@ -75,40 +75,20 @@ public interface Query<Children> extends Serializable {
* @param column 函数作用的字段
* @param alias 别名
*/
Children selectFunc(boolean condition, BaseFuncEnum funcEnum, Object column, String alias);
Children selectFunc(BaseFuncEnum funcEnum, Object column, String alias);
<S> Children selectFunc(boolean condition, BaseFuncEnum funcEnum, SFunction<S, ?> column, String alias);
default <S> Children selectFunc(BaseFuncEnum funcEnum, Object column, String alias) {
return selectFunc(true, funcEnum, column, alias);
}
default <S> Children selectFunc(BaseFuncEnum funcEnum, SFunction<S, ?> column, String alias) {
return selectFunc(true, funcEnum, column, alias);
}
<S> Children selectFunc(BaseFuncEnum funcEnum, SFunction<S, ?> column, String alias);
default <S, X> Children selectFunc(BaseFuncEnum funcEnum, SFunction<S, ?> column, SFunction<X, ?> alias) {
return selectFunc(true, funcEnum, column, LambdaUtils.getName(alias));
return selectFunc(funcEnum, column, LambdaUtils.getName(alias));
}
default <S> Children selectFunc(BaseFuncEnum funcEnum, SFunction<S, ?> column) {
return selectFunc(true, funcEnum, column, column);
return selectFunc(funcEnum, column, column);
}
default <X> Children selectFunc(BaseFuncEnum funcEnum, Object column, SFunction<X, ?> alias) {
return selectFunc(true, funcEnum, column, LambdaUtils.getName(alias));
}
default <S, X> Children selectFunc(boolean condition, BaseFuncEnum funcEnum, SFunction<S, ?> column, SFunction<X, ?> alias) {
return selectFunc(condition, funcEnum, column, LambdaUtils.getName(alias));
}
default <S> Children selectFunc(boolean condition, BaseFuncEnum funcEnum, SFunction<S, ?> column) {
return selectFunc(condition, funcEnum, column, column);
}
default <X> Children selectFunc(boolean condition, BaseFuncEnum funcEnum, Object column, SFunction<X, ?> alias) {
return selectFunc(condition, funcEnum, column, LambdaUtils.getName(alias));
return selectFunc(funcEnum, column, LambdaUtils.getName(alias));
}
/**
@ -138,18 +118,6 @@ public interface Query<Children> extends Serializable {
return selectFunc(DefaultFuncEnum.SUM, column, alias);
}
default <S> Children selectSum(boolean condition, SFunction<S, ?> column) {
return selectFunc(condition, DefaultFuncEnum.SUM, column);
}
default <S, X> Children selectSum(boolean condition, SFunction<S, ?> column, SFunction<X, ?> alias) {
return selectFunc(condition, DefaultFuncEnum.SUM, column, alias);
}
default <S, X> Children selectSum(boolean condition, SFunction<S, ?> column, String alias) {
return selectFunc(condition, DefaultFuncEnum.SUM, column, alias);
}
/**
* COUNT()
*/
@ -173,26 +141,6 @@ public interface Query<Children> extends Serializable {
return selectFunc(DefaultFuncEnum.COUNT, column, alias);
}
default <S> Children selectCount(boolean condition, SFunction<S, ?> column) {
return selectFunc(condition, DefaultFuncEnum.COUNT, column);
}
default <X> Children selectCount(boolean condition, Object column, SFunction<X, ?> alias) {
return selectFunc(condition, DefaultFuncEnum.COUNT, column, alias);
}
default Children selectCount(boolean condition, Object column, String alias) {
return selectFunc(condition, DefaultFuncEnum.COUNT, column, alias);
}
default <S, X> Children selectCount(boolean condition, SFunction<S, ?> column, SFunction<X, ?> alias) {
return selectFunc(condition, DefaultFuncEnum.COUNT, column, alias);
}
default <S, X> Children selectCount(boolean condition, SFunction<S, ?> column, String alias) {
return selectFunc(condition, DefaultFuncEnum.COUNT, column, alias);
}
/**
* MAX()
*/
@ -208,18 +156,6 @@ public interface Query<Children> extends Serializable {
return selectFunc(DefaultFuncEnum.MAX, column, alias);
}
default <S> Children selectMax(boolean condition, SFunction<S, ?> column) {
return selectFunc(condition, DefaultFuncEnum.MAX, column);
}
default <S, X> Children selectMax(boolean condition, SFunction<S, ?> column, SFunction<X, ?> alias) {
return selectFunc(condition, DefaultFuncEnum.MAX, column, alias);
}
default <S, X> Children selectMax(boolean condition, SFunction<S, ?> column, String alias) {
return selectFunc(condition, DefaultFuncEnum.MAX, column, alias);
}
/**
* MIN()
*/
@ -235,18 +171,6 @@ public interface Query<Children> extends Serializable {
return selectFunc(DefaultFuncEnum.MIN, column, alias);
}
default <S> Children selectMin(boolean condition, SFunction<S, ?> column) {
return selectFunc(condition, DefaultFuncEnum.MIN, column);
}
default <S, X> Children selectMin(boolean condition, SFunction<S, ?> column, SFunction<X, ?> alias) {
return selectFunc(condition, DefaultFuncEnum.MIN, column, alias);
}
default <S, X> Children selectMin(boolean condition, SFunction<S, ?> column, String alias) {
return selectFunc(condition, DefaultFuncEnum.MIN, column, alias);
}
/**
* MIN()
*/
@ -262,18 +186,6 @@ public interface Query<Children> extends Serializable {
return selectFunc(DefaultFuncEnum.AVG, column, alias);
}
default <S> Children selectAvg(boolean condition, SFunction<S, ?> column) {
return selectFunc(condition, DefaultFuncEnum.AVG, column);
}
default <S, X> Children selectAvg(boolean condition, SFunction<S, ?> column, SFunction<X, ?> alias) {
return selectFunc(condition, DefaultFuncEnum.AVG, column, alias);
}
default <S, X> Children selectAvg(boolean condition, SFunction<S, ?> column, String alias) {
return selectFunc(condition, DefaultFuncEnum.AVG, column, alias);
}
/**
* LEN()
*/
@ -288,16 +200,4 @@ public interface Query<Children> extends Serializable {
default <S, X> Children selectLen(SFunction<S, ?> column, String alias) {
return selectFunc(DefaultFuncEnum.LEN, column, alias);
}
default <S> Children selectLen(boolean condition, SFunction<S, ?> column) {
return selectFunc(condition, DefaultFuncEnum.LEN, column);
}
default <S, X> Children selectLen(boolean condition, SFunction<S, ?> column, SFunction<X, ?> alias) {
return selectFunc(condition, DefaultFuncEnum.LEN, column, alias);
}
default <S, X> Children selectLen(boolean condition, SFunction<S, ?> column, String alias) {
return selectFunc(condition, DefaultFuncEnum.LEN, column, alias);
}
}

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();
@ -235,4 +225,4 @@ public class MybatisLabel<E, T> {
return 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

@ -0,0 +1,104 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-root</artifactId>
<version>1.3.8</version>
</parent>
<version>1.3.8</version>
<artifactId>mybatis-plus-join-test</artifactId>
<name>mybatis-plus-join-test</name>
<description>An enhanced toolkit of Mybatis-Plus to simplify development.</description>
<url>https://github.com/yulichang/mybatis-plus-join</url>
<licenses>
<license>
<name>The Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<developers>
<developer>
<id>mybatis-plus-join</id>
<name>yulichang</name>
<email>yu_lichang@qq.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:https://github.com/yulichang/mybatis-plus-join.git</connection>
<developerConnection>scm:git:https://github.com/yulichang/mybatis-plus-join.git</developerConnection>
<url>https://github.com/yulichang/mybatis-plus-join</url>
</scm>
<properties>
<springboot.version>2.5.4</springboot.version>
<jdkVersion>1.8</jdkVersion>
<jdkVersion.test>1.8</jdkVersion.test>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<github.global.server>github</github.global.server>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${springboot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${springboot.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.1.214</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-boot-starter</artifactId>
<version>1.3.8</version>
</dependency>
<!-- PageHelper 兼容性测试 -->
<!-- <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>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.4</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,48 @@
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);
assert dtos.size() == 1;
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;
}

Some files were not shown because too many files have changed in this diff Show More