diff --git a/.gitignore b/.gitignore index a1c2a238a965f004ff76978ac1086aa6fe95caea..3de983acc32b243f2a4dafb8be6c0d6bd8d02c98 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,7 @@ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* +/.idea +/target +/mybatis-plus-boot-starter.iml +/mybatis-plus-spring-boot-starter.iml diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..119b5c8765d6b12c5388db8fb761d045502f4f5e --- /dev/null +++ b/pom.xml @@ -0,0 +1,151 @@ + + + + org.sonatype.oss + oss-parent + 7 + + 4.0.0 + com.baomidou + mybatis-plus-boot-starter + 3.5.2-sb3 + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + mybatis-plus + An enhanced toolkit of Mybatis to simplify development. + https://github.com/baomidou/mybatis-plus + + UTF-8 + UTF-8 + 1.8 + 1.8 + 1.8 + + + + + + org.springframework.boot + spring-boot-dependencies + 2.5.3 + pom + import + + + + + + com.baomidou + mybatis-plus + 3.5.2 + compile + + + org.mybatis + mybatis-spring + 3.0.0 + compile + + + org.springframework.boot + spring-boot-autoconfigure + compile + + + org.springframework.boot + spring-boot-starter-jdbc + compile + + + org.springframework.boot + spring-boot-configuration-processor + compile + true + + + org.springframework.boot + spring-boot-autoconfigure-processor + compile + true + + + org.mybatis.scripting + mybatis-thymeleaf + 1.0.3 + compile + true + + + org.mybatis.scripting + mybatis-velocity + 2.1.1 + compile + true + + + org.mybatis.scripting + mybatis-freemarker + 1.2.3 + compile + true + + + org.springframework.cloud + spring-cloud-commons + 3.0.3 + compile + true + + + org.projectlombok + lombok + 1.18.24 + true + + + + + github Issue + https://github.com/baomidou/mybatis-plus + + + + The Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + + baomidou + hubin + jobob@qq.com + + + + scm:git@github.com:Codearte/gradle-nexus-staging-plugin.git + scm:git@github.com:Codearte/gradle-nexus-staging-plugin.git + https://github.com/baomidou/mybatis-plus + + + + oss + OSS Snapshots Repository + https://oss.sonatype.org/content/repositories/snapshots/ + + + oss + OSS Staging Repository + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + diff --git a/src/main/java/com/baomidou/mybatisplus/autoconfigure/ConfigurationCustomizer.java b/src/main/java/com/baomidou/mybatisplus/autoconfigure/ConfigurationCustomizer.java new file mode 100644 index 0000000000000000000000000000000000000000..1d51bc109a87cd93a7a8e2d094f31333d6ae3aba --- /dev/null +++ b/src/main/java/com/baomidou/mybatisplus/autoconfigure/ConfigurationCustomizer.java @@ -0,0 +1,35 @@ +/* + * 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.baomidou.mybatisplus.autoconfigure; + +import com.baomidou.mybatisplus.core.MybatisConfiguration; + +/** + * Callback interface that can be customized a {@link MybatisConfiguration} object generated on auto-configuration. + * + * @author Kazuki Shimizu + * @since 1.2.1 + */ +@FunctionalInterface +public interface ConfigurationCustomizer { + + /** + * Customize the given a {@link MybatisConfiguration} object. + * + * @param configuration the configuration object to customize + */ + void customize(MybatisConfiguration configuration); +} diff --git a/src/main/java/com/baomidou/mybatisplus/autoconfigure/IdentifierGeneratorAutoConfiguration.java b/src/main/java/com/baomidou/mybatisplus/autoconfigure/IdentifierGeneratorAutoConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..7bbb521b83bfd3b056ffdf64f00abb3f5e1162c1 --- /dev/null +++ b/src/main/java/com/baomidou/mybatisplus/autoconfigure/IdentifierGeneratorAutoConfiguration.java @@ -0,0 +1,62 @@ +/* + * 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.baomidou.mybatisplus.autoconfigure; + +import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator; +import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cloud.commons.util.InetUtils; +import org.springframework.cloud.commons.util.InetUtilsProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; + +/** + * @author nieqiurong 2021/1/29 + * @since 3.4.3 + */ +@Lazy +@Configuration(proxyBeanMethods = false) +@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") +public class IdentifierGeneratorAutoConfiguration { + + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(InetUtils.class) + public static class InetUtilsAutoConfig { + + @Bean + @ConditionalOnMissingBean + public InetUtilsProperties inetUtilsProperties() { + return new InetUtilsProperties(); + } + + @Bean + @ConditionalOnMissingBean + public InetUtils inetUtils(InetUtilsProperties properties) { + return new InetUtils(properties); + } + + @Bean + @ConditionalOnMissingBean + public IdentifierGenerator identifierGenerator(InetUtils inetUtils) { + return new DefaultIdentifierGenerator(inetUtils.findFirstNonLoopbackAddress()); + } + + } + +} diff --git a/src/main/java/com/baomidou/mybatisplus/autoconfigure/MybatisPlusAutoConfiguration.java b/src/main/java/com/baomidou/mybatisplus/autoconfigure/MybatisPlusAutoConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..49ad9c24cb5f671ad01933ad9d887d9889eaa079 --- /dev/null +++ b/src/main/java/com/baomidou/mybatisplus/autoconfigure/MybatisPlusAutoConfiguration.java @@ -0,0 +1,342 @@ +/* + * 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.baomidou.mybatisplus.autoconfigure; + + +import com.baomidou.mybatisplus.core.MybatisConfiguration; +import com.baomidou.mybatisplus.core.config.GlobalConfig; +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator; +import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; +import com.baomidou.mybatisplus.core.injector.ISqlInjector; +import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.mapping.DatabaseIdProvider; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.scripting.LanguageDriver; +import org.apache.ibatis.session.ExecutorType; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.transaction.TransactionFactory; +import org.apache.ibatis.type.TypeHandler; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.SqlSessionTemplate; +import org.mybatis.spring.mapper.MapperFactoryBean; +import org.mybatis.spring.mapper.MapperScannerConfigurer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeanWrapper; +import org.springframework.beans.BeanWrapperImpl; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.boot.autoconfigure.AutoConfigurationPackages; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +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.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +import javax.sql.DataSource; +import java.beans.PropertyDescriptor; +import java.util.*; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * {@link EnableAutoConfiguration Auto-Configuration} for Mybatis. Contributes a + * {@link SqlSessionFactory} and a {@link SqlSessionTemplate}. + *

