mirror of
https://gitee.com/best_handsome/mybatis-plus-join
synced 2025-07-11 00:02:22 +08:00
Merge branch '2.0'
# Conflicts: # README.md # pom.xml
This commit is contained in:
commit
de2e1d8e09
@ -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>
|
||||
|
54
mybatis-plus-join-annotation/pom.xml
Normal file
54
mybatis-plus-join-annotation/pom.xml
Normal 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>
|
@ -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 {
|
@ -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 {
|
@ -7,6 +7,7 @@ package com.github.yulichang.annotation;
|
||||
* @author yulichang
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public @interface MPJMappingApply {
|
||||
|
||||
/**
|
@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.core.enums.SqlKeyword;
|
||||
* @author yulichang
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public @interface MPJMappingCondition {
|
||||
|
||||
/**
|
71
mybatis-plus-join-boot-starter/pom.xml
Normal file
71
mybatis-plus-join-boot-starter/pom.xml
Normal 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>
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
@ -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配置了逻辑删除)."
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.github.yulichang.autoconfigure.MybatisPlusJoinAutoConfiguration
|
77
mybatis-plus-join-core/pom.xml
Normal file
77
mybatis-plus-join-core/pom.xml
Normal 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>
|
@ -0,0 +1,9 @@
|
||||
package com.github.yulichang.config;
|
||||
|
||||
/**
|
||||
* @author yulichang
|
||||
* @since 1.3.7
|
||||
*/
|
||||
public class ConfigProperties {
|
||||
public static boolean subTableLogic = true;
|
||||
}
|
@ -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")
|
@ -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())));
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
@ -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;
|
||||
}
|
@ -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);
|
@ -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;
|
@ -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();
|
@ -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};
|
||||
}
|
||||
}
|
@ -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> {
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -9,7 +9,7 @@ import lombok.Getter;
|
||||
* MPJLambdaWrapper 查询字段
|
||||
*
|
||||
* @author yulichang
|
||||
* @since 1.2.5
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@Getter
|
||||
public class SelectColumn {
|
@ -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;
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
104
mybatis-plus-join-test/pom.xml
Normal file
104
mybatis-plus-join-test/pom.xml
Normal 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>
|
@ -0,0 +1,9 @@
|
||||
package com.github.yulichang.test.collection;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
Loading…
x
Reference in New Issue
Block a user