!536 feat:新增 loveqq-framework 框架下的启动器

Merge pull request !536 from kfyty/main
This commit is contained in:
Michael Yang 2025-03-31 03:01:48 +00:00 committed by Gitee
commit 65b1161651
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
119 changed files with 8031 additions and 0 deletions

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<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.mybatis-flex</groupId>
<artifactId>parent</artifactId>
<version>1.10.9</version>
</parent>
<artifactId>mybatis-flex-loveqq-starter</artifactId>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.kfyty</groupId>
<artifactId>loveqq-boot-starter-mybatis</artifactId>
<version>${loveqq.version}</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-core</artifactId>
<version>${mybatis-flex.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2022-2024, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.framework.boot.autoconfig;
import com.kfyty.loveqq.framework.boot.data.orm.mybatis.autoconfig.SqlSessionFactoryBean;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Autowired;
import com.kfyty.loveqq.framework.core.event.ContextRefreshedEvent;
import com.kfyty.loveqq.framework.core.support.Pair;
import com.mybatisflex.core.FlexConsts;
import com.mybatisflex.core.datasource.FlexDataSource;
import com.mybatisflex.core.mybatis.FlexConfiguration;
import com.mybatisflex.core.mybatis.FlexSqlSessionFactoryBuilder;
import com.mybatisflex.loveqq.framework.boot.autoconfig.transaction.FlexTransactionFactory;
import org.apache.ibatis.builder.xml.XMLConfigBuilder;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
/**
* <p>源于 {@link SqlSessionFactoryBean}主要是用于构建 {@link com.mybatisflex.core.mybatis.FlexConfiguration }而不是使用原生的 {@link Configuration}
*
* @author kfyty725
*/
public class FlexSqlSessionFactoryBean extends SqlSessionFactoryBean {
@Autowired
private MybatisFlexProperties mybatisFlexProperties;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// nothing
}
@Override
protected Class<? extends Configuration> obtainConfigurationClass() {
return FlexConfiguration.class;
}
@Override
protected Pair<Configuration, XMLConfigBuilder> buildConfiguration() {
Pair<Configuration, XMLConfigBuilder> configPair = super.buildConfiguration();
MybatisFlexProperties.CoreConfiguration coreConfiguration = this.mybatisFlexProperties.getConfiguration();
if (coreConfiguration != null && coreConfiguration.getDefaultEnumTypeHandler() != null) {
configPair.getKey().setDefaultEnumTypeHandler(coreConfiguration.getDefaultEnumTypeHandler());
}
return configPair;
}
@Override
protected void buildEnvironment(Configuration configuration) {
FlexDataSource flexDataSource;
if (this.getDataSource() instanceof FlexDataSource) {
flexDataSource = (FlexDataSource) this.getDataSource();
} else {
flexDataSource = new FlexDataSource(FlexConsts.NAME, this.getDataSource());
}
configuration.setEnvironment(
new Environment(
FlexConsts.NAME,
this.getTransactionFactory() == null ? new FlexTransactionFactory() : this.getTransactionFactory(),
flexDataSource
)
);
}
@Override
protected void buildMapperLocations(Configuration configuration) {
// mybatis-flex 要延迟加载
}
/**
* 需先构建 sqlSessionFactory再去初始化 mapperLocations
* 因为 xmlMapperBuilder.parse() 用到 FlexGlobalConfig FlexGlobalConfig 的初始化是在 sqlSessionFactory 的构建方法里进行的
* fixed https://gitee.com/mybatis-flex/mybatis-flex/issues/I6X59V
*/
@Override
protected SqlSessionFactory build(Configuration configuration) {
SqlSessionFactory sqlSessionFactory = new FlexSqlSessionFactoryBuilder().build(configuration);
super.buildMapperLocations(configuration);
return sqlSessionFactory;
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.framework.boot.autoconfig;
import com.kfyty.loveqq.framework.core.autoconfig.InitializingBean;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Autowired;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Component;
import com.kfyty.loveqq.framework.core.autoconfig.condition.annotation.ConditionalOnProperty;
import com.mybatisflex.core.audit.AuditManager;
import com.mybatisflex.core.audit.MessageFactory;
import com.mybatisflex.core.audit.MessageReporter;
import com.mybatisflex.core.audit.http.HttpMessageReporter;
/**
* MyBatis-Flex-Admin 自动配置
*
* @author 王帅
* @author kfyty725
* @since 2023-07-01
*/
@Component
@ConditionalOnProperty(prefix = "mybatis-flex.adminConfig", value = "enable", havingValue = "true")
public class MybatisFlexAdminAutoConfiguration implements InitializingBean {
@Autowired(required = false)
private MessageFactory messageFactory;
@Autowired(required = false)
private MybatisFlexProperties properties;
@Autowired(required = false)
private HttpMessageReporter.JSONFormatter jsonFormatter;
@Override
public void afterPropertiesSet() {
AuditManager.setAuditEnable(true);
if (messageFactory != null) {
AuditManager.setMessageFactory(messageFactory);
}
MybatisFlexProperties.AdminConfig adminConfig = properties.getAdminConfig();
MessageReporter messageReporter = new HttpMessageReporter(
adminConfig.getEndpoint(),
adminConfig.getSecretKey(),
jsonFormatter
);
AuditManager.setMessageReporter(messageReporter);
}
}

View File

@ -0,0 +1,263 @@
/*
* Copyright (c) 2022-2024, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.framework.boot.autoconfig;
import com.kfyty.loveqq.framework.aop.Advisor;
import com.kfyty.loveqq.framework.aop.support.annotated.AnnotationPointcutAdvisor;
import com.kfyty.loveqq.framework.boot.data.orm.mybatis.autoconfig.MybatisProperties;
import com.kfyty.loveqq.framework.boot.data.orm.mybatis.autoconfig.SqlSessionFactoryBean;
import com.kfyty.loveqq.framework.core.autoconfig.InitializingBean;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Autowired;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Bean;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Configuration;
import com.kfyty.loveqq.framework.core.autoconfig.condition.annotation.ConditionalOnMissingBean;
import com.kfyty.loveqq.framework.core.exception.ResolvableException;
import com.kfyty.loveqq.framework.core.utils.IOUtil;
import com.mybatisflex.annotation.UseDataSource;
import com.mybatisflex.core.FlexGlobalConfig;
import com.mybatisflex.core.datasource.DataSourceBuilder;
import com.mybatisflex.core.datasource.DataSourceDecipher;
import com.mybatisflex.core.datasource.DataSourceManager;
import com.mybatisflex.core.datasource.FlexDataSource;
import com.mybatisflex.core.exception.FlexExceptions;
import com.mybatisflex.core.logicdelete.LogicDeleteManager;
import com.mybatisflex.core.logicdelete.LogicDeleteProcessor;
import com.mybatisflex.core.mybatis.FlexConfiguration;
import com.mybatisflex.core.table.DynamicSchemaProcessor;
import com.mybatisflex.core.table.DynamicTableProcessor;
import com.mybatisflex.core.table.TableManager;
import com.mybatisflex.core.tenant.TenantFactory;
import com.mybatisflex.core.tenant.TenantManager;
import com.mybatisflex.core.util.MapUtil;
import com.mybatisflex.loveqq.framework.boot.autoconfig.annotation.ConditionalOnMybatisFlexDatasource;
import com.mybatisflex.loveqq.framework.boot.autoconfig.customize.ConfigurationCustomizer;
import com.mybatisflex.loveqq.framework.boot.autoconfig.customize.MyBatisFlexCustomizer;
import com.mybatisflex.loveqq.framework.boot.autoconfig.datasource.DataSourceInterceptor;
import com.mybatisflex.loveqq.framework.boot.autoconfig.transaction.FlexTransactionFactory;
import com.mybatisflex.loveqq.framework.boot.autoconfig.transaction.FlexTransactionManager;
import org.apache.ibatis.transaction.TransactionFactory;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
/**
* Mybatis-Flex 的核心配置
*
* @author kfyty725
*/
@Configuration
public class MybatisFlexAutoConfiguration implements InitializingBean {
@Autowired
protected MybatisProperties mybatisProperties;
@Autowired
protected MybatisFlexProperties mybatisFlexProperties;
/**
* 数据源解密器
*/
@Autowired(required = false)
protected DataSourceDecipher dataSourceDecipher;
/**
* 动态表名
*/
@Autowired(required = false)
protected DynamicTableProcessor dynamicTableProcessor;
/**
* 动态 schema 处理器
*/
@Autowired(required = false)
protected DynamicSchemaProcessor dynamicSchemaProcessor;
/**
* 多租户
*/
@Autowired(required = false)
protected TenantFactory tenantFactory;
/**
* 自定义逻辑删除处理器
*/
@Autowired(required = false)
protected LogicDeleteProcessor logicDeleteProcessor;
/**
* 配置监听
*/
@Autowired(required = false)
protected List<ConfigurationCustomizer> configurationCustomizers;
/**
* 初始化监听
*/
@Autowired(required = false)
protected List<MyBatisFlexCustomizer> mybatisFlexCustomizers;
@Override
public void afterPropertiesSet() {
// 检测 MyBatis 原生配置文件是否存在
this.checkConfigFileExists();
// 添加 MyBatis-Flex 全局配置
if (mybatisFlexProperties.getGlobalConfig() != null) {
mybatisFlexProperties.getGlobalConfig().applyTo(FlexGlobalConfig.getDefaultConfig());
}
//数据源解密器
if (dataSourceDecipher != null) {
DataSourceManager.setDecipher(dataSourceDecipher);
}
// 动态表名配置
if (dynamicTableProcessor != null) {
TableManager.setDynamicTableProcessor(dynamicTableProcessor);
}
// 动态 schema 处理器配置
if (dynamicSchemaProcessor != null) {
TableManager.setDynamicSchemaProcessor(dynamicSchemaProcessor);
}
//多租户
if (tenantFactory != null) {
TenantManager.setTenantFactory(tenantFactory);
}
//逻辑删除处理器
if (logicDeleteProcessor != null) {
LogicDeleteManager.setProcessor(logicDeleteProcessor);
}
//初始化监听器
if (mybatisFlexCustomizers != null) {
mybatisFlexCustomizers.forEach(myBatisFlexCustomizer -> myBatisFlexCustomizer.customize(FlexGlobalConfig.getDefaultConfig()));
}
}
@ConditionalOnMybatisFlexDatasource
@Bean(resolveNested = false, independent = true)
public DataSource flexDataSource() {
FlexDataSource flexDataSource = null;
Map<String, Map<String, String>> dataSourceProperties = this.mybatisFlexProperties.getDatasource();
if (dataSourceDecipher != null) {
DataSourceManager.setDecipher(dataSourceDecipher);
}
if (this.mybatisFlexProperties.getDefaultDatasourceKey() != null) {
Map<String, String> map = dataSourceProperties.remove(this.mybatisFlexProperties.getDefaultDatasourceKey());
if (map != null) {
flexDataSource = this.addDataSource(MapUtil.entry(this.mybatisFlexProperties.getDefaultDatasourceKey(), map), flexDataSource);
} else {
throw FlexExceptions.wrap("没有找到默认数据源 \"%s\" 对应的配置,请检查您的多数据源配置。", this.mybatisFlexProperties.getDefaultDatasourceKey());
}
}
for (Map.Entry<String, Map<String, String>> entry : dataSourceProperties.entrySet()) {
flexDataSource = this.addDataSource(entry, flexDataSource);
}
return flexDataSource;
}
/**
* 事务管理器
*
* @param dataSource 数据源
* @return 事务管理器
*/
@ConditionalOnMybatisFlexDatasource
@Bean(resolveNested = false, independent = true)
public PlatformTransactionManager flexDataSourceTransactionManager(DataSource dataSource) {
return new FlexTransactionManager();
}
/**
* {@link com.mybatisflex.annotation.UseDataSource} 注解切换数据源切面
*/
@Bean(resolveNested = false, independent = true)
@ConditionalOnMissingBean(name = "flexDataSourceAdvisor")
public Advisor flexDataSourceAdvisor() {
return new AnnotationPointcutAdvisor(UseDataSource.class, new DataSourceInterceptor());
}
@ConditionalOnMissingBean
@Bean(resolveNested = false, independent = true)
public TransactionFactory flexTransactionFactory() {
return new FlexTransactionFactory();
}
@Bean
public SqlSessionFactoryBean flexSqlSessionFactoryBean() {
SqlSessionFactoryBean factory = new FlexSqlSessionFactoryBean();
this.mybatisFlexProperties.applyTo(this.mybatisProperties);
this.applyConfiguration(factory);
return factory;
}
protected void applyConfiguration(SqlSessionFactoryBean factory) {
FlexConfiguration configuration = null;
MybatisFlexProperties.CoreConfiguration coreConfiguration = this.mybatisFlexProperties.getConfiguration();
if (coreConfiguration != null || !StringUtils.hasText(this.mybatisFlexProperties.getConfigLocation())) {
configuration = new FlexConfiguration();
}
if (configuration != null && coreConfiguration != null) {
coreConfiguration.applyTo(configuration);
}
if (!CollectionUtils.isEmpty(this.configurationCustomizers)) {
for (ConfigurationCustomizer customizer : this.configurationCustomizers) {
customizer.customize(configuration);
}
}
factory.setConfiguration(configuration);
}
private void checkConfigFileExists() {
if (this.mybatisFlexProperties.isCheckConfigLocation() && StringUtils.hasText(this.mybatisFlexProperties.getConfigLocation())) {
try (InputStream loaded = IOUtil.load(this.mybatisProperties.getConfigLocation())) {
Assert.state(loaded != null, "Cannot find config location: " + this.mybatisProperties.getConfigLocation() + " (please add config file or check your Mybatis configuration)");
} catch (IOException e) {
throw new ResolvableException(e);
}
}
}
private FlexDataSource addDataSource(Map.Entry<String, Map<String, String>> entry, FlexDataSource flexDataSource) {
DataSource dataSource = new DataSourceBuilder(entry.getValue()).build();
DataSourceManager.decryptDataSource(dataSource);
if (flexDataSource == null) {
flexDataSource = new FlexDataSource(entry.getKey(), dataSource, false);
} else {
flexDataSource.addDataSource(entry.getKey(), dataSource, false);
}
return flexDataSource;
}
}

View File

@ -0,0 +1,472 @@
/*
* Copyright (c) 2022-2024, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.framework.boot.autoconfig;
import com.kfyty.loveqq.framework.boot.data.orm.mybatis.autoconfig.MybatisProperties;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Component;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.ConfigurationProperties;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.NestedConfigurationProperty;
import com.kfyty.loveqq.framework.core.lang.util.Mapping;
import com.mybatisflex.core.FlexConsts;
import com.mybatisflex.core.FlexGlobalConfig;
import lombok.Data;
import org.apache.ibatis.io.VFS;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.mapping.ResultSetType;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.session.AutoMappingBehavior;
import org.apache.ibatis.session.AutoMappingUnknownColumnBehavior;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.LocalCacheScope;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* Mybatis-Flex 的配置属性
* 参考自 mybatis-flex-spring-boot-starter
*
* @author kfyty725
*/
@Data
@Component
@ConfigurationProperties("mybatis-flex")
public class MybatisFlexProperties {
/**
* 默认数据源 key
*/
private String defaultDatasourceKey;
/**
* <p>多数据源的配置
*
* <p>
* mybatis-flex.datasource.ds1.url=***<br>
* mybatis-flex.datasource.ds2.url=***
*/
private Map<String, Map<String, String>> datasource;
/**
* 全局配置
*/
private GlobalConfig globalConfig;
/**
* MyBatis-Flex-Admin 配置
*/
private AdminConfig adminConfig;
/**
* Location of MyBatis xml config file.
*/
private String configLocation;
/**
* Locations of MyBatis mapper files.
*/
private String[] mapperLocations = new String[]{"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 com.kfyty.loveqq.framework.boot.data.orm.mybatis.autoconfig.support.ConcurrentSqlSession}.
*/
private ExecutorType executorType;
/**
* The default scripting language driver class. (Available when use together with mybatis-spring 2.0.2+)
*/
private Class<? extends LanguageDriver> 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.
*/
private CoreConfiguration configuration;
/**
* 合并到 {@link MybatisProperties} 配置
*
* @param properties 配置
*/
void applyTo(MybatisProperties properties) {
Mapping.from(getConfigLocation()).whenNotNull(properties::setConfigLocation);
Mapping.from(getExecutorType()).whenNotNull(properties::setExecutorType);
Mapping.from(getTypeAliasesPackage()).whenNotNull(properties::setTypeAliasesPackage);
Mapping.from(getTypeHandlersPackage()).whenNotNull(properties::setTypeHandlersPackage);
Mapping.from(getMapperLocations()).whenNotNull(properties::setMapperLocations);
Mapping.from(getDefaultScriptingLanguageDriver()).whenNotNull(properties::setDefaultScriptingLanguageDriver);
Mapping.from(getConfigurationProperties()).whenNotNull(properties::setConfigurationProperties);
Mapping.from(getConfiguration()).notNullMap(CoreConfiguration::getVfsImpl).whenNotNull(properties::setVfs);
}
/**
* The configuration properties for mybatis core module.
*
* @since 3.0.0
*/
@Data
@NestedConfigurationProperty
public static class CoreConfiguration {
/**
* Allows using RowBounds on nested statements. If allow, set the false. Default is false.
*/
private Boolean safeRowBoundsEnabled;
/**
* Allows using ResultHandler on nested statements. If allow, set the false. Default is true.
*/
private Boolean safeResultHandlerEnabled;
/**
* Enables automatic mapping from classic database column names A_COLUMN to camel case classic Java property names
* aColumn. Default is true.
*/
private Boolean mapUnderscoreToCamelCase = true;
/**
* When enabled, any method call will load all the lazy properties of the object. Otherwise, each property is loaded
* on demand (see also lazyLoadTriggerMethods). Default is false.
*/
private Boolean aggressiveLazyLoading;
/**
* Allows or disallows multiple ResultSets to be returned from a single statement (compatible driver required).
* Default is true.
*/
private Boolean multipleResultSetsEnabled;
/**
* Allows JDBC support for generated keys. A compatible driver is required. This setting forces generated keys to be
* used if set to true, as some drivers deny compatibility but still work (e.g. Derby). Default is false.
*/
private Boolean useGeneratedKeys;
/**
* Uses the column label instead of the column name. Different drivers behave differently in this respect. Refer to
* the driver documentation, or test out both modes to determine how your driver behaves. Default is true.
*/
private Boolean useColumnLabel;
/**
* Globally enables or disables any caches configured in any mapper under this configuration. Default is true.
*/
private Boolean cacheEnabled;
/**
* Specifies if setters or map's put method will be called when a retrieved value is null. It is useful when you
* rely on Map.keySet() or null value initialization. Note primitives such as (int,boolean,etc.) will not be set to
* null. Default is false.
*/
private Boolean callSettersOnNulls;
/**
* Allow referencing statement parameters by their actual names declared in the method signature. To use this
* feature, your project must be compiled in Java 8 with -parameters option. Default is true.
*/
private Boolean useActualParamName;
/**
* MyBatis, by default, returns null when all the columns of a returned row are NULL. When this setting is enabled,
* MyBatis returns an empty instance instead. Note that it is also applied to nested results (i.e. collectioin and
* association). Default is false.
*/
private Boolean returnInstanceForEmptyRow;
/**
* Removes extra whitespace characters from the SQL. Note that this also affects literal strings in SQL. Default is
* false.
*/
private Boolean shrinkWhitespacesInSql;
/**
* Specifies the default value of 'nullable' attribute on 'foreach' tag. Default is false.
*/
private Boolean nullableOnForEach;
/**
* When applying constructor auto-mapping, argument name is used to search the column to map instead of relying on
* the column order. Default is false.
*/
private Boolean argNameBasedConstructorAutoMapping;
/**
* Globally enables or disables lazy loading. When enabled, all relations will be lazily loaded. This value can be
* superseded for a specific relation by using the fetchType attribute on it. Default is False.
*/
private Boolean lazyLoadingEnabled;
/**
* Sets the number of seconds the driver will wait for a response from the database.
*/
private Integer defaultStatementTimeout;
/**
* Sets the driver a hint as to control fetching size for return results. This parameter value can be override by a
* query setting.
*/
private Integer defaultFetchSize;
/**
* MyBatis uses local cache to prevent circular references and speed up repeated nested queries. By default
* (SESSION) all queries executed during a session are cached. If localCacheScope=STATEMENT local session will be
* used just for statement execution, no data will be shared between two different calls to the same SqlSession.
* Default is SESSION.
*/
private LocalCacheScope localCacheScope;
/**
* Specifies the JDBC type for null values when no specific JDBC type was provided for the parameter. Some drivers
* require specifying the column JDBC type but others work with generic values like NULL, VARCHAR or OTHER. Default
* is OTHER.
*/
private JdbcType jdbcTypeForNull;
/**
* Specifies a scroll strategy when omit it per statement settings.
*/
private ResultSetType defaultResultSetType;
/**
* Configures the default executor. SIMPLE executor does nothing special. REUSE executor reuses prepared statements.
* BATCH executor reuses statements and batches updates. Default is SIMPLE.
*/
private ExecutorType defaultExecutorType;
/**
* Specifies if and how MyBatis should automatically map columns to fields/properties. NONE disables auto-mapping.
* PARTIAL will only auto-map results with no nested result mappings defined inside. FULL will auto-map result
* mappings of any complexity (containing nested or otherwise). Default is PARTIAL.
*/
private AutoMappingBehavior autoMappingBehavior;
/**
* Specify the behavior when detects an unknown column (or unknown property type) of automatic mapping target.
* Default is NONE.
*/
private AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior;
/**
* Specifies the prefix string that MyBatis will add to the logger names.
*/
private String logPrefix;
/**
* Specifies which Object's methods trigger a lazy load. Default is [equals,clone,hashCode,toString].
*/
private Set<String> lazyLoadTriggerMethods;
/**
* Specifies which logging implementation MyBatis should use. If this setting is not present logging implementation
* will be autodiscovered.
*/
private Class<? extends Log> logImpl;
/**
* Specifies VFS implementations.
*/
private Class<? extends VFS> vfsImpl;
/**
* Specifies an sql provider class that holds provider method. This class apply to the type(or value) attribute on
* sql provider annotation(e.g. @SelectProvider), when these attribute was omitted.
*/
private Class<?> defaultSqlProviderType;
/**
* Specifies the TypeHandler used by default for Enum.
*/
Class<? extends TypeHandler> defaultEnumTypeHandler;
/**
* Specifies the class that provides an instance of Configuration. The returned Configuration instance is used to
* load lazy properties of deserialized objects. This class must have a method with a signature static Configuration
* getConfiguration().
*/
private Class<?> configurationFactory;
/**
* Specify any configuration variables.
*/
private Properties variables;
void applyTo(Configuration target) {
Mapping.from(getSafeRowBoundsEnabled()).whenNotNull(target::setSafeRowBoundsEnabled);
Mapping.from(getSafeResultHandlerEnabled()).whenNotNull(target::setSafeResultHandlerEnabled);
Mapping.from(getMapUnderscoreToCamelCase()).whenNotNull(target::setMapUnderscoreToCamelCase);
Mapping.from(getAggressiveLazyLoading()).whenNotNull(target::setAggressiveLazyLoading);
Mapping.from(getMultipleResultSetsEnabled()).whenNotNull(target::setMultipleResultSetsEnabled);
Mapping.from(getUseGeneratedKeys()).whenNotNull(target::setUseGeneratedKeys);
Mapping.from(getUseColumnLabel()).whenNotNull(target::setUseColumnLabel);
Mapping.from(getCacheEnabled()).whenNotNull(target::setCacheEnabled);
Mapping.from(getCallSettersOnNulls()).whenNotNull(target::setCallSettersOnNulls);
Mapping.from(getUseActualParamName()).whenNotNull(target::setUseActualParamName);
Mapping.from(getReturnInstanceForEmptyRow()).whenNotNull(target::setReturnInstanceForEmptyRow);
Mapping.from(getShrinkWhitespacesInSql()).whenNotNull(target::setShrinkWhitespacesInSql);
Mapping.from(getNullableOnForEach()).whenNotNull(target::setNullableOnForEach);
Mapping.from(getArgNameBasedConstructorAutoMapping()).whenNotNull(target::setArgNameBasedConstructorAutoMapping);
Mapping.from(getLazyLoadingEnabled()).whenNotNull(target::setLazyLoadingEnabled);
Mapping.from(getLogPrefix()).whenNotNull(target::setLogPrefix);
Mapping.from(getLazyLoadTriggerMethods()).whenNotNull(target::setLazyLoadTriggerMethods);
Mapping.from(getDefaultStatementTimeout()).whenNotNull(target::setDefaultStatementTimeout);
Mapping.from(getDefaultFetchSize()).whenNotNull(target::setDefaultFetchSize);
Mapping.from(getLocalCacheScope()).whenNotNull(target::setLocalCacheScope);
Mapping.from(getJdbcTypeForNull()).whenNotNull(target::setJdbcTypeForNull);
Mapping.from(getDefaultResultSetType()).whenNotNull(target::setDefaultResultSetType);
Mapping.from(getDefaultExecutorType()).whenNotNull(target::setDefaultExecutorType);
Mapping.from(getAutoMappingBehavior()).whenNotNull(target::setAutoMappingBehavior);
Mapping.from(getAutoMappingUnknownColumnBehavior()).whenNotNull(target::setAutoMappingUnknownColumnBehavior);
Mapping.from(getVariables()).whenNotNull(target::setVariables);
Mapping.from(getLogImpl()).whenNotNull(target::setLogImpl);
Mapping.from(getVfsImpl()).whenNotNull(target::setVfsImpl);
Mapping.from(getDefaultSqlProviderType()).whenNotNull(target::setDefaultSqlProviderType);
Mapping.from(getConfigurationFactory()).whenNotNull(target::setConfigurationFactory);
Mapping.from(getDefaultEnumTypeHandler()).whenNotNull(target::setDefaultEnumTypeHandler);
}
}
/**
* {@link FlexGlobalConfig} 配置
*
* @author 王帅
* @author kfyty725
* @since 2023-06-21
*/
@Data
@NestedConfigurationProperty
public static class GlobalConfig {
/**
* 启动是否打印 banner 版本号
*/
private boolean printBanner = true;
/**
* 全局的 ID 生成策略配置 @Id 未配置 或者 配置 KeyType None
* 使用当前全局配置
*/
@NestedConfigurationProperty
private FlexGlobalConfig.KeyConfig keyConfig;
/**
* 逻辑删除数据存在标记值
*/
private Object normalValueOfLogicDelete = FlexConsts.LOGIC_DELETE_NORMAL;
/**
* 逻辑删除数据删除标记值
*/
private Object deletedValueOfLogicDelete = FlexConsts.LOGIC_DELETE_DELETED;
/**
* 默认的分页查询时的每页数据量
*/
private int defaultPageSize = 10;
/**
* 默认的 Relation 注解查询深度
*/
private int defaultRelationQueryDepth = 2;
/**
* 默认的逻辑删除字段
*/
private String logicDeleteColumn;
/**
* 默认的多租户字段
*/
private String tenantColumn;
/**
* 默认的乐观锁字段
*/
private String versionColumn;
/**
* 全局忽略 @Table 中配置的 schema
*/
private boolean ignoreSchema = false;
void applyTo(FlexGlobalConfig target) {
Mapping.from(isPrintBanner()).whenNotNull(target::setPrintBanner);
Mapping.from(getKeyConfig()).whenNotNull(target::setKeyConfig);
Mapping.from(getNormalValueOfLogicDelete()).whenNotNull(target::setNormalValueOfLogicDelete);
Mapping.from(getDeletedValueOfLogicDelete()).whenNotNull(target::setDeletedValueOfLogicDelete);
Mapping.from(getDefaultPageSize()).whenNotNull(target::setDefaultPageSize);
Mapping.from(getDefaultRelationQueryDepth()).whenNotNull(target::setDefaultRelationQueryDepth);
Mapping.from(getLogicDeleteColumn()).whenNotNull(target::setLogicDeleteColumn);
Mapping.from(getVersionColumn()).whenNotNull(target::setVersionColumn);
Mapping.from(getTenantColumn()).whenNotNull(target::setTenantColumn);
Mapping.from(isIgnoreSchema()).whenNotNull(target::setIgnoreSchema);
}
}
/**
* MyBatis Flex Admin 配置
*
* @author 王帅
* @author kfyty725
* @since 2023-07-02
*/
@Data
@NestedConfigurationProperty
public static class AdminConfig {
/**
* 启用服务
*/
private boolean enable;
/**
* 连接端点
*/
private String endpoint;
/**
* 秘密密钥
*/
private String secretKey;
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.framework.boot.autoconfig.annotation;
import com.kfyty.loveqq.framework.core.autoconfig.condition.Condition;
import com.kfyty.loveqq.framework.core.autoconfig.condition.ConditionContext;
import com.kfyty.loveqq.framework.core.autoconfig.condition.annotation.Conditional;
import com.kfyty.loveqq.framework.core.autoconfig.env.PropertyContext;
import com.kfyty.loveqq.framework.core.support.AnnotationMetadata;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;
/**
* <p>判断是否有 MyBatis-Flex 的多数据源配置
* <p>如果配置文件中有 MyBatis-Flex 的多数据源配置就加载 MyBatis-Flex 多数据源自动配置类
*
* @author michael
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Conditional(ConditionalOnMybatisFlexDatasource.OnMybatisFlexDataSourceCondition.class)
public @interface ConditionalOnMybatisFlexDatasource {
class OnMybatisFlexDataSourceCondition implements Condition {
@Override
public boolean isMatch(ConditionContext context, AnnotationMetadata<?> metadata) {
PropertyContext propertyContext = context.getBeanFactory().getBean(PropertyContext.class);
Map<String, String> properties = propertyContext.searchMapProperties("mybatis-flex.datasource");
return properties != null && !properties.isEmpty();
}
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.framework.boot.autoconfig.customize;
import com.mybatisflex.core.mybatis.FlexConfiguration;
/**
* {@link FlexConfiguration} 做自定义的配置支持
*
* @author michael
*/
@FunctionalInterface
public interface ConfigurationCustomizer {
/**
* 自定义配置 {@link FlexConfiguration}
*
* @param configuration MyBatis Flex Configuration
*/
void customize(FlexConfiguration configuration);
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.framework.boot.autoconfig.customize;
import com.mybatisflex.core.FlexGlobalConfig;
/**
* <p>MyBatis-Flex 配置
*
* <p>一般可以用于去初始化
*
* <ul>
* <li>FlexGlobalConfig 的全局配置
* <li>自定义主键生成器
* <li>多租户配置
* <li>动态表名配置
* <li>逻辑删除处理器配置
* <li>自定义脱敏规则
* <li>SQL 审计配置
* <li>SQL 打印配置
* <li>数据源解密器配置
* <li>自定义数据方言配置
* <li>...
* </ul>
*/
public interface MyBatisFlexCustomizer {
/**
* 自定义 MyBatis-Flex 配置
*
* @param globalConfig 全局配置
*/
void customize(FlexGlobalConfig globalConfig);
}

View File

@ -0,0 +1,93 @@
/*
* Copyright (c) 2022-2024, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.framework.boot.autoconfig.datasource;
import com.kfyty.loveqq.framework.core.support.Pair;
import com.mybatisflex.annotation.UseDataSource;
import com.mybatisflex.core.datasource.DataSourceKey;
import com.mybatisflex.core.util.StringUtil;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 多数据源切换拦截器
*
* @author 王帅
* @author barql
* @author michael
* @since 2023-06-25
*/
public class DataSourceInterceptor implements MethodInterceptor {
/**
* 缓存方法对应的数据源
*/
private final Map<Object, String> dsCache = new ConcurrentHashMap<>();
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
String dsKey = getDataSourceKey(invocation.getThis(), invocation.getMethod(), invocation.getArguments());
if (StringUtil.noText(dsKey)) {
return invocation.proceed();
}
try {
DataSourceKey.use(dsKey);
return invocation.proceed();
} finally {
DataSourceKey.clear();
}
}
private String getDataSourceKey(Object target, Method method, Object[] arguments) {
Object cacheKey = new Pair<>(method, target.getClass());
String dsKey = this.dsCache.get(cacheKey);
if (dsKey == null) {
dsKey = determineDataSourceKey(method, target.getClass());
// 对数据源取值进行动态取值处理
if (StringUtil.hasText(dsKey)) {
dsKey = DataSourceKey.processDataSourceKey(dsKey, target, method, arguments);
}
this.dsCache.put(cacheKey, dsKey);
}
return dsKey;
}
private String determineDataSourceKey(Method method, Class<?> targetClass) {
// 方法上定义有 UseDataSource 注解
UseDataSource annotation = method.getAnnotation(UseDataSource.class);
if (annotation != null) {
return annotation.value();
}
// 类上定义有 UseDataSource 注解
annotation = targetClass.getAnnotation(UseDataSource.class);
if (annotation != null) {
return annotation.value();
}
// 接口上定义有 UseDataSource 注解
Class<?>[] interfaces = targetClass.getInterfaces();
for (Class<?> anInterface : interfaces) {
annotation = anInterface.getAnnotation(UseDataSource.class);
if (annotation != null) {
return annotation.value();
}
}
// 哪里都没有 UseDataSource 注解
return "";
}
}

View File

@ -0,0 +1,19 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.
*/
/**
* MyBatis-Flex loveqq-framework 支持
*/
package com.mybatisflex.loveqq.framework.boot.autoconfig;

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.framework.boot.autoconfig.service;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Autowired;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.service.IService;
/**
* Mybatis-Flex 提供的顶级增强 Service 接口的默认实现类
*
* @param <T> 实体类Entity类型
* @param <M> 映射类Mapper类型
* @author 王帅
* @since 2023-05-01
*/
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {
@Autowired
protected M mapper;
@Override
public M getMapper() {
return mapper;
}
}

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.framework.boot.autoconfig.transaction;
import com.mybatisflex.core.transaction.TransactionContext;
import com.mybatisflex.core.util.StringUtil;
import org.apache.ibatis.transaction.Transaction;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
/**
* spring 事务支持解决 issues: https://gitee.com/mybatis-flex/mybatis-flex/issues/I7HJ4J
*
* @author life
* @author michael
*/
public class FlexTransaction implements Transaction {
private final DataSource dataSource;
private Boolean isConnectionTransactional;
private Boolean autoCommit;
private Connection connection;
public FlexTransaction(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public Connection getConnection() throws SQLException {
if (isConnectionTransactional == null) {
connection = dataSource.getConnection();
isConnectionTransactional = StringUtil.hasText(TransactionContext.getXID());
autoCommit = connection.getAutoCommit();
return connection;
}
// 在事务中通过 FlexDataSource 去获取
// FlexDataSource 内部会进行 connection 缓存以及多数据源下的 key 判断
else if (isConnectionTransactional) {
return dataSource.getConnection();
}
// 非事务返回当前链接
else {
return connection;
}
}
@Override
public void commit() throws SQLException {
if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {
this.connection.commit();
}
}
@Override
public void rollback() throws SQLException {
if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {
this.connection.rollback();
}
}
@Override
public void close() throws SQLException {
if (this.connection != null && !this.isConnectionTransactional) {
connection.close();
}
}
@Override
public Integer getTimeout() throws SQLException {
return TimeoutHolder.getTimeToLiveInSeconds();
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.framework.boot.autoconfig.transaction;
import org.apache.ibatis.session.TransactionIsolationLevel;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.transaction.TransactionFactory;
import javax.sql.DataSource;
import java.sql.Connection;
/**
* @author life
* @author michael
*/
public class FlexTransactionFactory implements TransactionFactory {
/**
* {@inheritDoc}
*/
@Override
public Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit) {
return new FlexTransaction(dataSource);
}
/**
* {@inheritDoc}
*/
@Override
public Transaction newTransaction(Connection conn) {
throw new UnsupportedOperationException("New Flex transactions require a DataSource");
}
}

View File

@ -0,0 +1,119 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.framework.boot.autoconfig.transaction;
import com.mybatisflex.core.transaction.TransactionContext;
import com.mybatisflex.core.transaction.TransactionalManager;
import com.mybatisflex.core.util.StringUtil;
import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;
/**
* MyBatis-Flex 事务支持
*
* @author michael
*/
public class FlexTransactionManager extends AbstractPlatformTransactionManager {
@Override
protected Object doGetTransaction() throws TransactionException {
return new TransactionObject(TransactionContext.getXID());
}
@Override
protected boolean isExistingTransaction(Object transaction) throws TransactionException {
TransactionObject transactionObject = (TransactionObject) transaction;
return StringUtil.hasText(transactionObject.prevXid);
}
@Override
protected Object doSuspend(Object transaction) throws TransactionException {
TransactionContext.release();
TransactionObject transactionObject = (TransactionObject) transaction;
return transactionObject.prevXid;
}
@Override
protected void doResume(Object transaction, Object suspendedResources) throws TransactionException {
String xid = (String) suspendedResources;
TransactionContext.holdXID(xid);
}
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException {
TransactionObject transactionObject = (TransactionObject) transaction;
transactionObject.currentXid = TransactionalManager.startTransactional();
TimeoutHolder.hold(definition);
}
@Override
protected void doCommit(DefaultTransactionStatus status) throws TransactionException {
TransactionObject transactionObject = (TransactionObject) status.getTransaction();
TransactionalManager.commit(transactionObject.currentXid);
transactionObject.clear();
}
@Override
protected void doRollback(DefaultTransactionStatus status) throws TransactionException {
TransactionObject transactionObject = (TransactionObject) status.getTransaction();
TransactionalManager.rollback(transactionObject.currentXid);
transactionObject.clear();
}
@Override
protected void doSetRollbackOnly(DefaultTransactionStatus status) throws TransactionException {
// 在多个事务嵌套时子事务的传递方式为 REQUIRED加入当前事务
// 那么当子事务抛出异常时会调当前方法而不是直接调用 doRollback
// 此时需要标识 prevXid 进行 Rollback
TransactionObject transactionObject = (TransactionObject) status.getTransaction();
transactionObject.setRollbackOnly();
}
@Override
protected void doCleanupAfterCompletion(Object transaction) {
TimeoutHolder.clear();
}
static class TransactionObject extends JdbcTransactionObjectSupport {
private static final ThreadLocal<String> ROLLBACK_ONLY_XIDS = new ThreadLocal<>();
private final String prevXid;
private String currentXid;
public TransactionObject(String prevXid) {
this.prevXid = prevXid;
}
public void setRollbackOnly() {
ROLLBACK_ONLY_XIDS.set(prevXid);
}
public void clear() {
ROLLBACK_ONLY_XIDS.remove();
}
@Override
public boolean isRollbackOnly() {
return currentXid != null && currentXid.equals(ROLLBACK_ONLY_XIDS.get());
}
}
}

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.framework.boot.autoconfig.transaction;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionTimedOutException;
import java.util.Date;
/**
* 事务定义管理器 用于更完整的实现Spring事务
* 仅支持传统事务不支持R2DBC事务
*
* @author Aliothmoon
* @author Michael
* @since 2024/10/25
*/
public final class TimeoutHolder {
private static final ThreadLocal<Long> TRANSACTION_DEADLINE = new ThreadLocal<>();
public static void hold(TransactionDefinition definition) {
if (definition == null) {
return;
}
int timeout = definition.getTimeout();
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
Long deadline = System.currentTimeMillis() + timeout * 1000L;
TRANSACTION_DEADLINE.set(deadline);
}
}
/**
* 清除事务上下文
*/
public static void clear() {
TRANSACTION_DEADLINE.remove();
}
/**
* 获取当前事务可用TTL
*
* @return int
*/
public static Integer getTimeToLiveInSeconds() {
Long deadline = TRANSACTION_DEADLINE.get();
if (deadline == null) {
return null;
}
double diff = ((double) getTimeToLiveInMillis(deadline)) / 1000;
int secs = (int) Math.ceil(diff);
checkTransactionTimeout(secs <= 0, deadline);
return secs;
}
private static void checkTransactionTimeout(boolean deadlineReached, Long deadline) throws TransactionTimedOutException {
if (deadlineReached) {
throw new TransactionTimedOutException("Transaction timed out: deadline was " + new Date(deadline));
}
}
private static long getTimeToLiveInMillis(Long deadline) throws TransactionTimedOutException {
if (deadline == null) {
throw new IllegalStateException("No timeout specified for this resource holder");
}
long timeToLive = deadline - System.currentTimeMillis();
checkTransactionTimeout(timeToLive <= 0, deadline);
return timeToLive;
}
}

View File

@ -0,0 +1,4 @@
com.kfyty.loveqq.framework.core.autoconfig.annotation.EnableAutoConfiguration=\
com.mybatisflex.loveqq.framework.boot.autoconfig.MybatisFlexProperties,\
com.mybatisflex.loveqq.framework.boot.autoconfig.MybatisFlexAutoConfiguration,\
com.mybatisflex.loveqq.framework.boot.autoconfig.MybatisFlexAdminAutoConfiguration

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<artifactId>mybatis-flex-test</artifactId>
<groupId>com.mybatis-flex</groupId>
<version>1.10.9</version>
</parent>
<artifactId>mybatis-flex-loveqq-test</artifactId>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.kfyty</groupId>
<artifactId>loveqq-boot</artifactId>
<version>${loveqq.version}</version>
</dependency>
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-loveqq-starter</artifactId>
<version>${mybatis-flex.version}</version>
</dependency>
<dependency>
<groupId>com.kfyty</groupId>
<artifactId>loveqq-boot-starter-logback</artifactId>
<version>${loveqq.version}</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.32</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Component;
import com.kfyty.loveqq.framework.core.event.ApplicationListener;
import com.kfyty.loveqq.framework.core.event.ContextRefreshedEvent;
import com.mybatisflex.core.FlexGlobalConfig;
import com.mybatisflex.core.datasource.FlexDataSource;
@Component
public class DataSourceInitListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
FlexDataSource dataSource = FlexGlobalConfig.getDefaultConfig().getDataSource();
System.out.println("onApplicationEvent>>>> datasource:" + dataSource);
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Configuration;
import com.mybatisflex.core.FlexGlobalConfig;
import com.mybatisflex.core.datasource.DataSourceDecipher;
import com.mybatisflex.core.datasource.DataSourceManager;
import com.mybatisflex.core.mybatis.FlexConfiguration;
import com.mybatisflex.loveqq.framework.boot.autoconfig.customize.ConfigurationCustomizer;
import com.mybatisflex.loveqq.framework.boot.autoconfig.customize.MyBatisFlexCustomizer;
import com.mybatisflex.loveqq.test.unmapped.MyUnMappedColumnHandler;
import org.apache.ibatis.logging.stdout.StdOutImpl;
@Configuration
public class MyConfigurationCustomizer implements ConfigurationCustomizer, MyBatisFlexCustomizer {
@Override
public void customize(FlexConfiguration configuration) {
System.out.println(">>>>>>> MyConfigurationCustomizer.customize() invoked");
configuration.setLogImpl(StdOutImpl.class);
}
// @Bean
// public DataSourceDecipher decipher() {
// DataSourceDecipher decipher = new DataSourceDecipher() {
// @Override
// public String decrypt(DataSourceProperty property, String value) {
// System.out.println(">>>>>> decipher.decrypt");
// return value;
// }
// };
// return decipher;
// }
@Override
public void customize(FlexGlobalConfig globalConfig) {
DataSourceDecipher decipher = (property, value) -> {
System.out.println(">>>>>> decipher.decrypt");
return value;
};
DataSourceManager.setDecipher(decipher);
globalConfig.setUnMappedColumnHandler(new MyUnMappedColumnHandler());
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kfyty.loveqq.framework.boot.K;
import com.kfyty.loveqq.framework.boot.data.orm.mybatis.autoconfig.annotation.MapperScan;
import com.kfyty.loveqq.framework.core.autoconfig.CommandLineRunner;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Autowired;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Bean;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.BootApplication;
import com.kfyty.loveqq.framework.core.autoconfig.condition.annotation.ConditionalOnMissingBean;
import com.kfyty.loveqq.framework.core.event.ApplicationListener;
import com.kfyty.loveqq.framework.core.event.ContextRefreshedEvent;
import com.kfyty.loveqq.framework.core.utils.JsonUtil;
import com.mybatisflex.core.audit.AuditManager;
import com.mybatisflex.core.audit.ConsoleMessageCollector;
import com.mybatisflex.core.audit.MessageCollector;
import com.mybatisflex.loveqq.test.mapper.AccountMapper;
@BootApplication
@MapperScan("com.mybatisflex.loveqq.test.mapper.**.*")
public class SampleApplication implements CommandLineRunner, ApplicationListener<ContextRefreshedEvent> {
@Autowired
private AccountMapper accountMapper;
@Override
public void run(String... args) throws Exception {
System.out.println(this.accountMapper.selectOneById(1));
}
public static void main(String[] args) {
K.start(SampleApplication.class, args);
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("onApplicationEvent");
// 开启审计功能
AuditManager.setAuditEnable(true);
// 设置 SQL 审计收集器
MessageCollector collector = new ConsoleMessageCollector((sql, tookTimeMillis) -> System.out.println(sql));
AuditManager.setMessageCollector(collector);
}
@ConditionalOnMissingBean
@Bean(resolveNested = false, independent = true)
public ObjectMapper objectMapper() {
return JsonUtil.configure();
}
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.alias;
import java.io.Serializable;
import java.util.Date;
/**
* 父类
*
* @author 王帅
* @since 2023-11-16
*/
public abstract class BaseEntity implements Serializable {
private Date createTime;
private String createBy;
private Date updateTime;
private String updateBy;
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String getCreateBy() {
return createBy;
}
public void setCreateBy(String createBy) {
this.createBy = createBy;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public String getUpdateBy() {
return updateBy;
}
public void setUpdateBy(String updateBy) {
this.updateBy = updateBy;
}
@Override
public String toString() {
return "BaseEntity{" +
"createTime=" + createTime +
", createBy='" + createBy + '\'' +
", updateTime=" + updateTime +
", updateBy='" + updateBy + '\'' +
'}';
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.alias;
import com.mybatisflex.annotation.TableRef;
/**
* 部门
*
* @author 王帅
* @since 2023-11-16
*/
@TableRef(SysDept.class)
public class DeptVO extends BaseEntity {
private Integer id;
private String deptName;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
@Override
public String toString() {
return "SysDept{" +
"id=" + id +
", deptName='" + deptName + '\'' +
'}' + super.toString();
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.alias;
import com.mybatisflex.annotation.TableRef;
/**
* 角色
*
* @author 王帅
* @since 2023-11-16
*/
@TableRef(SysRole.class)
public class RoleVO extends BaseEntity {
private Integer id;
private String roleKey;
private String roleName;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getRoleKey() {
return roleKey;
}
public void setRoleKey(String roleKey) {
this.roleKey = roleKey;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
@Override
public String toString() {
return "SysRole{" +
"id=" + id +
", roleKey='" + roleKey + '\'' +
", roleName='" + roleName + '\'' +
'}' + super.toString();
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.alias;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
/**
* 部门
*
* @author 王帅
* @since 2023-11-16
*/
@Table("sys_dept")
public class SysDept extends BaseEntity {
@Id(keyType = KeyType.Auto)
private Integer id;
private String deptName;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
@Override
public String toString() {
return "SysDept{" +
"id=" + id +
", deptName='" + deptName + '\'' +
'}' + super.toString();
}
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.alias;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
/**
* 角色
*
* @author 王帅
* @since 2023-11-16
*/
@Table("sys_role")
public class SysRole extends BaseEntity {
@Id(keyType = KeyType.Auto)
private Integer id;
private String roleKey;
private String roleName;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getRoleKey() {
return roleKey;
}
public void setRoleKey(String roleKey) {
this.roleKey = roleKey;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
@Override
public String toString() {
return "SysRole{" +
"id=" + id +
", roleKey='" + roleKey + '\'' +
", roleName='" + roleName + '\'' +
'}' + super.toString();
}
}

View File

@ -0,0 +1,106 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.alias;
import com.mybatisflex.annotation.ColumnAlias;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.util.Date;
import java.util.List;
/**
* 用户
*
* @author 王帅
* @since 2023-11-16
*/
@Table("sys_user")
public class SysUser extends BaseEntity {
@Id(keyType = KeyType.Auto)
private Integer id;
private String userName;
@ColumnAlias("user_age")
private Integer age;
private Date birthday;
private List<SysRole> roleList;
private List<SysDept> deptList;
public List<SysRole> getRoleList() {
return roleList;
}
public void setRoleList(List<SysRole> roleList) {
this.roleList = roleList;
}
public List<SysDept> getDeptList() {
return deptList;
}
public void setDeptList(List<SysDept> deptList) {
this.deptList = deptList;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "SysUser{" +
"id=" + id +
", userName='" + userName + '\'' +
", age=" + age +
", birthday=" + birthday +
", roleList=" + roleList +
", deptList=" + deptList +
'}' + super.toString();
}
}

View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.alias;
import com.mybatisflex.annotation.ColumnAlias;
import com.mybatisflex.annotation.TableRef;
import java.util.Date;
import java.util.List;
/**
* 用户
*
* @author 王帅
* @since 2023-11-16
*/
@TableRef(SysUser.class)
public class UserVO extends BaseEntity {
private Integer id;
private String userName;
@ColumnAlias("user_age")
private Integer age;
private Date birthday;
private List<SysRole> roleList;
private List<SysDept> deptList;
public List<SysRole> getRoleList() {
return roleList;
}
public void setRoleList(List<SysRole> roleList) {
this.roleList = roleList;
}
public List<SysDept> getDeptList() {
return deptList;
}
public void setDeptList(List<SysDept> deptList) {
this.deptList = deptList;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "SysUser{" +
"id=" + id +
", userName='" + userName + '\'' +
", age=" + age +
", birthday=" + birthday +
", roleList=" + roleList +
", deptList=" + deptList +
'}' + super.toString();
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.entity;
import com.mybatisflex.annotation.Table;
/**
* @author 王帅
* @since 2023-07-01
*/
@Table("tb_inner")
public class Inner {
private Integer id;
private String type;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public String toString() {
return "Inner{" +
"id=" + id +
", type='" + type + '\'' +
'}';
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.entity;
import com.mybatisflex.annotation.ColumnAlias;
import com.mybatisflex.annotation.Table;
import com.mybatisflex.loveqq.test.model.IdEntity;
/**
* @author 王帅
* @since 2023-06-16
*/
@Table("tb_outer")
public class Outer extends IdEntity<Integer> {
private String name;
private Inner inner;
@Override
@ColumnAlias("outer_id")
public Integer getId() {
return super.getId();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Inner getInner() {
return inner;
}
public void setInner(Inner inner) {
this.inner = inner;
}
@Override
public String toString() {
return "Outer{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", inner=" + inner +
'}';
}
}

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.entity;
import com.mybatisflex.annotation.Table;
/**
* @author 王帅
* @since 2023-06-16
*/
@Table("test")
public class TestEntity {
}

View File

@ -0,0 +1,13 @@
package com.mybatisflex.loveqq.test.listener.missingListenerFix;
import com.mybatisflex.annotation.InsertListener;
import com.mybatisflex.loveqq.test.model.AccountMissingListenerTestModel;
public class AccountAgeInsertListener implements InsertListener {
@Override
public void onInsert(Object entity) {
AccountMissingListenerTestModel model = (AccountMissingListenerTestModel) entity;
model.setAge(18);
}
}

View File

@ -0,0 +1,5 @@
package com.mybatisflex.loveqq.test.listener.missingListenerFix;
public interface AccountAgeInsertListenerFlag {
}

View File

@ -0,0 +1,13 @@
package com.mybatisflex.loveqq.test.listener.missingListenerFix;
import com.mybatisflex.annotation.InsertListener;
import com.mybatisflex.loveqq.test.model.AccountMissingListenerTestModel;
public class AccountTableAnnoInsertListener implements InsertListener {
@Override
public void onInsert(Object entity) {
AccountMissingListenerTestModel model = (AccountMissingListenerTestModel) entity;
model.setUserName("测试缺失的监听器-userName");
}
}

View File

@ -0,0 +1,18 @@
package com.mybatisflex.loveqq.test.listener.missingListenerFix;
import com.mybatisflex.annotation.Column;
public class BaseLogicDelete implements LogicDeleteInsertListenerFlag {
@Column(isLogicDelete = true)
private Boolean isDelete;
public Boolean getDelete() {
return isDelete;
}
public void setDelete(Boolean delete) {
isDelete = delete;
}
}

View File

@ -0,0 +1,12 @@
package com.mybatisflex.loveqq.test.listener.missingListenerFix;
import com.mybatisflex.annotation.InsertListener;
public class LogicDeleteInsertListener implements InsertListener {
@Override
public void onInsert(Object entity) {
BaseLogicDelete logicDeleteEntity = (BaseLogicDelete) entity;
logicDeleteEntity.setDelete(false);
}
}

View File

@ -0,0 +1,5 @@
package com.mybatisflex.loveqq.test.listener.missingListenerFix;
public interface LogicDeleteInsertListenerFlag {
}

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.mapper;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.loveqq.test.model.Account;
/**
* @author 王帅
* @since 2023-06-23
*/
public interface AccountMapper extends BaseMapper<Account> {
}

View File

@ -0,0 +1,10 @@
package com.mybatisflex.loveqq.test.mapper;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.loveqq.test.model.AccountMissingListenerTestModel;
/**
* @author noear 2024/12/24 created
*/
public interface AccountMissingListenerTestModelMapper extends BaseMapper<AccountMissingListenerTestModel> {
}

View File

@ -0,0 +1,10 @@
package com.mybatisflex.loveqq.test.mapper;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.loveqq.test.model.Article;
/**
* @author noear 2024/12/24 created
*/
public interface ArticleMapper extends BaseMapper<Article> {
}

View File

@ -0,0 +1,10 @@
package com.mybatisflex.loveqq.test.mapper;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.loveqq.test.model.FieldMappingInner;
/**
* @author noear 2024/12/24 created
*/
public interface FieldMappingInnerMapper extends BaseMapper<FieldMappingInner> {
}

View File

@ -0,0 +1,10 @@
package com.mybatisflex.loveqq.test.mapper;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.loveqq.test.model.FieldMapping;
/**
* @author noear 2024/12/24 created
*/
public interface FieldMappingMapper extends BaseMapper<FieldMapping> {
}

View File

@ -0,0 +1,10 @@
package com.mybatisflex.loveqq.test.mapper;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.loveqq.test.model.Good;
/**
* @author noear 2024/12/24 created
*/
public interface GoodMapper extends BaseMapper<Good> {
}

View File

@ -0,0 +1,10 @@
package com.mybatisflex.loveqq.test.mapper;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.loveqq.test.entity.Inner;
/**
* @author noear 2024/12/24 created
*/
public interface InnerMapper extends BaseMapper<Inner> {
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.mapper;
import com.mybatisflex.loveqq.test.model.Account;
import com.mybatisflex.loveqq.test.model.AccountDto;
import com.mybatisflex.loveqq.test.model.AccountView;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.Map;
public interface MyAccountMapper extends AccountMapper {
AccountDto selectByName(@Param("name") String name);
AccountView selectViewObject();
@Select("select * from tb_account where id = #{id} and id =#{id}")
Account selectById(@Param("id") Object id);
@Select("select * from tb_account where id = #{id}")
Map selectMapById(@Param("id") Object id);
}

View File

@ -0,0 +1,10 @@
package com.mybatisflex.loveqq.test.mapper;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.loveqq.test.entity.Outer;
/**
* @author noear 2024/12/24 created
*/
public interface OuterMapper extends BaseMapper<Outer> {
}

View File

@ -0,0 +1,10 @@
package com.mybatisflex.loveqq.test.mapper;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.loveqq.test.model.Patient;
/**
* @author noear 2024/12/24 created
*/
public interface PatientMapper extends BaseMapper<Patient> {
}

View File

@ -0,0 +1,10 @@
package com.mybatisflex.loveqq.test.mapper;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.loveqq.test.alias.SysUser;
/**
* @author noear 2024/12/24 created
*/
public interface SysUserMapper extends BaseMapper<SysUser> {
}

View File

@ -0,0 +1,7 @@
package com.mybatisflex.loveqq.test.mapper;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.loveqq.test.model.TbClass;
public interface TbClassMapper extends BaseMapper<TbClass> {
}

View File

@ -0,0 +1,10 @@
package com.mybatisflex.loveqq.test.mapper;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.loveqq.test.model.UnmappedUser;
/**
* @author noear 2024/12/24 created
*/
public interface UnmappedUserMapper extends BaseMapper<UnmappedUser> {
}

View File

@ -0,0 +1,10 @@
package com.mybatisflex.loveqq.test.mapper;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.loveqq.test.model.User;
/**
* @author noear 2024/12/24 created
*/
public interface UserMapper extends BaseMapper<User> {
}

View File

@ -0,0 +1,122 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Table;
import java.util.Date;
/**
* 账户信息
*/
@Table(value = "tb_account", onSet = AccountOnSetListener.class)
public class Account extends BaseEntity<String, Long, String> {
/*@Id(keyType = KeyType.Auto)
private Long id;*/
//private String userName;
/**
* 年龄
*/
private Integer age;
/**
* 生日
*/
private Date birthday;
/**
* 逻辑删除
*/
@Column(isLogicDelete = true)
private Boolean isDelete;
@Column(ignore = true)
private String anotherColumn;
// private Gender gender;
//
// public Gender getGender() {
// return gender;
// }
//
// public void setGender(Gender gender) {
// this.gender = gender;
// }
/*public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}*/
/*public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}*/
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Boolean getDelete() {
return isDelete;
}
public void setDelete(Boolean delete) {
isDelete = delete;
}
public String getAnotherColumn() {
return anotherColumn;
}
public void setAnotherColumn(String anotherColumn) {
this.anotherColumn = anotherColumn;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", userName='" + userName + '\'' +
", age=" + age +
", birthday=" + birthday +
", isDelete=" + isDelete +
", anotherColumn=" + anotherColumn +
// ", roles=" + roles +
'}';
}
}

View File

@ -0,0 +1,37 @@
package com.mybatisflex.loveqq.test.model;
import java.util.List;
import java.util.Map;
public class AccountDto {
private Long id;
private String name;
private List<Map<String,String>> other;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Map<String, String>> getOther() {
return other;
}
public void setOther(List<Map<String, String>> other) {
this.other = other;
}
}

View File

@ -0,0 +1,89 @@
package com.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import com.mybatisflex.loveqq.test.listener.missingListenerFix.AccountAgeInsertListenerFlag;
import com.mybatisflex.loveqq.test.listener.missingListenerFix.AccountTableAnnoInsertListener;
import com.mybatisflex.loveqq.test.listener.missingListenerFix.BaseLogicDelete;
import java.util.Objects;
/**
* 缺失的监听器测试
*
* @author Ice 2023/10/23
* @version 1.0
*/
@Table(value = "tb_account", onInsert = AccountTableAnnoInsertListener.class)
public class AccountMissingListenerTestModel extends BaseLogicDelete implements AccountAgeInsertListenerFlag {
/**
* 主键
*/
@Id(keyType = KeyType.Auto)
private Long id;
private String userName;
private Integer age;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AccountMissingListenerTestModel that = (AccountMissingListenerTestModel) o;
return Objects.equals(id, that.id) && Objects.equals(userName, that.userName) && Objects.equals(age, that.age) && Objects.equals(getDelete(), that.getDelete());
}
@Override
public int hashCode() {
return Objects.hash(id, userName, age, getDelete());
}
@Override
public String toString() {
return "AccountMissingListenerTestModel{" +
"id=" + id +
", userName='" + userName + '\'' +
", age=" + age +
", isDelete=" + getDelete() +
'}';
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.SetListener;
public class AccountOnSetListener implements SetListener {
@Override
public Object onSet(Object entity, String property, Object value) {
System.out.println(">>>>>>> property: " + property + " value:" + value);
return value;
}
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import java.util.Date;
public class AccountVO extends IdEntity<Long> {
private Integer age;
private Date birthday;
private Gender gender;
private RoleVO2<String, String> role;
public RoleVO2<String, String> getRole() {
return role;
}
public void setRole(RoleVO2<String, String> role) {
this.role = role;
}
public Gender getGender() {
return gender;
}
public void setGender(Gender gender) {
this.gender = gender;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", age=" + age +
", birthday=" + birthday +
", roleName=" + role +
'}';
}
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.ColumnAlias;
/**
* @author 王帅
* @since 2023-06-30
*/
public class AccountVO2 extends IdEntity<Long> {
private Integer age;
@ColumnAlias("account_name")
private String userName;
private User user;
@Override
@ColumnAlias("account_id")
public Long getId() {
return super.getId();
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "AccountVO2{" +
"id=" + id +
", age=" + age +
", userName='" + userName + '\'' +
", user='" + user + '\'' +
'}';
}
}

View File

@ -0,0 +1,54 @@
package com.mybatisflex.loveqq.test.model;
import java.util.Date;
import java.util.List;
/**
* 复杂查询接收类
* <a href="https://gitee.com/mybatis-flex/mybatis-flex/issues/IAU28L">演示问题</a>
*
* @author 王帅
* @since 2024-10-03
*/
@SuppressWarnings({"LombokGetterMayBeUsed", "LombokSetterMayBeUsed"})
public class AccountView {
private Long id;
private String userName;
private Date birthday;
private List<Account> accountList;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public List<Account> getAccountList() {
return accountList;
}
public void setAccountList(List<Account> accountList) {
this.accountList = accountList;
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Table;
@Table(value = "tb_article")
public class Article extends IdEntity<Long> {
private static final long serialVersionUID = 1L;
private Long accountId;
private String title;
private String content;
@Column(isLogicDelete = true)
private Boolean isDelete;
public Long getAccountId() {
return accountId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "Article{" +
"id=" + id +
", accountId=" + accountId +
", title='" + title + '\'' +
", content='" + content + '\'' +
'}';
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Column;
import java.util.List;
/**
* @author 王帅
* @since 2.0
*/
public class BaseEntity<T, ID, L> extends IdEntity<ID> {
/**
* 用户名
*/
protected T userName;
/**
* 用户角色
*/
@Column(ignore = true)
protected List<L> roles;
public List<L> getRoles() {
return roles;
}
public void setRoles(List<L> roles) {
this.roles = roles;
}
public T getUserName() {
return userName;
}
public void setUserName(T userName) {
this.userName = userName;
}
}

View File

@ -0,0 +1,45 @@
package com.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
/**
* 疾病
*
* @author Ice 2023/09/26
* @version 1.0
*/
@Table(value = "tb_disease")
public class Disease implements Serializable {
private static final long serialVersionUID = -3195530228167432902L;
/**
* ID
*/
@Id(keyType = KeyType.Generator, value = "uuid")
private String diseaseId;
/**
* 疾病名称
*/
private String name;
public String getDiseaseId() {
return diseaseId;
}
public void setDiseaseId(String diseaseId) {
this.diseaseId = diseaseId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,66 @@
package com.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import com.mybatisflex.core.activerecord.Model;
import com.mybatisflex.core.keygen.KeyGenerators;
import java.util.Date;
import java.util.Objects;
@Table("field_mapping")
public class FieldMapping extends Model<FieldMapping> {
@Id(keyType = KeyType.Generator,value = KeyGenerators.snowFlakeId)
private String id;
@Column(ignore = true)
private Date innerDate;
public String getId() {
return id;
}
public static FieldMapping create() {
return new FieldMapping();
}
public FieldMapping setId(String id) {
this.id = id;
return this;
}
public Date getInnerDate() {
return innerDate;
}
public FieldMapping setInnerDate(Date innerDate) {
this.innerDate = innerDate;
return this;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FieldMapping that = (FieldMapping) o;
return Objects.equals(id, that.id) && Objects.equals(innerDate, that.innerDate);
}
@Override
public int hashCode() {
return Objects.hash(id, innerDate);
}
@Override
public String toString() {
return "FieldMapping{" +
"id='" + id + '\'' +
", innerDate=" + innerDate +
'}';
}
}

View File

@ -0,0 +1,71 @@
package com.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import com.mybatisflex.core.activerecord.Model;
import com.mybatisflex.core.keygen.KeyGenerators;
import java.util.Date;
import java.util.Objects;
@Table("field_mapping_inner")
public class FieldMappingInner extends Model<FieldMappingInner> {
@Id(keyType = KeyType.Generator,value = KeyGenerators.snowFlakeId)
private String id;
private String outId;
private Date createDate;
public static FieldMappingInner create() {
return new FieldMappingInner();
}
public String getId() {
return id;
}
public FieldMappingInner setId(String id) {
this.id = id;
return this;
}
public String getOutId() {
return outId;
}
public FieldMappingInner setOutId(String outId) {
this.outId = outId;
return this;
}
public Date getCreateDate() {
return createDate;
}
public FieldMappingInner setCreateDate(Date createDate) {
this.createDate = createDate;
return this;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FieldMappingInner that = (FieldMappingInner) o;
return Objects.equals(id, that.id) && Objects.equals(outId, that.outId) && Objects.equals(createDate, that.createDate);
}
@Override
public int hashCode() {
return Objects.hash(id, outId, createDate);
}
@Override
public String toString() {
return "FieldMappingInner{" +
"id='" + id + '\'' +
", outId='" + outId + '\'' +
", createDate=" + createDate +
'}';
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.EnumValue;
/**
* @author 王帅
* @since 2023-06-14
*/
public enum Gender {
// MALE, FEMALE;
MALE(1), FEMALE(0);
public int getCode() {
return code;
}
@EnumValue
private final int code;
Gender(int code) {
this.code = code;
}
}

View File

@ -0,0 +1,108 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import com.mybatisflex.core.activerecord.Model;
import java.util.Objects;
/**
* 商品
*
* @author 王帅
* @since 2023-06-07
*/
@Table(value = "tb_good", onSet = GoodOnSetListener.class)
public class Good extends Model<Good> {
@Id(keyType = KeyType.Auto)
private Integer goodId;
private String name;
private Double price;
public static Good create() {
return new Good();
}
public Integer getGoodId() {
return goodId;
}
public Good setGoodId(Integer goodId) {
this.goodId = goodId;
return this;
}
public String getName() {
return name;
}
public Good setName(String name) {
this.name = name;
return this;
}
public Double getPrice() {
return price;
}
public Good setPrice(Double price) {
this.price = price;
return this;
}
@Override
public String toString() {
return "Good{" +
"goodId=" + goodId +
", name='" + name + '\'' +
", price=" + price +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Good good = (Good) o;
if (!Objects.equals(goodId, good.goodId)) {
return false;
}
if (!Objects.equals(name, good.name)) {
return false;
}
return Objects.equals(price, good.price);
}
@Override
public int hashCode() {
int result = goodId != null ? goodId.hashCode() : 0;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (price != null ? price.hashCode() : 0);
return result;
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.SetListener;
/**
* @author 王帅
* @since 2023-08-11
*/
public class GoodOnSetListener implements SetListener {
@Override
public Object onSet(Object entity, String property, Object value) {
System.out.println("Good: " + property + " --- " + value);
return value;
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Table;
/**
* @author 王帅
* @since 2023-07-12
*/
@Table("tb_id_card")
public class IdCard {
private Integer id;
private String idNumber;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getIdNumber() {
return idNumber;
}
public void setIdNumber(String idNumber) {
this.idNumber = idNumber;
}
@Override
public String toString() {
return "IdCard{" +
"id=" + id +
", IdNumber='" + idNumber + '\'' +
'}';
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import java.io.Serializable;
/**
* @author 王帅
* @since 2023-06-13
*/
public class IdEntity<T> implements Serializable {
/**
* 主键
*/
@Id(keyType = KeyType.Auto)
protected T id;
public T getId() {
return id;
}
public void setId(T id) {
this.id = id;
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import java.time.LocalDateTime;
/**
* 订单
*
* @author 王帅
* @since 2023-06-07
*/
@Table("tb_order")
public class Order {
@Id
private int orderId;
private LocalDateTime createTime;
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
@Override
public String toString() {
return "Order{" +
"orderId=" + orderId +
", createTime=" + createTime +
'}';
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Table;
/**
* 订单与商品连接表
*
* @author 王帅
* @since 2023-06-07
*/
@Table("tb_order_good")
public class OrderGood {
private Integer orderId;
private Integer goodId;
public Integer getOrderId() {
return orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
public Integer getGoodId() {
return goodId;
}
public void setGoodId(Integer goodId) {
this.goodId = goodId;
}
}

View File

@ -0,0 +1,106 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.RelationManyToMany;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
/**
* 订单信息
*
* @author 王帅
* @since 2023-06-07
*/
public class OrderInfo {
private Integer orderId;
private LocalDateTime createTime;
@RelationManyToMany(
selfField = "orderId",
targetField = "goodId",
joinTable = "tb_order_good",
joinSelfColumn = "order_id",
joinTargetColumn = "good_id"
)
private List<Good> goodList;
public Integer getOrderId() {
return orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public List<Good> getGoodList() {
return goodList;
}
public void setGoodList(List<Good> goodList) {
this.goodList = goodList;
}
@Override
public String toString() {
return "OrderInfo{" +
"orderId=" + orderId +
", createTime=" + createTime +
", goodList=" + goodList +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
OrderInfo orderInfo = (OrderInfo) o;
if (!Objects.equals(orderId, orderInfo.orderId)) {
return false;
}
if (!Objects.equals(createTime, orderInfo.createTime)) {
return false;
}
return Objects.equals(goodList, orderInfo.goodList);
}
@Override
public int hashCode() {
int result = orderId != null ? orderId.hashCode() : 0;
result = 31 * result + (createTime != null ? createTime.hashCode() : 0);
result = 31 * result + (goodList != null ? goodList.hashCode() : 0);
return result;
}
}

View File

@ -0,0 +1,72 @@
package com.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import com.mybatisflex.core.activerecord.Model;
import java.io.Serializable;
/**
* 患者信息
*
* @author Ice 2023/09/26
* @version 1.0
*/
@Table(value = "tb_patient")
public class Patient extends Model<Patient> implements Serializable {
private static final long serialVersionUID = 5117723684832788508L;
/**
* ID
*/
@Id
private Integer patientId;
/**
* 姓名
*/
private String name;
/**
* 所患病症(对应字符串类型) 英文逗号 分割
*/
private String diseaseIds;
/**
* 患者标签(对应数字类型) / 分割
*/
private String tagIds;
public Integer getPatientId() {
return patientId;
}
public void setPatientId(Integer patientId) {
this.patientId = patientId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDiseaseIds() {
return diseaseIds;
}
public void setDiseaseIds(String diseaseIds) {
this.diseaseIds = diseaseIds;
}
public String getTagIds() {
return tagIds;
}
public void setTagIds(String tagIds) {
this.tagIds = tagIds;
}
}

View File

@ -0,0 +1,121 @@
package com.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.RelationOneToMany;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
/**
* 患者VO
*
* @author Ice 2023/09/26
* @version 1.0
*/
@Table(value = "tb_patient")
public class PatientVO1 implements Serializable {
private static final long serialVersionUID = -2298625009592638988L;
/**
* ID
*/
@Id
private Integer patientId;
/**
* 姓名
*/
private String name;
/**
* 所患病症(对应字符串类型) 英文逗号 分割
*/
private String diseaseIds;
/**
* 患者标签(对应数字类型) / 分割
*/
private String tagIds;
@RelationOneToMany(
selfField = "diseaseIds",
selfValueSplitBy = ",", //使用 , 进行分割
targetTable = "tb_disease", //只获取某个字段值需要填入目标表名
targetField = "diseaseId", //测试目标字段是字符串类型是否正常转换
valueField = "name" //测试只获取某个字段值是否正常
)
private List<String> diseaseNameList;
@RelationOneToMany(
selfField = "tagIds",
selfValueSplitBy = "/", //使用 / 进行分割
targetField = "tagId" //测试目标字段是数字类型是否正常转换
)
private List<Tag> tagList;
@RelationOneToMany(
selfField = "diseaseIds",
selfValueSplitBy = ",", //使用 , 进行分割
targetField = "diseaseId", //测试目标字段是字符串类型是否正常转换
mapKeyField = "diseaseId" //测试Map映射
)
private Map<String, Disease> diseaseMap;
public Integer getPatientId() {
return patientId;
}
public void setPatientId(Integer patientId) {
this.patientId = patientId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDiseaseIds() {
return diseaseIds;
}
public void setDiseaseIds(String diseaseIds) {
this.diseaseIds = diseaseIds;
}
public String getTagIds() {
return tagIds;
}
public void setTagIds(String tagIds) {
this.tagIds = tagIds;
}
public List<String> getDiseaseNameList() {
return diseaseNameList;
}
public void setDiseaseNameList(List<String> diseaseNameList) {
this.diseaseNameList = diseaseNameList;
}
public List<Tag> getTagList() {
return tagList;
}
public void setTagList(List<Tag> tagList) {
this.tagList = tagList;
}
public Map<String, Disease> getDiseaseMap() {
return diseaseMap;
}
public void setDiseaseMap(Map<String, Disease> diseaseMap) {
this.diseaseMap = diseaseMap;
}
}

View File

@ -0,0 +1,121 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import java.util.List;
import java.util.Objects;
/**
* 角色
*
* @author 王帅
* @since 2023-06-07
*/
@Table("tb_role")
public class Role implements Comparable<Role> {
@Id
private Integer roleId;
private String roleKey;
private String roleName;
@Column(ignore = true)
private List<UserVO> userVOS;
public Integer getRoleId() {
return roleId;
}
public void setRoleId(Integer roleId) {
this.roleId = roleId;
}
public String getRoleKey() {
return roleKey;
}
public void setRoleKey(String roleKey) {
this.roleKey = roleKey;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public List<UserVO> getUserVOS() {
return userVOS;
}
public void setUserVOS(List<UserVO> userVOS) {
this.userVOS = userVOS;
}
@Override
public String toString() {
return "Role{" +
"roleId=" + roleId +
", roleKey='" + roleKey + '\'' +
", roleName='" + roleName + '\'' +
'}';
}
@Override
public int compareTo(Role o) {
return Integer.compare(this.roleId, o.roleId);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Role role = (Role) o;
if (!Objects.equals(roleId, role.roleId)) {
return false;
}
if (!Objects.equals(roleKey, role.roleKey)) {
return false;
}
if (!Objects.equals(roleName, role.roleName)) {
return false;
}
return Objects.equals(userVOS, role.userVOS);
}
@Override
public int hashCode() {
int result = roleId != null ? roleId.hashCode() : 0;
result = 31 * result + (roleKey != null ? roleKey.hashCode() : 0);
result = 31 * result + (roleName != null ? roleName.hashCode() : 0);
result = 31 * result + (userVOS != null ? userVOS.hashCode() : 0);
return result;
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
/**
* @author 王帅
* @since 2023-06-15
*/
public class RoleKey<T> {
private T roleKey;
public T getRoleKey() {
return roleKey;
}
public void setRoleKey(T roleKey) {
this.roleKey = roleKey;
}
@Override
public String toString() {
return roleKey.toString();
}
}

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
/**
* 角色
*
* @author 王帅
* @since 2023-06-13
*/
public class RoleVO1 {
private Integer roleId;
private String roleKey;
private String roleName;
private UserVO1 user;
public Integer getRoleId() {
return roleId;
}
public void setRoleId(Integer roleId) {
this.roleId = roleId;
}
public String getRoleKey() {
return roleKey;
}
public void setRoleKey(String roleKey) {
this.roleKey = roleKey;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public UserVO1 getUser() {
return user;
}
public void setUser(UserVO1 user) {
this.user = user;
}
@Override
public String toString() {
return "Role{" +
"roleId=" + roleId +
", roleKey='" + roleKey + '\'' +
", roleName='" + roleName + '\'' +
", userVO1='" + user + '\'' +
'}';
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
/**
* @author 王帅
* @since 2023-06-15
*/
public class RoleVO2<T, K> {
private T roleName;
private RoleKey<K> roleKey;
public T getRoleName() {
return roleName;
}
public void setRoleName(T roleName) {
this.roleName = roleName;
}
public RoleKey<K> getRoleKey() {
return roleKey;
}
public void setRoleKey(RoleKey<K> roleKey) {
this.roleKey = roleKey;
}
@Override
public String toString() {
return "RoleName{" +
"roleName=" + roleName +
", roleKey=" + roleKey +
'}';
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
/**
* @author 王帅
* @since 2023-06-15
*/
public class RoleVO3 {
private Integer roleId;
private String roleKey;
private String userName;
public Integer getRoleId() {
return roleId;
}
public void setRoleId(Integer roleId) {
this.roleId = roleId;
}
public String getRoleKey() {
return roleKey;
}
public void setRoleKey(String roleKey) {
this.roleKey = roleKey;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Override
public String toString() {
return "RoleVO3{" +
"roleId=" + roleId +
", roleKey='" + roleKey + '\'' +
", roleName='" + userName + '\'' +
'}';
}
}

View File

@ -0,0 +1,44 @@
package com.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
/**
* 标签
*
* @author Ice 2023/09/26
* @version 1.0
*/
@Table(value = "tb_tag")
public class Tag implements Serializable {
private static final long serialVersionUID = 5600670055904157386L;
/**
* ID
*/
@Id
private Integer tagId;
/**
* 标签名称
*/
private String name;
public Integer getTagId() {
return tagId;
}
public void setTagId(Integer tagId) {
this.tagId = tagId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,47 @@
package com.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
@Table(value = "tb_class")
public class TbClass {
@Id
private Long id;
private Long user_id;
private String className;
public Long getId() {
return id;
}
public Long getUser_id() {
return user_id;
}
public String getClassName() {
return className;
}
public void setId(Long id) {
this.id = id;
}
public void setUser_id(Long user_id) {
this.user_id = user_id;
}
public void setClassName(String className) {
this.className = className;
}
@Override
public String toString() {
return "TbClass{" +
"id=" + id +
", user_id=" + user_id +
", className='" + className + '\'' +
'}';
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import lombok.Getter;
import lombok.Setter;
import java.util.Map;
/**
* UnMappedBaseEntity
*
* @author wy
* @version 1.0
* @date 2024/9/12 11:36
**/
@Getter
@Setter
public class UnmappedBaseEntity {
protected Map<String, Object> unmappedMap;
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import lombok.Getter;
import lombok.Setter;
import org.springframework.util.CollectionUtils;
/**
* UnMapped
*
* @author wy
* @version 1.0
* @date 2024/9/12 11:28
**/
@Getter
@Setter
@Table("tb_unmapped_user")
public class UnmappedUser extends UnmappedBaseEntity {
@Id(keyType = KeyType.Auto)
private Long id;
private Integer age;
private String name;
@Override
public String toString() {
return "UnmappedUser{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
(CollectionUtils.isEmpty(unmappedMap) ? "" : ", unmappedMap=" + unmappedMap.toString())
+ '}';
}
}

View File

@ -0,0 +1,96 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.RelationManyToMany;
import com.mybatisflex.annotation.Table;
import com.mybatisflex.core.activerecord.Model;
import java.util.List;
/**
* 用户
*
* @author 王帅
* @since 2023-06-07
*/
@Table("tb_user")
public class User extends Model<User> {
@Id
private Integer userId;
private String userName;
private String password;
@RelationManyToMany(
selfField = "userId",
targetField = "roleId",
joinTable = "tb_user_role",
joinSelfColumn = "user_id",
joinTargetColumn = "role_id"
)
private List<Role> roleList;
public static User create() {
return new User();
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<Role> getRoleList() {
return roleList;
}
public void setRoleList(List<Role> roleList) {
this.roleList = roleList;
}
@Override
public String toString() {
return "User{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", password='" + password + '\'' +
", roleList=" + roleList +
'}';
}
}

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.RelationManyToMany;
import java.util.List;
/**
* 用户信息
*
* @author 王帅
* @since 2023-06-07
*/
public class UserInfo {
private Integer userId;
private String userName;
private String password;
private String idNumber;
@RelationManyToMany(
selfField = "userId",
targetField = "roleId",
joinTable = "tb_user_role",
joinSelfColumn = "user_id",
joinTargetColumn = "role_id"
)
private List<Role> roleList;
@RelationManyToMany(
selfField = "userId",
targetField = "orderId",
targetTable = "tb_order",
joinTable = "tb_user_order",
joinSelfColumn = "user_id",
joinTargetColumn = "order_id"
)
private List<OrderInfo> orderInfoList;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getIdNumber() {
return idNumber;
}
public void setIdNumber(String idNumber) {
this.idNumber = idNumber;
}
public List<Role> getRoleList() {
return roleList;
}
public void setRoleList(List<Role> roleList) {
this.roleList = roleList;
}
public List<OrderInfo> getOrderInfoList() {
return orderInfoList;
}
public void setOrderInfoList(List<OrderInfo> orderInfoList) {
this.orderInfoList = orderInfoList;
}
@Override
public String toString() {
return "UserInfo{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", password='" + password + '\'' +
", idNumber='" + idNumber + '\'' +
", roleList=" + roleList +
", orderInfoList=" + orderInfoList +
'}';
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Table;
/**
* 用户订单映射
*
* @author 王帅
* @since 2023-06-07
*/
@Table("tb_user_order")
public class UserOrder {
private Integer userId;
private Integer orderId;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public Integer getOrderId() {
return orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Table;
/**
* 用户与角色连接表
*
* @author 王帅
* @since 2023-06-07
*/
@Table("tb_user_role")
public class UserRole {
private Integer userId;
private Integer roleId;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public Integer getRoleId() {
return roleId;
}
public void setRoleId(Integer roleId) {
this.roleId = roleId;
}
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import java.util.HashMap;
import java.util.Map;
/**
* 用户 VO 对象
*
* @author 王帅
* @since 2023-06-07
*/
public class UserVO {
private String userId;
private String userName;
// private TreeSet<Role> roleList;
// private Role[] roleList;
private HashMap<String, Object> roleList;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Map<String, Object> getRoleList() {
return roleList;
}
public void setRoleList(HashMap<String, Object> roleList) {
this.roleList = roleList;
}
@Override
public String toString() {
return "UserVO{" +
"userId='" + userId + '\'' +
", userName='" + userName + '\'' +
", roleList=" + roleList +
'}';
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
/**
* @author 王帅
* @since 2023-06-07
*/
public class UserVO1 {
private String userId;
private String userName;
private RoleVO1 role;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public RoleVO1 getRole() {
return role;
}
public void setRole(RoleVO1 role) {
this.role = role;
}
@Override
public String toString() {
return "UserVO1{" +
"userId='" + userId + '\'' +
", userName='" + userName + '\'' +
", roleVO1=" + role +
'}';
}
}

View File

@ -0,0 +1,75 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import java.util.List;
/**
* @author 王帅
* @since 2023-06-07
*/
public class UserVO2 {
private String userId;
private String userName;
private List<String> roles;
private List<Integer> roleIds;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public List<String> getRoles() {
return roles;
}
public void setRoles(List<String> roles) {
this.roles = roles;
}
public List<Integer> getRoleIds() {
return roleIds;
}
public void setRoleIds(List<Integer> roleIds) {
this.roleIds = roleIds;
}
@Override
public String toString() {
return "UserVO2{" +
"userId='" + userId + '\'' +
", userName='" + userName + '\'' +
", roles=" + roles +
", roleIds=" + roleIds +
'}';
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
import com.mybatisflex.annotation.Id;
import java.util.List;
/**
* @author 王帅
* @since 2023-06-07
*/
public class UserVO3 {
@Id
private String userId;
private String userName;
private List<RoleVO3> roleVO3;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public List<RoleVO3> getRoleVO3() {
return roleVO3;
}
public void setRoleVO3(List<RoleVO3> roleVO3) {
this.roleVO3 = roleVO3;
}
@Override
public String toString() {
return "UserVO3{" +
"userId='" + userId + '\'' +
", userName='" + userName + '\'' +
", roleVO3=" + roleVO3 +
'}';
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.model;
/**
* 用户 VO 对象
*
* @author 王帅
* @since 2023-06-30
*/
public class UserVO4 {
private String userId;
private String userName;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Override
public String toString() {
return "UserVO{" +
"userId='" + userId + '\'' +
", userName='" + userName + '\'' +
'}';
}
}

View File

@ -0,0 +1,108 @@
package com.mybatisflex.loveqq.test.model;//package com.mybatisflex.test.model;
//
//import com.mybatisflex.annotation.*;
//
//import java.io.Serializable;
//import java.util.List;
//
///**
// * 字段绑定测试
// * @author Ice 2023/09/16
// * @version 1.0
// */
//@Table("tb_user")
//public class UserVO5 implements Serializable {
// private static final long serialVersionUID = 474700189859144273L;
//
// @Id
// private Integer userId;
// private String userName;
// private String password;
//
// @RelationOneToOne(
// selfField = "userId",
// targetTable = "tb_id_card",
// targetField = "id",
// valueField = "idNumber"
// )
// private String idNumberCustomFieldName;
//
// @RelationOneToMany(
// selfField = "userId",
// targetTable = "tb_user_order",
// targetField = "userId",
// valueField = "orderId"
// )
// private List<Integer> orderIdList;
//
// @RelationManyToMany(
// selfField = "userId",
// targetTable = "tb_role",
// targetField = "roleId",
// valueField = "roleName",
// joinTable = "tb_user_role",
// joinSelfColumn = "user_id",
// joinTargetColumn = "role_id"
// )
// private List<String> roleNameList;
//
// public Integer getUserId() {
// return userId;
// }
//
// public void setUserId(Integer userId) {
// this.userId = userId;
// }
//
// public String getUserName() {
// return userName;
// }
//
// public void setUserName(String userName) {
// this.userName = userName;
// }
//
// public String getPassword() {
// return password;
// }
//
// public void setPassword(String password) {
// this.password = password;
// }
//
// public String getIdNumberCustomFieldName() {
// return idNumberCustomFieldName;
// }
//
// public void setIdNumberCustomFieldName(String idNumberCustomFieldName) {
// this.idNumberCustomFieldName = idNumberCustomFieldName;
// }
//
// public List<Integer> getOrderIdList() {
// return orderIdList;
// }
//
// public void setOrderIdList(List<Integer> orderIdList) {
// this.orderIdList = orderIdList;
// }
//
// public List<String> getRoleNameList() {
// return roleNameList;
// }
//
// public void setRoleNameList(List<String> roleNameList) {
// this.roleNameList = roleNameList;
// }
//
// @Override
// public String toString() {
// return "UserVO5{" +
// "userId=" + userId +
// ", userName='" + userName + '\'' +
// ", password='" + password + '\'' +
// ", idNumberCustomFieldName='" + idNumberCustomFieldName + '\'' +
// ", orderIdList=" + orderIdList +
// ", roleNameList=" + roleNameList +
// '}';
// }
//}

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.service;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Service;
import com.mybatisflex.loveqq.test.mapper.AccountMapper;
import com.mybatisflex.loveqq.test.model.Account;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
@Service
public class AccountService {
@Resource
AccountMapper accountMapper;
@Transactional
public void update2() {
int x = 1 / 0;
Account account = new Account();
account.setId(2L);
account.setUserName("haha");
accountMapper.update(account);
}
@Transactional(rollbackFor = Exception.class, timeout = 3)
public void transactionTimeTest() throws InterruptedException {
Account account = new Account();
account.setId(100L);
account.setUserName("aliothmoon");
accountMapper.insert(account);
TimeUnit.SECONDS.sleep(5);
accountMapper.selectOneById(account.getId());
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2022-2024, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.service;
import com.mybatisflex.core.service.IService;
import com.mybatisflex.loveqq.test.model.Article;
/**
* @author 王帅
* @since 2023-07-22
*/
public interface ArticleService extends IService<Article> {
void changeDataSource();
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2022-2024, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.service.impl;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Service;
import com.mybatisflex.annotation.UseDataSource;
import com.mybatisflex.core.datasource.DataSourceKey;
import com.mybatisflex.loveqq.framework.boot.autoconfig.service.ServiceImpl;
import com.mybatisflex.loveqq.test.mapper.ArticleMapper;
import com.mybatisflex.loveqq.test.model.Article;
import com.mybatisflex.loveqq.test.service.ArticleService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author 王帅
* @since 2023-07-22
*/
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {
private static final Logger LOGGER = LoggerFactory.getLogger(ArticleServiceImpl.class);
@Override
@UseDataSource("annotation ds")
public void changeDataSource() {
LOGGER.info("start1: {}", DataSourceKey.get());
DataSourceKey.use("ds outer", () -> {
LOGGER.info("start2: {}", DataSourceKey.get());
DataSourceKey.use("ds inner", () -> {
LOGGER.info("start3: {}", DataSourceKey.get());
LOGGER.info("end3: {}", DataSourceKey.get());
});
LOGGER.info("end2: {}", DataSourceKey.get());
});
LOGGER.info("end1: {}", DataSourceKey.get());
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.unmapped;
import com.mybatisflex.core.mybatis.UnMappedColumnHandler;
import com.mybatisflex.loveqq.test.model.UnmappedBaseEntity;
import org.apache.ibatis.reflection.MetaObject;
import java.util.HashMap;
import java.util.Map;
/**
* MyUnMappedColumnHandler
*
* @author wy
* @version 1.0
* @date 2024/9/12 11:34
**/
public class MyUnMappedColumnHandler implements UnMappedColumnHandler {
@Override
public void handleUnMappedColumn(MetaObject metaObject, String unmappedColumnName, Object value) {
if (metaObject.getOriginalObject() instanceof UnmappedBaseEntity){
Object object = metaObject.getValue("unmappedMap");
if(object == null){
Map<String, Object> map = new HashMap<>();
map.put(unmappedColumnName, value);
metaObject.setValue("unmappedMap", map);
}else {
((Map)object).put(unmappedColumnName, value);
}
}
}
}

View File

@ -0,0 +1,48 @@
# DataSource Config
#spring:
# # h2:
# # console:
# # enabled: true
# datasource:
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://localhost:3306/flex_test
# username: root
# password: 12345678
# driver-class-name:
# datasource:
# driver-class-name: org.h2.Driver
# username: root
# password: test
# sql:
# init:
# schema-locations: classpath:schema.sql
# data-locations: classpath:data.sql
#mybatis-flex:
# admin-config:
# enable: true
# endpoint: http://localhost/admin
# secret-key: secretKey
# mapper-locations:
# - classpath*:/mapper/*.xml
# global-config:
# print-banner: false
# key-config:
# key-type: generator
# value: uuid
# configuration:
# use-generated-keys: true
# datasource:
# data-center:
# url: jdbc:mysql://localhost:3306/flex_test
# username: root
# password: 12345678
mybatis-flex:
datasource:
ds1:
url: jdbc:mysql://localhost:3306/flex_test
username: root
password: 12345678
ds2:
url: jdbc:mysql://localhost:3306/flex_test
username: root
password: 12345678

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.mybatisflex.loveqq.test.mapper.MyAccountMapper">
<!-- <resultMap id="testResultMap" type="com.mybatisflex.test.model.UserVO">-->
<!-- <id column="user_id" property="userId"/>-->
<!-- <result column="user_name" property="userName"/>-->
<!-- <collection property="roleList" ofType="com.mybatisflex.test.model.Role">-->
<!-- <id column="role_id" property="roleId"/>-->
<!-- <result column="role_key" property="roleKey"/>-->
<!-- <result column="role_name" property="roleName"/>-->
<!-- </collection>-->
<!-- <association property="role" javaType="com.mybatisflex.test.model.Role">-->
<!-- <id column="role_id" property="roleId"/>-->
<!-- <result column="role_key" property="roleKey"/>-->
<!-- <result column="role_name" property="roleName"/>-->
<!-- </association>-->
<!-- </resultMap>-->
<!-- selectByName -->
<select id="selectByName" resultType="com.mybatisflex.loveqq.test.model.AccountDto">
select * from `tb_account` ${qwSql} limit ${pageOffset}, ${pageSize}
</select>
<select id="selectByName_COUNT" resultType="long">
select count(*) from `tb_account` ${qwSql}
</select>
<resultMap id="AccountViewObject" type="com.mybatisflex.loveqq.test.model.AccountView">
<id property="id" column="id"/>
<result property="userName" column="user_name"/>
<result property="birthday" column="birthday"/>
<association property="accountList" column="id" select="selectAssociation"/>
</resultMap>
<select id="selectViewObject" resultMap="AccountViewObject">
select id, user_name, birthday from tb_account where id = 1
</select>
<select id="selectAssociation" resultType="com.mybatisflex.loveqq.test.model.Account">
select * from tb_account where id = #{id}
</select>
</mapper>

View File

@ -0,0 +1,28 @@
package com.mybatisflex.loveqq.test;
import com.kfyty.loveqq.framework.boot.K;
import com.kfyty.loveqq.framework.core.autoconfig.ApplicationContext;
import com.kfyty.loveqq.framework.core.autoconfig.beans.AutowiredCapableSupport;
import com.kfyty.loveqq.framework.core.utils.BeanUtil;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
public class LoveqqExtension implements BeforeAllCallback, BeforeEachCallback {
private static ApplicationContext context;
private static AutowiredCapableSupport autowiredCapable;
@Override
public void beforeAll(ExtensionContext extensionContext) throws Exception {
if (context == null) {
context = K.start(SampleApplication.class);
autowiredCapable = context.getBean(AutowiredCapableSupport.BEAN_NAME);
}
}
@Override
public void beforeEach(ExtensionContext extensionContext) throws Exception {
Object instance = extensionContext.getRequiredTestInstance();
autowiredCapable.autowiredBean(BeanUtil.getBeanName(instance.getClass()), instance);
}
}

View File

@ -0,0 +1,134 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.common;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import com.mybatisflex.core.query.CPI;
import com.mybatisflex.core.query.QueryWrapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.function.Supplier;
import static com.mybatisflex.core.query.QueryMethods.count;
import static com.mybatisflex.core.query.QueryMethods.distinct;
import static com.mybatisflex.loveqq.test.model.table.AccountTableDef.ACCOUNT;
import static com.mybatisflex.loveqq.test.model.table.RoleTableDef.ROLE;
import static com.mybatisflex.loveqq.test.model.table.UserRoleTableDef.USER_ROLE;
import static com.mybatisflex.loveqq.test.model.table.UserTableDef.USER;
/**
* @author 王帅
* @since 2023-06-09
*/
class CloneTest {
@Test
void test03() {
String jsonString = JSON.toJSONString(newQueryWrapper(), JSONWriter.Feature.FieldBased, JSONWriter.Feature.ReferenceDetection);
System.out.println(jsonString);
}
@Test
void test() {
QueryWrapper queryWrapper = newQueryWrapper();
Class<QueryWrapper> queryWrapperClass = QueryWrapper.class;
int count = 10000;
/*
* new: 41ms
* clone: 65ms
* fastjson: 620ms
* serial: 2003ms
*/
calcTime(count, "new", this::newQueryWrapper);
calcTime(count, "clone", queryWrapper::clone);
calcTime(count, "fastjson", () -> SerialUtil.cloneObject(queryWrapper, queryWrapperClass));
calcTime(count, "serial", () -> SerialUtil.cloneObject(queryWrapper));
}
@Test
void test02() {
QueryWrapper queryWrapper = newQueryWrapper();
QueryWrapper queryWrapper1 = queryWrapper.clone();
QueryWrapper queryWrapper2 = SerialUtil.cloneObject(queryWrapper);
// QueryWrapper queryWrapper3 = SerialUtil.cloneObject(queryWrapper, QueryWrapper.class);
System.err.println(SerialUtil.toJSONString(queryWrapper));
System.out.println(queryWrapper.toSQL());
System.out.println(queryWrapper1.toSQL());
System.out.println(queryWrapper2.toSQL());
// System.out.println(queryWrapper3.toSQL());
Assertions.assertEquals(queryWrapper.toSQL(), queryWrapper1.toSQL());
Assertions.assertEquals(queryWrapper.toSQL(), queryWrapper2.toSQL());
// Assertions.assertEquals(queryWrapper.toSQL(), queryWrapper3.toSQL());
}
private void calcTime(int count, String type, Supplier<QueryWrapper> supplier) {
long start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
supplier.get();
}
long end = System.currentTimeMillis();
System.out.println(type + ": " + (end - start) + "ms");
}
private QueryWrapper newQueryWrapper() {
return QueryWrapper.create()
.select(count(distinct(USER.USER_ID))/*case_()
.when(USER.USER_ID.eq(3)).then("x3")
.when(USER.USER_ID.eq(5)).then("x4")
.end(),
distinct(USER.USER_ID.add(4)),
USER.USER_NAME,
ROLE.ALL_COLUMNS*/)
.from(USER.as("u"))
.leftJoin(USER_ROLE).as("ur").on(USER_ROLE.USER_ID.eq(USER.USER_ID))
.leftJoin(ROLE).as("r").on(USER_ROLE.ROLE_ID.eq(ROLE.ROLE_ID))
.where(USER.USER_ID.eq(3))
.and(ROLE.ROLE_NAME.in(Arrays.asList(1, 2, 3)))
.or(ROLE.ROLE_ID.ge(USER.USER_ID))
.groupBy(ROLE.ROLE_NAME)
.having(ROLE.ROLE_ID.ge(7))
.orderBy(ROLE.ROLE_NAME.asc());
}
@Test
void test04() {
QueryWrapper queryWrapper = QueryWrapper.create()
.from(ACCOUNT)
.select(ACCOUNT.DEFAULT_COLUMNS)
.where(ACCOUNT.ID.eq(1));
QueryWrapper clone = queryWrapper.clone();
CPI.setSelectColumns(clone, null);
clone.select(ACCOUNT.ID, ACCOUNT.USER_NAME);
String sql1 = queryWrapper.toSQL();
String sql2 = clone.toSQL();
System.out.println(sql1);
System.out.println(sql2);
Assertions.assertNotEquals(sql1, sql2);
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.mybatisflex.loveqq.test.common;
import com.mybatisflex.loveqq.test.model.Account;
import com.mybatisflex.loveqq.test.model.BaseEntity;
import com.mybatisflex.loveqq.test.model.UserVO;
import org.apache.ibatis.reflection.Reflector;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* @author 王帅
* @since 2023-06-13
*/
class FieldTest {
@Test
void test() {
String genericString = BaseEntity.class.toGenericString();
System.out.println(genericString);
}
@Test
void test02() {
Class<Account> accountClass = Account.class;
Method[] declaredMethods = accountClass.getMethods();
Arrays.stream(declaredMethods)
.filter(e -> e.getName().startsWith("get"))
.forEach(System.out::println);
}
@Test
void test03() {
Reflector reflector = new Reflector(Account.class);
Class<?> id = reflector.getGetterType("id");
Class<?> userName = reflector.getGetterType("userName");
Class<?> age = reflector.getGetterType("age");
System.out.println(id);
System.out.println(userName);
System.out.println(age);
}
@Test
void test04() {
Reflector reflector = new Reflector(UserVO.class);
Class<?> roleList = reflector.getGetterType("roleList");
System.out.println(roleList);
}
}

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