+ * If {@link org.mybatis.spring.annotation.MapperScan} is used, or a + * configuration file is specified as a property, those will be considered, + * otherwise this auto-configuration will attempt to register mappers based on + * the interface definitions in or under the root auto-configuration package. + *

+ *

copy from {@link org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration}

+ * + * @author Eddú Meléndez + * @author Josh Long + * @author Kazuki Shimizu + * @author Eduardo Macarrón + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class}) +@ConditionalOnSingleCandidate(DataSource.class) +@EnableConfigurationProperties(MybatisPlusProperties.class) +@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisPlusLanguageDriverAutoConfiguration.class}) +public class MybatisPlusAutoConfiguration implements InitializingBean { + + private static final Logger logger = LoggerFactory.getLogger(MybatisPlusAutoConfiguration.class); + + private final MybatisPlusProperties properties; + + private final Interceptor[] interceptors; + + private final TypeHandler[] typeHandlers; + + private final LanguageDriver[] languageDrivers; + + private final ResourceLoader resourceLoader; + + private final DatabaseIdProvider databaseIdProvider; + + private final List configurationCustomizers; + + private final List mybatisPlusPropertiesCustomizers; + + private final ApplicationContext applicationContext; + + + public MybatisPlusAutoConfiguration(MybatisPlusProperties properties, + ObjectProvider interceptorsProvider, + ObjectProvider typeHandlersProvider, + ObjectProvider languageDriversProvider, + ResourceLoader resourceLoader, + ObjectProvider databaseIdProvider, + ObjectProvider> configurationCustomizersProvider, + ObjectProvider> mybatisPlusPropertiesCustomizerProvider, + ApplicationContext applicationContext) { + this.properties = properties; + this.interceptors = interceptorsProvider.getIfAvailable(); + this.typeHandlers = typeHandlersProvider.getIfAvailable(); + this.languageDrivers = languageDriversProvider.getIfAvailable(); + this.resourceLoader = resourceLoader; + this.databaseIdProvider = databaseIdProvider.getIfAvailable(); + this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable(); + this.mybatisPlusPropertiesCustomizers = mybatisPlusPropertiesCustomizerProvider.getIfAvailable(); + this.applicationContext = applicationContext; + } + + @Override + public void afterPropertiesSet() { + if (!CollectionUtils.isEmpty(mybatisPlusPropertiesCustomizers)) { + mybatisPlusPropertiesCustomizers.forEach(i -> i.customize(properties)); + } + checkConfigFileExists(); + } + + private void checkConfigFileExists() { + if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) { + Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation()); + Assert.state(resource.exists(), + "Cannot find config location: " + resource + " (please add config file or check your Mybatis configuration)"); + } + } + + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") + @Bean + @ConditionalOnMissingBean + public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { + // TODO 使用 MybatisSqlSessionFactoryBean 而不是 SqlSessionFactoryBean + MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean(); + factory.setDataSource(dataSource); + factory.setVfs(SpringBootVFS.class); + if (StringUtils.hasText(this.properties.getConfigLocation())) { + factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation())); + } + applyConfiguration(factory); + if (this.properties.getConfigurationProperties() != null) { + factory.setConfigurationProperties(this.properties.getConfigurationProperties()); + } + if (!ObjectUtils.isEmpty(this.interceptors)) { + factory.setPlugins(this.interceptors); + } + if (this.databaseIdProvider != null) { + factory.setDatabaseIdProvider(this.databaseIdProvider); + } + if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) { + factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage()); + } + if (this.properties.getTypeAliasesSuperType() != null) { + factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType()); + } + if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) { + factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage()); + } + if (!ObjectUtils.isEmpty(this.typeHandlers)) { + factory.setTypeHandlers(this.typeHandlers); + } + Resource[] mapperLocations = this.properties.resolveMapperLocations(); + if (!ObjectUtils.isEmpty(mapperLocations)) { + factory.setMapperLocations(mapperLocations); + } + // TODO 修改源码支持定义 TransactionFactory + this.getBeanThen(TransactionFactory.class, factory::setTransactionFactory); + + // TODO 对源码做了一定的修改(因为源码适配了老旧的mybatis版本,但我们不需要适配) + Class defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver(); + if (!ObjectUtils.isEmpty(this.languageDrivers)) { + factory.setScriptingLanguageDrivers(this.languageDrivers); + } + Optional.ofNullable(defaultLanguageDriver).ifPresent(factory::setDefaultScriptingLanguageDriver); + + // TODO 自定义枚举包 + if (StringUtils.hasLength(this.properties.getTypeEnumsPackage())) { + factory.setTypeEnumsPackage(this.properties.getTypeEnumsPackage()); + } + // TODO 此处必为非 NULL + GlobalConfig globalConfig = this.properties.getGlobalConfig(); + // TODO 注入填充器 + this.getBeanThen(MetaObjectHandler.class, globalConfig::setMetaObjectHandler); + // TODO 注入主键生成器 + this.getBeansThen(IKeyGenerator.class, i -> globalConfig.getDbConfig().setKeyGenerators(i)); + // TODO 注入sql注入器 + this.getBeanThen(ISqlInjector.class, globalConfig::setSqlInjector); + // TODO 注入ID生成器 + this.getBeanThen(IdentifierGenerator.class, globalConfig::setIdentifierGenerator); + // TODO 设置 GlobalConfig 到 MybatisSqlSessionFactoryBean + factory.setGlobalConfig(globalConfig); + return factory.getObject(); + } + + /** + * 检查spring容器里是否有对应的bean,有则进行消费 + * + * @param clazz class + * @param consumer 消费 + * @param 泛型 + */ + private void getBeanThen(Class clazz, Consumer consumer) { + if (this.applicationContext.getBeanNamesForType(clazz, false, false).length > 0) { + consumer.accept(this.applicationContext.getBean(clazz)); + } + } + + /** + * 检查spring容器里是否有对应的bean,有则进行消费 + * + * @param clazz class + * @param consumer 消费 + * @param 泛型 + */ + private void getBeansThen(Class clazz, Consumer> consumer) { + if (this.applicationContext.getBeanNamesForType(clazz, false, false).length > 0) { + final Map beansOfType = this.applicationContext.getBeansOfType(clazz); + List clazzList = new ArrayList<>(); + beansOfType.forEach((k, v) -> clazzList.add(v)); + consumer.accept(clazzList); + } + } + + // TODO 入参使用 MybatisSqlSessionFactoryBean + private void applyConfiguration(MybatisSqlSessionFactoryBean factory) { + // TODO 使用 MybatisConfiguration + MybatisConfiguration configuration = this.properties.getConfiguration(); + if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) { + configuration = new MybatisConfiguration(); + } + if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) { + for (ConfigurationCustomizer customizer : this.configurationCustomizers) { + customizer.customize(configuration); + } + } + factory.setConfiguration(configuration); + } + + @Bean + @ConditionalOnMissingBean + public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { + ExecutorType executorType = this.properties.getExecutorType(); + if (executorType != null) { + return new SqlSessionTemplate(sqlSessionFactory, executorType); + } else { + return new SqlSessionTemplate(sqlSessionFactory); + } + } + + + /** + * This will just scan the same base package as Spring Boot does. If you want more power, you can explicitly use + * {@link org.mybatis.spring.annotation.MapperScan} but this will get typed mappers working correctly, out-of-the-box, + * similar to using Spring Data JPA repositories. + */ + public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, ImportBeanDefinitionRegistrar { + + private BeanFactory beanFactory; + + @Override + public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { + + if (!AutoConfigurationPackages.has(this.beanFactory)) { + logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled."); + return; + } + + logger.debug("Searching for mappers annotated with @Mapper"); + + List packages = AutoConfigurationPackages.get(this.beanFactory); + if (logger.isDebugEnabled()) { + packages.forEach(pkg -> logger.debug("Using auto-configuration base package '{}'", pkg)); + } + + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class); + builder.addPropertyValue("processPropertyPlaceHolders", true); + builder.addPropertyValue("annotationClass", Mapper.class); + builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages)); + BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class); + Set propertyNames = Stream.of(beanWrapper.getPropertyDescriptors()).map(PropertyDescriptor::getName) + .collect(Collectors.toSet()); + if (propertyNames.contains("lazyInitialization")) { + // Need to mybatis-spring 2.0.2+ + // TODO 兼容了mybatis.lazy-initialization配置 + builder.addPropertyValue("lazyInitialization", "${mybatis-plus.lazy-initialization:${mybatis.lazy-initialization:false}}"); + } + if (propertyNames.contains("defaultScope")) { + // Need to mybatis-spring 2.0.6+ + builder.addPropertyValue("defaultScope", "${mybatis-plus.mapper-default-scope:}"); + } + registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition()); + } + + @Override + public void setBeanFactory(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + } + + /** + * If mapper registering configuration or mapper scanning configuration not present, this configuration allow to scan + * mappers based on the same component-scanning path as Spring Boot itself. + */ + @Configuration(proxyBeanMethods = false) + @Import(AutoConfiguredMapperScannerRegistrar.class) + @ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.class}) + public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean { + + @Override + public void afterPropertiesSet() { + logger.debug( + "Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer."); + } + } +} diff --git a/src/main/java/com/baomidou/mybatisplus/autoconfigure/MybatisPlusLanguageDriverAutoConfiguration.java b/src/main/java/com/baomidou/mybatisplus/autoconfigure/MybatisPlusLanguageDriverAutoConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..51a0b170739bab6f2cd79ab753bc2e887cafb0bc --- /dev/null +++ b/src/main/java/com/baomidou/mybatisplus/autoconfigure/MybatisPlusLanguageDriverAutoConfiguration.java @@ -0,0 +1,139 @@ +/* + * 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.baomidou.mybatisplus.autoconfigure; + +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.scripting.MybatisFreeMarkerLanguageDriver; +import com.baomidou.mybatisplus.extension.scripting.MybatisThymeleafLanguageDriver; +import com.baomidou.mybatisplus.extension.scripting.MybatisVelocityLanguageDriver; +import org.apache.ibatis.scripting.LanguageDriver; +import org.mybatis.scripting.freemarker.FreeMarkerLanguageDriver; +import org.mybatis.scripting.freemarker.FreeMarkerLanguageDriverConfig; +import org.mybatis.scripting.thymeleaf.ThymeleafLanguageDriver; +import org.mybatis.scripting.thymeleaf.ThymeleafLanguageDriverConfig; +import org.mybatis.scripting.velocity.VelocityLanguageDriver; +import org.mybatis.scripting.velocity.VelocityLanguageDriverConfig; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; + +/** + * {@link EnableAutoConfiguration Auto-Configuration} for MyBatis's scripting language drivers. + *

copy from {@link org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration}

+ * + * @author miemie + * @since 2019-10-22 + */ +@Lazy +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass(LanguageDriver.class) +public class MybatisPlusLanguageDriverAutoConfiguration { + + private static final String CONFIGURATION_PROPERTY_PREFIX = Constants.MYBATIS_PLUS + ".scripting-language-driver"; + + /** + * Configuration class for mybatis-freemarker 1.1.x or under. + */ + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(FreeMarkerLanguageDriver.class) + @ConditionalOnMissingClass("org.mybatis.scripting.freemarker.FreeMarkerLanguageDriverConfig") + public static class LegacyFreeMarkerConfiguration { + @Bean + @ConditionalOnMissingBean + FreeMarkerLanguageDriver freeMarkerLanguageDriver() { + return new MybatisFreeMarkerLanguageDriver(); + } + } + + /** + * Configuration class for mybatis-freemarker 1.2.x or above. + */ + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass({FreeMarkerLanguageDriver.class, FreeMarkerLanguageDriverConfig.class}) + public static class FreeMarkerConfiguration { + @Bean + @ConditionalOnMissingBean + FreeMarkerLanguageDriver freeMarkerLanguageDriver(FreeMarkerLanguageDriverConfig config) { + return new MybatisFreeMarkerLanguageDriver(config); + } + + @Bean + @ConditionalOnMissingBean + @ConfigurationProperties(CONFIGURATION_PROPERTY_PREFIX + ".freemarker") + public FreeMarkerLanguageDriverConfig freeMarkerLanguageDriverConfig() { + return FreeMarkerLanguageDriverConfig.newInstance(); + } + } + + /** + * Configuration class for mybatis-velocity 2.1.x or above. + */ + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass({VelocityLanguageDriver.class, VelocityLanguageDriverConfig.class}) + public static class VelocityConfiguration { + @Bean + @ConditionalOnMissingBean + VelocityLanguageDriver velocityLanguageDriver(VelocityLanguageDriverConfig config) { + return new MybatisVelocityLanguageDriver(config); + } + + @Bean + @ConditionalOnMissingBean + @ConfigurationProperties(CONFIGURATION_PROPERTY_PREFIX + ".velocity") + public VelocityLanguageDriverConfig velocityLanguageDriverConfig() { + return VelocityLanguageDriverConfig.newInstance(); + } + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(ThymeleafLanguageDriver.class) + public static class ThymeleafConfiguration { + @Bean + @ConditionalOnMissingBean + ThymeleafLanguageDriver thymeleafLanguageDriver(ThymeleafLanguageDriverConfig config) { + return new MybatisThymeleafLanguageDriver(config); + } + + @Bean + @ConditionalOnMissingBean + @ConfigurationProperties(CONFIGURATION_PROPERTY_PREFIX + ".thymeleaf") + public ThymeleafLanguageDriverConfig thymeleafLanguageDriverConfig() { + return ThymeleafLanguageDriverConfig.newInstance(); + } + + // This class provides to avoid the https://github.com/spring-projects/spring-boot/issues/21626 as workaround. + @SuppressWarnings("unused") + private static class MetadataThymeleafLanguageDriverConfig extends ThymeleafLanguageDriverConfig { + + @ConfigurationProperties(CONFIGURATION_PROPERTY_PREFIX + ".thymeleaf.dialect") + @Override + public DialectConfig getDialect() { + return super.getDialect(); + } + + @ConfigurationProperties(CONFIGURATION_PROPERTY_PREFIX + ".thymeleaf.template-file") + @Override + public TemplateFileConfig getTemplateFile() { + return super.getTemplateFile(); + } + } + } +} diff --git a/src/main/java/com/baomidou/mybatisplus/autoconfigure/MybatisPlusProperties.java b/src/main/java/com/baomidou/mybatisplus/autoconfigure/MybatisPlusProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..a87dd61e55f4ef1c5d917877c9728ec5e8899be3 --- /dev/null +++ b/src/main/java/com/baomidou/mybatisplus/autoconfigure/MybatisPlusProperties.java @@ -0,0 +1,132 @@ +/* + * 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.baomidou.mybatisplus.autoconfigure; + +import com.baomidou.mybatisplus.core.MybatisConfiguration; +import com.baomidou.mybatisplus.core.config.GlobalConfig; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils; +import lombok.Data; +import lombok.experimental.Accessors; +import org.apache.ibatis.scripting.LanguageDriver; +import org.apache.ibatis.session.ExecutorType; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.NestedConfigurationProperty; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; + +import java.io.IOException; +import java.util.Optional; +import java.util.Properties; +import java.util.stream.Stream; + +/** + * Configuration properties for MyBatis. + * + * @author Eddú Meléndez + * @author Kazuki Shimizu + */ +@Data +@Accessors(chain = true) +@ConfigurationProperties(prefix = Constants.MYBATIS_PLUS) +public class MybatisPlusProperties { + + private static final ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); + + /** + * Location of MyBatis xml config file. + */ + private String configLocation; + + /** + * Locations of MyBatis mapper files. + * + * @since 3.1.2 add default value + */ + private String[] mapperLocations = new String[]{"classpath*:/mapper/**/*.xml"}; + + /** + * Packages to search type aliases. (Package delimiters are ",; \t\n") + */ + private String typeAliasesPackage; + + /** + * The super class for filtering type alias. + * If this not specifies, the MyBatis deal as type alias all classes that searched from typeAliasesPackage. + */ + private Class typeAliasesSuperType; + + /** + * Packages to search for type handlers. (Package delimiters are ",; \t\n") + */ + private String typeHandlersPackage; + + /** + * Indicates whether perform presence check of the MyBatis xml config file. + */ + private boolean checkConfigLocation = false; + + /** + * Execution mode for {@link org.mybatis.spring.SqlSessionTemplate}. + */ + private ExecutorType executorType; + + /** + * The default scripting language driver class. (Available when use together with mybatis-spring 2.0.2+) + *

+ * 如果设置了这个,你会至少失去几乎所有 mp 提供的功能 + */ + private Class defaultScriptingLanguageDriver; + + /** + * Externalized properties for MyBatis configuration. + */ + private Properties configurationProperties; + + /** + * A Configuration object for customize default settings. If {@link #configLocation} + * is specified, this property is not used. + * TODO 使用 MybatisConfiguration + */ + @NestedConfigurationProperty + private MybatisConfiguration configuration; + + /** + * TODO 枚举包扫描 + */ + private String typeEnumsPackage; + + /** + * TODO 全局配置 + */ + @NestedConfigurationProperty + private GlobalConfig globalConfig = GlobalConfigUtils.defaults(); + + + public Resource[] resolveMapperLocations() { + return Stream.of(Optional.ofNullable(this.mapperLocations).orElse(new String[0])) + .flatMap(location -> Stream.of(getResources(location))).toArray(Resource[]::new); + } + + private Resource[] getResources(String location) { + try { + return resourceResolver.getResources(location); + } catch (IOException e) { + return new Resource[0]; + } + } +} diff --git a/src/main/java/com/baomidou/mybatisplus/autoconfigure/MybatisPlusPropertiesCustomizer.java b/src/main/java/com/baomidou/mybatisplus/autoconfigure/MybatisPlusPropertiesCustomizer.java new file mode 100644 index 0000000000000000000000000000000000000000..c96c3e3a55380c8822e2190c58ef71f2b352f991 --- /dev/null +++ b/src/main/java/com/baomidou/mybatisplus/autoconfigure/MybatisPlusPropertiesCustomizer.java @@ -0,0 +1,35 @@ +/* + * 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.baomidou.mybatisplus.autoconfigure; + +/** + * Callback interface that can be customized a {@link MybatisPlusProperties} object generated on auto-configuration. + * + *

慎用

+ * + * @author miemie + * @since 3.1.2 + */ +@FunctionalInterface +public interface MybatisPlusPropertiesCustomizer { + + /** + * Customize the given a {@link MybatisPlusProperties} object. + * + * @param properties the MybatisPlusProperties object to customize + */ + void customize(MybatisPlusProperties properties); +} diff --git a/src/main/java/com/baomidou/mybatisplus/autoconfigure/SafetyEncryptProcessor.java b/src/main/java/com/baomidou/mybatisplus/autoconfigure/SafetyEncryptProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..9a55e67f1571745afb966cf32d2286ab5136e7bc --- /dev/null +++ b/src/main/java/com/baomidou/mybatisplus/autoconfigure/SafetyEncryptProcessor.java @@ -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.baomidou.mybatisplus.autoconfigure; + +import com.baomidou.mybatisplus.core.toolkit.AES; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.boot.env.OriginTrackedMapPropertySource; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; +import org.springframework.core.env.SimpleCommandLinePropertySource; + +import java.util.HashMap; + +/** + * 安全加密处理器 + * + * @author hubin + * @since 2020-05-23 + */ +public class SafetyEncryptProcessor implements EnvironmentPostProcessor { + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { + /** + * 命令行中获取密钥 + */ + String mpwKey = null; + for (PropertySource ps : environment.getPropertySources()) { + if (ps instanceof SimpleCommandLinePropertySource) { + SimpleCommandLinePropertySource source = (SimpleCommandLinePropertySource) ps; + mpwKey = source.getProperty("mpw.key"); + break; + } + } + /** + * 处理加密内容 + */ + if (StringUtils.isNotBlank(mpwKey)) { + HashMap map = new HashMap<>(); + for (PropertySource ps : environment.getPropertySources()) { + if (ps instanceof OriginTrackedMapPropertySource) { + OriginTrackedMapPropertySource source = (OriginTrackedMapPropertySource) ps; + for (String name : source.getPropertyNames()) { + Object value = source.getProperty(name); + if (value instanceof String) { + String str = (String) value; + if (str.startsWith("mpw:")) { + map.put(name, AES.decrypt(str.substring(4), mpwKey)); + } + } + } + } + } + // 将解密的数据放入环境变量,并处于第一优先级上 + if (CollectionUtils.isNotEmpty(map)) { + environment.getPropertySources().addFirst(new MapPropertySource("custom-encrypt", map)); + } + } + } +} diff --git a/src/main/java/com/baomidou/mybatisplus/autoconfigure/SpringBootVFS.java b/src/main/java/com/baomidou/mybatisplus/autoconfigure/SpringBootVFS.java new file mode 100644 index 0000000000000000000000000000000000000000..3da2d82dc64bfa2041b151f85a17d78334ebee34 --- /dev/null +++ b/src/main/java/com/baomidou/mybatisplus/autoconfigure/SpringBootVFS.java @@ -0,0 +1,68 @@ +/* + * 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.baomidou.mybatisplus.autoconfigure; + + +import com.baomidou.mybatisplus.core.toolkit.StringPool; +import org.apache.ibatis.io.VFS; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URL; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * @author Hans Westerbeek + * @author Eddú Meléndez + * @author Kazuki Shimizu + */ +public class SpringBootVFS extends VFS { + + private final ResourcePatternResolver resourceResolver; + + public SpringBootVFS() { + this.resourceResolver = new PathMatchingResourcePatternResolver(getClass().getClassLoader()); + } + + @Override + public boolean isValid() { + return true; + } + + private static String preserveSubpackageName(final String baseUrlString, final Resource resource, + final String rootPath) { + try { + return rootPath + (rootPath.endsWith(StringPool.SLASH) ? StringPool.EMPTY : StringPool.SLASH) + + resource.getURL().toString().substring(baseUrlString.length()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + @Override + protected List list(URL url, String path) throws IOException { + String urlString = url.toString(); + String baseUrlString = urlString.endsWith(StringPool.SLASH) ? urlString : urlString.concat(StringPool.SLASH); + Resource[] resources = resourceResolver.getResources(baseUrlString + "**/*.class"); + return Stream.of(resources).map(resource -> preserveSubpackageName(baseUrlString, resource, path)) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/baomidou/mybatisplus/autoconfigure/package-info.java b/src/main/java/com/baomidou/mybatisplus/autoconfigure/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..4afc6e7803edce5871f955dc3f9e87ac92152fa4 --- /dev/null +++ b/src/main/java/com/baomidou/mybatisplus/autoconfigure/package-info.java @@ -0,0 +1,19 @@ +/* + * 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. + */ +/** + * Spring Boot Stater + */ +package com.baomidou.mybatisplus.autoconfigure; diff --git a/src/main/java/org/springframework/core/NestedIOException.java b/src/main/java/org/springframework/core/NestedIOException.java new file mode 100644 index 0000000000000000000000000000000000000000..2123804fcc47a12e7cbd7b1b5602dea0b5a5cc70 --- /dev/null +++ b/src/main/java/org/springframework/core/NestedIOException.java @@ -0,0 +1,25 @@ +package org.springframework.core; + +import org.springframework.core.NestedExceptionUtils; +import org.springframework.lang.Nullable; + +import java.io.IOException; + +public class NestedIOException extends IOException { + public NestedIOException(String msg) { + super(msg); + } + + public NestedIOException(@Nullable String msg, @Nullable Throwable cause) { + super(msg, cause); + } + + @Nullable + public String getMessage() { + return NestedExceptionUtils.buildMessage(super.getMessage(), this.getCause()); + } + + static { + NestedExceptionUtils.class.getName(); + } +} diff --git a/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 0000000000000000000000000000000000000000..93b2f962a608df94a4643822c5557ac9c5bd1b7d --- /dev/null +++ b/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,100 @@ +{ + "groups": [ + { + "sourceType": "com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties", + "name": "mybatis-plus", + "type": "com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties" + }, + { + "sourceType": "com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties", + "name": "mybatis-plus.configuration", + "sourceMethod": "getConfiguration()", + "type": "com.baomidou.mybatisplus.core.MybatisConfiguration" + }, + { + "sourceType": "com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties", + "name": "mybatis-plus.global-config", + "sourceMethod": "getGlobalConfig()", + "type": "com.baomidou.mybatisplus.core.config.GlobalConfig" + }, + { + "sourceType": "com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig", + "name": "mybatis-plus.global-config.db-config", + "sourceMethod": "getDbConfig()", + "type": "com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig" + } + ], + "properties": [ + { + "defaultValue": false, + "name": "mybatis-plus.lazy-initialization", + "description": "Set whether enable lazy initialization for mapper bean.", + "type": "java.lang.Boolean" + }, + { + "defaultValue": "", + "name": "mybatis-plus.mapper-default-scope", + "description": "A default scope for mapper bean that scanned by auto-configure.", + "type": "java.lang.String" + }, + { + "sourceType": "com.baomidou.mybatisplus.core.config.GlobalConfig", + "name": "mybatis-plus.global-config.identifier-generator", + "deprecation": { + "level": "error", + "reason": "请使用@Bean的方式注入至Spring容器." + } + }, + { + "sourceType": "com.baomidou.mybatisplus.core.config.GlobalConfig", + "name": "mybatis-plus.global-config.meta-object-handler", + "deprecation": { + "level": "error", + "reason": "3.0开始废除此属性,请使用@Bean的方式注入至Spring容器." + } + }, + { + "sourceType": "com.baomidou.mybatisplus.core.config.GlobalConfig", + "name": "mybatis-plus.global-config.sql-injector", + "deprecation": { + "level": "error", + "reason": "3.0开始废除此属性,请使用@Bean的方式注入至Spring容器." + } + }, + { + "sourceType": "com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig", + "name": "mybatis-plus.global-config.db-config.key-generator", + "deprecation": { + "level": "error", + "reason": "3.0开始废除此属性,请使用@Bean的方式注入至Spring容器." + } + }, + { + "sourceType": "com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties", + "name": "mybatis-plus.default-scripting-language-driver", + "defaultValue": "com.baomidou.mybatisplus.core.MybatisXMLLanguageDriver", + "type": "java.lang.Class", + "deprecation": { + "level": "error", + "reason": "如果修改了该值,你会至少失去几乎所有 mp 提供的功能." + } + }, + { + "sourceType": "com.baomidou.mybatisplus.core.MybatisConfiguration", + "name": "mybatis-plus.configuration.default-scripting-language", + "defaultValue": "com.baomidou.mybatisplus.core.MybatisXMLLanguageDriver", + "type": "java.lang.Class", + "deprecation": { + "level": "error", + "reason": "设置无效." + } + }, + { + "sourceType": "com.baomidou.mybatisplus.core.MybatisConfiguration", + "name": "mybatis-plus.configuration.default-enum-type-handler", + "defaultValue": "org.apache.ibatis.type.EnumTypeHandler", + "description": "A default TypeHandler class for Enum.", + "type": "java.lang.Class" + } + ] +} diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000000000000000000000000000000000000..2e54e91bd3b1348f6b5f1d948cf240d795384324 --- /dev/null +++ b/src/main/resources/META-INF/spring.factories @@ -0,0 +1,7 @@ +# Auto Configure +org.springframework.boot.env.EnvironmentPostProcessor=\ + com.baomidou.mybatisplus.autoconfigure.SafetyEncryptProcessor +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.baomidou.mybatisplus.autoconfigure.IdentifierGeneratorAutoConfiguration,\ + com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration,\ + com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration diff --git a/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000000000000000000000000000000000000..ed14b5feceedc85c56bece20f53d08414b7a22c6 --- /dev/null +++ b/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,3 @@ +com.baomidou.mybatisplus.autoconfigure.IdentifierGeneratorAutoConfiguration +com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration +com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration