diff --git a/mybatis-flex-solon-plugin/src/main/java/com/mybatisflex/solon/MybatisFlexProperties.java b/mybatis-flex-solon-plugin/src/main/java/com/mybatisflex/solon/MybatisFlexProperties.java new file mode 100644 index 00000000..661e7efd --- /dev/null +++ b/mybatis-flex-solon-plugin/src/main/java/com/mybatisflex/solon/MybatisFlexProperties.java @@ -0,0 +1,986 @@ +/* + * Copyright (c) 2022-2024, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.solon; + +import com.mybatisflex.core.FlexConsts; +import com.mybatisflex.core.FlexGlobalConfig; +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.*; +import org.apache.ibatis.type.JdbcType; +import org.apache.ibatis.type.TypeHandler; +import org.noear.solon.core.util.ResourceUtil; + +import java.net.URI; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; +import java.util.Set; +import java.util.stream.Stream; + +/** + * Mybatis-Flex 的配置属性。 + * 参考:https://github.com/mybatis/spring-boot-starter/blob/master/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MybatisProperties.java + * + * @author Eddú Meléndez + * @author Kazuki Shimizu + * @author micahel + * @author 王帅 + */ +public class MybatisFlexProperties { + private String defaultDatasourceKey; + + /** + *

多数据源的配置。 + * + *

+ * mybatis-flex.datasource.ds1.url=***
+ * mybatis-flex.datasource.ds2.url=*** + */ + private Map> 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[]{"classpath*:/mapper/**/*.xml"}; + + /** + * Packages to search type aliases. (Package delimiters are ",; \t\n") + */ + private String typeAliasesPackage; + + /** + * The super class for filtering type alias. If this not specifies, the MyBatis deal as type alias all classes that + * searched from typeAliasesPackage. + */ + private Class typeAliasesSuperType; + + /** + * Packages to search for type handlers. (Package delimiters are ",; \t\n") + */ + private String typeHandlersPackage; + + /** + * Indicates whether perform presence check of the MyBatis xml config file. + */ + private boolean checkConfigLocation = false; + + /** + * Execution mode for {@link org.mybatis.solon.SqlSessionTemplate}. + */ + private ExecutorType executorType; + + /** + * The default scripting language driver class. (Available when use together with mybatis-spring 2.0.2+) + */ + private Class defaultScriptingLanguageDriver; + + /** + * Externalized properties for MyBatis configuration. + */ + private Properties configurationProperties; + + /** + * A Configuration object for customize default settings. If {@link #configLocation} is specified, this property is + * not used. + */ + private CoreConfiguration configuration; + + /** + * A Configuration object for seata + */ + private SeataConfig seataConfig; + + public SeataConfig getSeataConfig() { + return seataConfig; + } + + public void setSeataConfig(SeataConfig seataConfig) { + this.seataConfig = seataConfig; + } + + public Map> getDatasource() { + return datasource; + } + + public void setDatasource(Map> datasource) { + this.datasource = datasource; + } + + public GlobalConfig getGlobalConfig() { + return globalConfig; + } + + public void setGlobalConfig(GlobalConfig globalConfig) { + this.globalConfig = globalConfig; + } + + public AdminConfig getAdminConfig() { + return adminConfig; + } + + public void setAdminConfig(AdminConfig adminConfig) { + this.adminConfig = adminConfig; + } + + public String getDefaultDatasourceKey() { + return defaultDatasourceKey; + } + + public void setDefaultDatasourceKey(String defaultDatasourceKey) { + this.defaultDatasourceKey = defaultDatasourceKey; + } + + /** + * @since 1.1.0 + */ + public String getConfigLocation() { + return this.configLocation; + } + + /** + * @since 1.1.0 + */ + public void setConfigLocation(String configLocation) { + this.configLocation = configLocation; + } + + public String[] getMapperLocations() { + return this.mapperLocations; + } + + public void setMapperLocations(String[] mapperLocations) { + this.mapperLocations = mapperLocations; + } + + public String getTypeHandlersPackage() { + return this.typeHandlersPackage; + } + + public void setTypeHandlersPackage(String typeHandlersPackage) { + this.typeHandlersPackage = typeHandlersPackage; + } + + public String getTypeAliasesPackage() { + return this.typeAliasesPackage; + } + + public void setTypeAliasesPackage(String typeAliasesPackage) { + this.typeAliasesPackage = typeAliasesPackage; + } + + /** + * @since 1.3.3 + */ + public Class getTypeAliasesSuperType() { + return typeAliasesSuperType; + } + + /** + * @since 1.3.3 + */ + public void setTypeAliasesSuperType(Class typeAliasesSuperType) { + this.typeAliasesSuperType = typeAliasesSuperType; + } + + public boolean isCheckConfigLocation() { + return this.checkConfigLocation; + } + + public void setCheckConfigLocation(boolean checkConfigLocation) { + this.checkConfigLocation = checkConfigLocation; + } + + public ExecutorType getExecutorType() { + return this.executorType; + } + + public void setExecutorType(ExecutorType executorType) { + this.executorType = executorType; + } + + /** + * @since 2.1.0 + */ + public Class getDefaultScriptingLanguageDriver() { + return defaultScriptingLanguageDriver; + } + + /** + * @since 2.1.0 + */ + public void setDefaultScriptingLanguageDriver(Class defaultScriptingLanguageDriver) { + this.defaultScriptingLanguageDriver = defaultScriptingLanguageDriver; + } + + /** + * @since 1.2.0 + */ + public Properties getConfigurationProperties() { + return configurationProperties; + } + + /** + * @since 1.2.0 + */ + public void setConfigurationProperties(Properties configurationProperties) { + this.configurationProperties = configurationProperties; + } + + public CoreConfiguration getConfiguration() { + return configuration; + } + + public void setConfiguration(CoreConfiguration configuration) { + this.configuration = configuration; + } + + public URI[] resolveMapperLocations() { + return Stream.of(Optional.ofNullable(this.mapperLocations).orElse(new String[0])) + .flatMap(location -> Stream.of(getResources(location))).toArray(URI[]::new); + } + + private URI[] getResources(String location) { + return ResourceUtil.scanResources(location).stream().map(m -> URI.create(m)).toArray(URI[]::new); + } + + /** + * The configuration properties for mybatis core module. + * + * @since 3.0.0 + */ + 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 lazyLoadTriggerMethods; + + /** + * Specifies which logging implementation MyBatis should use. If this setting is not present logging implementation + * will be autodiscovered. + */ + private Class logImpl; + + /** + * Specifies VFS implementations. + */ + private Class 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 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; + + public Boolean getSafeRowBoundsEnabled() { + return safeRowBoundsEnabled; + } + + public void setSafeRowBoundsEnabled(Boolean safeRowBoundsEnabled) { + this.safeRowBoundsEnabled = safeRowBoundsEnabled; + } + + public Boolean getSafeResultHandlerEnabled() { + return safeResultHandlerEnabled; + } + + public void setSafeResultHandlerEnabled(Boolean safeResultHandlerEnabled) { + this.safeResultHandlerEnabled = safeResultHandlerEnabled; + } + + public Boolean getMapUnderscoreToCamelCase() { + return mapUnderscoreToCamelCase; + } + + public void setMapUnderscoreToCamelCase(Boolean mapUnderscoreToCamelCase) { + this.mapUnderscoreToCamelCase = mapUnderscoreToCamelCase; + } + + public Boolean getAggressiveLazyLoading() { + return aggressiveLazyLoading; + } + + public void setAggressiveLazyLoading(Boolean aggressiveLazyLoading) { + this.aggressiveLazyLoading = aggressiveLazyLoading; + } + + public Boolean getMultipleResultSetsEnabled() { + return multipleResultSetsEnabled; + } + + public void setMultipleResultSetsEnabled(Boolean multipleResultSetsEnabled) { + this.multipleResultSetsEnabled = multipleResultSetsEnabled; + } + + public Boolean getUseGeneratedKeys() { + return useGeneratedKeys; + } + + public void setUseGeneratedKeys(Boolean useGeneratedKeys) { + this.useGeneratedKeys = useGeneratedKeys; + } + + public Boolean getUseColumnLabel() { + return useColumnLabel; + } + + public void setUseColumnLabel(Boolean useColumnLabel) { + this.useColumnLabel = useColumnLabel; + } + + public Boolean getCacheEnabled() { + return cacheEnabled; + } + + public void setCacheEnabled(Boolean cacheEnabled) { + this.cacheEnabled = cacheEnabled; + } + + public Boolean getCallSettersOnNulls() { + return callSettersOnNulls; + } + + public void setCallSettersOnNulls(Boolean callSettersOnNulls) { + this.callSettersOnNulls = callSettersOnNulls; + } + + public Boolean getUseActualParamName() { + return useActualParamName; + } + + public void setUseActualParamName(Boolean useActualParamName) { + this.useActualParamName = useActualParamName; + } + + public Boolean getReturnInstanceForEmptyRow() { + return returnInstanceForEmptyRow; + } + + public void setReturnInstanceForEmptyRow(Boolean returnInstanceForEmptyRow) { + this.returnInstanceForEmptyRow = returnInstanceForEmptyRow; + } + + public Boolean getShrinkWhitespacesInSql() { + return shrinkWhitespacesInSql; + } + + public void setShrinkWhitespacesInSql(Boolean shrinkWhitespacesInSql) { + this.shrinkWhitespacesInSql = shrinkWhitespacesInSql; + } + + public Boolean getNullableOnForEach() { + return nullableOnForEach; + } + + public void setNullableOnForEach(Boolean nullableOnForEach) { + this.nullableOnForEach = nullableOnForEach; + } + + public Boolean getArgNameBasedConstructorAutoMapping() { + return argNameBasedConstructorAutoMapping; + } + + public void setArgNameBasedConstructorAutoMapping(Boolean argNameBasedConstructorAutoMapping) { + this.argNameBasedConstructorAutoMapping = argNameBasedConstructorAutoMapping; + } + + public String getLogPrefix() { + return logPrefix; + } + + public void setLogPrefix(String logPrefix) { + this.logPrefix = logPrefix; + } + + public Class getLogImpl() { + return logImpl; + } + + public void setLogImpl(Class logImpl) { + this.logImpl = logImpl; + } + + public Class getVfsImpl() { + return vfsImpl; + } + + public void setVfsImpl(Class vfsImpl) { + this.vfsImpl = vfsImpl; + } + + public Class getDefaultSqlProviderType() { + return defaultSqlProviderType; + } + + public void setDefaultSqlProviderType(Class defaultSqlProviderType) { + this.defaultSqlProviderType = defaultSqlProviderType; + } + + public LocalCacheScope getLocalCacheScope() { + return localCacheScope; + } + + public void setLocalCacheScope(LocalCacheScope localCacheScope) { + this.localCacheScope = localCacheScope; + } + + public JdbcType getJdbcTypeForNull() { + return jdbcTypeForNull; + } + + public void setJdbcTypeForNull(JdbcType jdbcTypeForNull) { + this.jdbcTypeForNull = jdbcTypeForNull; + } + + public Set getLazyLoadTriggerMethods() { + return lazyLoadTriggerMethods; + } + + public void setLazyLoadTriggerMethods(Set lazyLoadTriggerMethods) { + this.lazyLoadTriggerMethods = lazyLoadTriggerMethods; + } + + public Integer getDefaultStatementTimeout() { + return defaultStatementTimeout; + } + + public void setDefaultStatementTimeout(Integer defaultStatementTimeout) { + this.defaultStatementTimeout = defaultStatementTimeout; + } + + public Integer getDefaultFetchSize() { + return defaultFetchSize; + } + + public void setDefaultFetchSize(Integer defaultFetchSize) { + this.defaultFetchSize = defaultFetchSize; + } + + public ResultSetType getDefaultResultSetType() { + return defaultResultSetType; + } + + public void setDefaultResultSetType(ResultSetType defaultResultSetType) { + this.defaultResultSetType = defaultResultSetType; + } + + public ExecutorType getDefaultExecutorType() { + return defaultExecutorType; + } + + public void setDefaultExecutorType(ExecutorType defaultExecutorType) { + this.defaultExecutorType = defaultExecutorType; + } + + public AutoMappingBehavior getAutoMappingBehavior() { + return autoMappingBehavior; + } + + public void setAutoMappingBehavior(AutoMappingBehavior autoMappingBehavior) { + this.autoMappingBehavior = autoMappingBehavior; + } + + public AutoMappingUnknownColumnBehavior getAutoMappingUnknownColumnBehavior() { + return autoMappingUnknownColumnBehavior; + } + + public void setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior) { + this.autoMappingUnknownColumnBehavior = autoMappingUnknownColumnBehavior; + } + + public Properties getVariables() { + return variables; + } + + public void setVariables(Properties variables) { + this.variables = variables; + } + + public Boolean getLazyLoadingEnabled() { + return lazyLoadingEnabled; + } + + public void setLazyLoadingEnabled(Boolean lazyLoadingEnabled) { + this.lazyLoadingEnabled = lazyLoadingEnabled; + } + + public Class getConfigurationFactory() { + return configurationFactory; + } + + public void setConfigurationFactory(Class configurationFactory) { + this.configurationFactory = configurationFactory; + } + + public Class getDefaultEnumTypeHandler() { + return defaultEnumTypeHandler; + } + + public void setDefaultEnumTypeHandler(Class defaultEnumTypeHandler) { + this.defaultEnumTypeHandler = defaultEnumTypeHandler; + } + + public void applyTo(Configuration target) { + Optional.ofNullable(getSafeRowBoundsEnabled()).ifPresent(target::setSafeRowBoundsEnabled); + Optional.ofNullable(getSafeRowBoundsEnabled()).ifPresent(target::setSafeRowBoundsEnabled); + Optional.ofNullable(getSafeResultHandlerEnabled()).ifPresent(target::setSafeResultHandlerEnabled); + Optional.ofNullable(getMapUnderscoreToCamelCase()).ifPresent(target::setMapUnderscoreToCamelCase); + Optional.ofNullable(getAggressiveLazyLoading()).ifPresent(target::setAggressiveLazyLoading); + Optional.ofNullable(getMultipleResultSetsEnabled()).ifPresent(target::setMultipleResultSetsEnabled); + Optional.ofNullable(getUseGeneratedKeys()).ifPresent(target::setUseGeneratedKeys); + Optional.ofNullable(getUseColumnLabel()).ifPresent(target::setUseColumnLabel); + Optional.ofNullable(getCacheEnabled()).ifPresent(target::setCacheEnabled); + Optional.ofNullable(getCallSettersOnNulls()).ifPresent(target::setCallSettersOnNulls); + Optional.ofNullable(getUseActualParamName()).ifPresent(target::setUseActualParamName); + Optional.ofNullable(getReturnInstanceForEmptyRow()).ifPresent(target::setReturnInstanceForEmptyRow); + Optional.ofNullable(getShrinkWhitespacesInSql()).ifPresent(target::setShrinkWhitespacesInSql); + Optional.ofNullable(getNullableOnForEach()).ifPresent(target::setNullableOnForEach); + Optional.ofNullable(getArgNameBasedConstructorAutoMapping()).ifPresent(target::setArgNameBasedConstructorAutoMapping); + Optional.ofNullable(getLazyLoadingEnabled()).ifPresent(target::setLazyLoadingEnabled); + Optional.ofNullable(getLogPrefix()).ifPresent(target::setLogPrefix); + Optional.ofNullable(getLazyLoadTriggerMethods()).ifPresent(target::setLazyLoadTriggerMethods); + Optional.ofNullable(getDefaultStatementTimeout()).ifPresent(target::setDefaultStatementTimeout); + Optional.ofNullable(getDefaultFetchSize()).ifPresent(target::setDefaultFetchSize); + Optional.ofNullable(getLocalCacheScope()).ifPresent(target::setLocalCacheScope); + Optional.ofNullable(getJdbcTypeForNull()).ifPresent(target::setJdbcTypeForNull); + Optional.ofNullable(getDefaultResultSetType()).ifPresent(target::setDefaultResultSetType); + Optional.ofNullable(getDefaultExecutorType()).ifPresent(target::setDefaultExecutorType); + Optional.ofNullable(getAutoMappingBehavior()).ifPresent(target::setAutoMappingBehavior); + Optional.ofNullable(getAutoMappingUnknownColumnBehavior()).ifPresent(target::setAutoMappingUnknownColumnBehavior); + Optional.ofNullable(getVariables()).ifPresent(target::setVariables); + Optional.ofNullable(getLogImpl()).ifPresent(target::setLogImpl); + Optional.ofNullable(getVfsImpl()).ifPresent(target::setVfsImpl); + Optional.ofNullable(getDefaultSqlProviderType()).ifPresent(target::setDefaultSqlProviderType); + Optional.ofNullable(getConfigurationFactory()).ifPresent(target::setConfigurationFactory); + Optional.ofNullable(getDefaultEnumTypeHandler()).ifPresent(target::setDefaultEnumTypeHandler); + } + + } + + /** + * {@link FlexGlobalConfig} 配置。 + * + * @author 王帅 + * @since 2023-06-21 + */ + public static class GlobalConfig { + + /** + * 启动是否打印 banner 和 版本号。 + */ + private boolean printBanner = true; + + + /** + * 全局的 ID 生成策略配置,当 @Id 未配置 或者 配置 KeyType 为 None 时 + * 使用当前全局配置。 + */ + 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; + + + public boolean isPrintBanner() { + return printBanner; + } + + public void setPrintBanner(boolean printBanner) { + this.printBanner = printBanner; + } + + public FlexGlobalConfig.KeyConfig getKeyConfig() { + return keyConfig; + } + + public void setKeyConfig(FlexGlobalConfig.KeyConfig keyConfig) { + this.keyConfig = keyConfig; + } + + public Object getNormalValueOfLogicDelete() { + return normalValueOfLogicDelete; + } + + public void setNormalValueOfLogicDelete(Object normalValueOfLogicDelete) { + this.normalValueOfLogicDelete = normalValueOfLogicDelete; + } + + public Object getDeletedValueOfLogicDelete() { + return deletedValueOfLogicDelete; + } + + public void setDeletedValueOfLogicDelete(Object deletedValueOfLogicDelete) { + this.deletedValueOfLogicDelete = deletedValueOfLogicDelete; + } + + public int getDefaultPageSize() { + return defaultPageSize; + } + + public void setDefaultPageSize(int defaultPageSize) { + this.defaultPageSize = defaultPageSize; + } + + public int getDefaultRelationQueryDepth() { + return defaultRelationQueryDepth; + } + + public void setDefaultRelationQueryDepth(int defaultRelationQueryDepth) { + this.defaultRelationQueryDepth = defaultRelationQueryDepth; + } + + public String getLogicDeleteColumn() { + return logicDeleteColumn; + } + + public void setLogicDeleteColumn(String logicDeleteColumn) { + this.logicDeleteColumn = logicDeleteColumn; + } + + public String getTenantColumn() { + return tenantColumn; + } + + public void setTenantColumn(String tenantColumn) { + this.tenantColumn = tenantColumn; + } + + public String getVersionColumn() { + return versionColumn; + } + + public void setVersionColumn(String versionColumn) { + this.versionColumn = versionColumn; + } + + public void applyTo(FlexGlobalConfig target) { + Optional.ofNullable(isPrintBanner()).ifPresent(target::setPrintBanner); + Optional.ofNullable(getKeyConfig()).ifPresent(target::setKeyConfig); + Optional.ofNullable(getNormalValueOfLogicDelete()).ifPresent(target::setNormalValueOfLogicDelete); + Optional.ofNullable(getDeletedValueOfLogicDelete()).ifPresent(target::setDeletedValueOfLogicDelete); + Optional.ofNullable(getDefaultPageSize()).ifPresent(target::setDefaultPageSize); + Optional.ofNullable(getDefaultRelationQueryDepth()).ifPresent(target::setDefaultRelationQueryDepth); + Optional.ofNullable(getLogicDeleteColumn()).ifPresent(target::setLogicDeleteColumn); + Optional.ofNullable(getVersionColumn()).ifPresent(target::setVersionColumn); + Optional.ofNullable(getTenantColumn()).ifPresent(target::setTenantColumn); + } + + } + + /** + * MyBatis Flex Admin 配置。 + * + * @author 王帅 + * @since 2023-07-02 + */ + public static class AdminConfig { + + /** + * 启用服务。 + */ + private boolean enable; + + /** + * 连接端点。 + */ + private String endpoint; + + /** + * 秘密密钥。 + */ + private String secretKey; + + public boolean isEnable() { + return enable; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } + + public String getEndpoint() { + return endpoint; + } + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + } + + /** + * Seata 配置 + * + * @author life + */ + public static class SeataConfig { + + /** + * 是否开启 + */ + private boolean enable = false; + + /** + * 事务模式支持,只支持XA或者AT + */ + private SeataMode seataMode = SeataMode.AT; + + public boolean isEnable() { + return enable; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } + + public SeataMode getSeataMode() { + return seataMode; + } + + public void setSeataMode(SeataMode seataMode) { + this.seataMode = seataMode; + } + + } + + /** + * @author life + */ + public enum SeataMode { + XA, + AT + } +} diff --git a/mybatis-flex-solon-plugin/src/main/java/com/mybatisflex/solon/integration/MybatisAdapterFlex.java b/mybatis-flex-solon-plugin/src/main/java/com/mybatisflex/solon/integration/MybatisAdapterFlex.java index b16c9b63..a99eb3c6 100644 --- a/mybatis-flex-solon-plugin/src/main/java/com/mybatisflex/solon/integration/MybatisAdapterFlex.java +++ b/mybatis-flex-solon-plugin/src/main/java/com/mybatisflex/solon/integration/MybatisAdapterFlex.java @@ -20,6 +20,7 @@ import com.mybatisflex.core.FlexGlobalConfig; import com.mybatisflex.core.mybatis.FlexConfiguration; import com.mybatisflex.core.mybatis.FlexSqlSessionFactoryBuilder; import com.mybatisflex.core.row.RowMapperInvoker; +import com.mybatisflex.solon.MybatisFlexProperties; import com.mybatisflex.solon.mybtais.MybatisAdapterDefault; import org.apache.ibatis.mapping.Environment; import org.apache.ibatis.session.SqlSessionFactory; @@ -28,7 +29,6 @@ import org.noear.solon.core.BeanWrap; import org.noear.solon.core.Props; import org.noear.solon.core.VarHolder; import org.noear.solon.core.event.EventBus; -import org.noear.solon.core.util.ClassUtil; import javax.sql.DataSource; @@ -43,18 +43,16 @@ public class MybatisAdapterFlex extends MybatisAdapterDefault { private FlexGlobalConfig globalConfig; private RowMapperInvoker rowMapperInvoker; private Class typeAliasesBaseType; + private MybatisFlexProperties flexProperties; - protected MybatisAdapterFlex(BeanWrap dsWrap) { - super(dsWrap); + protected MybatisAdapterFlex(BeanWrap dsWrap, Props flexProps, MybatisFlexProperties flexProperties) { + this.factoryBuilderPlus = new FlexSqlSessionFactoryBuilder(); + this.flexProperties = flexProperties; - factoryBuilderPlus = new FlexSqlSessionFactoryBuilder(); - initAfter(dsWrap); - } + //初始化开始 + initStart(dsWrap, flexProps); - protected MybatisAdapterFlex(BeanWrap dsWrap, Props dsProps) { - super(dsWrap, dsProps); - - factoryBuilderPlus = new FlexSqlSessionFactoryBuilder(); + //初始化之前 initAfter(dsWrap); } @@ -72,17 +70,14 @@ public class MybatisAdapterFlex extends MybatisAdapterDefault { //for configuration section config = new FlexConfiguration(environment); - String typeAliasesBaseTypeStr = dsProps.get("typeAliasesSuperType"); - if (Utils.isNotEmpty(typeAliasesBaseTypeStr)) { - typeAliasesBaseType = ClassUtil.loadClass(typeAliasesBaseTypeStr); + if (Utils.isNotEmpty(flexProperties.getConfigurationProperties())) { + Utils.injectProperties(config, flexProperties.getConfigurationProperties()); } - Props cfgProps = dsProps.getProp("configuration"); - if (cfgProps.size() > 0) { - Utils.injectProperties(config, cfgProps); + if (flexProperties.getConfiguration() != null) { + flexProperties.getConfiguration().applyTo(config); } - //for globalConfig section if (dsWrap.typed()) { globalConfig = FlexGlobalConfig.getDefaultConfig(); @@ -90,15 +85,15 @@ public class MybatisAdapterFlex extends MybatisAdapterDefault { globalConfig = new FlexGlobalConfig(); } + if (flexProperties.getGlobalConfig() != null) { + flexProperties.getGlobalConfig().applyTo(globalConfig); + } + if (globalConfig.getKeyConfig() == null) { + //如果没有,给个默认值 globalConfig.setKeyConfig(new FlexGlobalConfig.KeyConfig()); } - Props globalProps = dsProps.getProp("globalConfig"); - if (globalProps.size() > 0) { - //尝试配置注入 - Utils.injectProperties(globalConfig, globalProps); - } globalConfig.setConfiguration(config); FlexGlobalConfig.setConfig(environment.getId(), globalConfig, false); @@ -107,6 +102,12 @@ public class MybatisAdapterFlex extends MybatisAdapterDefault { EventBus.publish(globalConfig); } + @Override + protected void loadConfiguration() { + typeAliasesBaseType = flexProperties.getTypeAliasesSuperType(); + super.loadConfiguration(); + } + /** * 获取全局配置 */ diff --git a/mybatis-flex-solon-plugin/src/main/java/com/mybatisflex/solon/integration/XPluginImpl.java b/mybatis-flex-solon-plugin/src/main/java/com/mybatisflex/solon/integration/XPluginImpl.java index 3de974a7..fd8f4aa4 100644 --- a/mybatis-flex-solon-plugin/src/main/java/com/mybatisflex/solon/integration/XPluginImpl.java +++ b/mybatis-flex-solon-plugin/src/main/java/com/mybatisflex/solon/integration/XPluginImpl.java @@ -20,12 +20,15 @@ import com.mybatisflex.annotation.UseDataSource; import com.mybatisflex.core.FlexConsts; import com.mybatisflex.core.FlexGlobalConfig; import com.mybatisflex.core.MybatisFlexBootstrap; +import com.mybatisflex.core.datasource.DataSourceBuilder; import com.mybatisflex.core.datasource.DataSourceKey; import com.mybatisflex.core.datasource.FlexDataSource; import com.mybatisflex.core.mybatis.FlexConfiguration; import com.mybatisflex.core.row.RowMapperInvoker; +import com.mybatisflex.solon.MybatisFlexProperties; import com.mybatisflex.solon.aot.MybatisRuntimeNativeRegistrar; import org.apache.ibatis.session.SqlSessionFactory; +import org.noear.solon.Utils; import org.noear.solon.annotation.Inject; import org.noear.solon.aot.RuntimeNativeRegistrar; import org.noear.solon.core.AppContext; @@ -35,7 +38,6 @@ import org.noear.solon.core.Props; import org.noear.solon.core.runtime.NativeDetector; import org.noear.solon.core.util.ClassUtil; import org.noear.solon.core.util.TmplUtil; -import org.noear.solon.data.datasource.DsUtils; import javax.sql.DataSource; import java.util.Map; @@ -47,9 +49,7 @@ import java.util.Map; * @since 2.2 */ public class XPluginImpl implements Plugin { - private static final String CONFIG_PREFIX = "mybatisFlex"; - private static final String CONFIG_DS_PREFIX = "mybatisFlex.datasource"; - private static final String CONFIG_DS_DEF = "mybatisFlex.defaultDatasourceKey"; + private static final String CONFIG_PREFIX = "mybatisFlex."; private static MybatisAdapterFlex adapterFlex; @@ -57,11 +57,20 @@ public class XPluginImpl implements Plugin { return adapterFlex; } + private Props flexProps; + private MybatisFlexProperties flexProperties; + @Override public void start(AppContext context) throws Throwable { // 注册动态数据源的事务路由 //TranManager.routing(FlexDataSource.class, new FlexDataSourceRouting()); + flexProps = context.cfg().getProp(CONFIG_PREFIX); + flexProperties = flexProps.toBean(MybatisFlexProperties.class); + if (flexProperties == null) { + flexProperties = new MybatisFlexProperties(); + } + // 订阅数据源 context.subWrapsOfType(DataSource.class, bw -> { loadDs(context, bw); @@ -72,18 +81,12 @@ public class XPluginImpl implements Plugin { context.wrapAndPut(MybatisRuntimeNativeRegistrar.class); } - // 构建 mf 配置的数据源 - Class dsDefClz = ClassUtil.loadClass("com.zaxxer.hikari.HikariDataSource"); - Props dsProps = context.cfg().getProp(CONFIG_DS_PREFIX); - String dsDef = context.cfg().get(CONFIG_DS_DEF); - if (dsProps.size() > 0) { - Map dsMap = DsUtils.buildDsMap(dsProps, dsDefClz); - - for (Map.Entry entry : dsMap.entrySet()) { + if (Utils.isNotEmpty(flexProperties.getDatasource())) { + for (Map.Entry> entry : flexProperties.getDatasource().entrySet()) { String dsName = entry.getKey(); - DataSource ds = entry.getValue(); - BeanWrap bw = context.wrap(dsName, ds, dsName.equals(dsDef)); + DataSource ds = new DataSourceBuilder(entry.getValue()).build(); + BeanWrap bw = context.wrap(dsName, ds, dsName.equals(flexProperties.getDefaultDatasourceKey())); loadDs(context, bw); } } @@ -106,7 +109,7 @@ public class XPluginImpl implements Plugin { private void initDo(AppContext context) { BeanWrap dsBw = context.wrap(FlexConsts.NAME, MybatisFlexBootstrap.getInstance().getDataSource(), true); - MybatisAdapterFlex dsFlex = new MybatisAdapterFlex(dsBw, context.cfg().getProp(CONFIG_PREFIX)); + MybatisAdapterFlex dsFlex = new MybatisAdapterFlex(dsBw, flexProps, flexProperties); dsFlex.mapperPublish(); adapterFlex = dsFlex; diff --git a/mybatis-flex-solon-plugin/src/main/java/com/mybatisflex/solon/mybtais/MybatisAdapterDefault.java b/mybatis-flex-solon-plugin/src/main/java/com/mybatisflex/solon/mybtais/MybatisAdapterDefault.java index c5a13f6a..68f205eb 100644 --- a/mybatis-flex-solon-plugin/src/main/java/com/mybatisflex/solon/mybtais/MybatisAdapterDefault.java +++ b/mybatis-flex-solon-plugin/src/main/java/com/mybatisflex/solon/mybtais/MybatisAdapterDefault.java @@ -11,7 +11,6 @@ import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.apache.ibatis.transaction.TransactionFactory; import org.apache.ibatis.type.TypeHandler; -import org.noear.solon.Solon; import org.noear.solon.Utils; import org.noear.solon.core.BeanWrap; import org.noear.solon.core.LifecycleIndex; @@ -39,28 +38,21 @@ import java.util.Map; public class MybatisAdapterDefault { protected static final Logger log = LoggerFactory.getLogger(MybatisAdapterDefault.class); - protected final BeanWrap dsWrap; - protected final Props dsProps; + protected BeanWrap dsWrap; + protected Props dsProps; //mapper 注解验证启用? - protected final boolean mapperVerifyEnabled; + protected boolean mapperVerifyEnabled; protected Configuration config; protected SqlSessionFactory factory; protected List mappers = new ArrayList<>(); protected SqlSessionFactoryBuilder factoryBuilder; - /** - * 构建Sql工厂适配器,使用默认的 typeAliases 和 mappers 配置 - */ - protected MybatisAdapterDefault(BeanWrap dsWrap) { - this(dsWrap, Solon.cfg().getProp("mybatis")); - } - /** * 构建Sql工厂适配器,使用属性配置 */ - protected MybatisAdapterDefault(BeanWrap dsWrap, Props dsProps) { + protected void initStart(BeanWrap dsWrap, Props dsProps) { this.dsWrap = dsWrap; if (dsProps == null) { this.dsProps = new Props(); @@ -80,6 +72,7 @@ public class MybatisAdapterDefault { TransactionFactory tf = new SolonManagedTransactionFactory(); Environment environment = new Environment(dataSourceId, tf, dataSource); + //1.初始化配置器 initConfiguration(environment); //加载插件(通过Bean) @@ -91,11 +84,11 @@ public class MybatisAdapterDefault { }); }); - //1.分发事件,推给扩展处理 + //2.分发事件,推给扩展处理 EventBus.publish(config); - //2.初始化(顺序不能乱) - initDo(); + //3.加载配置器的内容(顺序不能乱) + loadConfiguration(); dsWrap.context().getBeanAsync(SqlSessionFactoryBuilder.class, bean -> { factoryBuilder = bean; @@ -124,19 +117,19 @@ public class MybatisAdapterDefault { return true; } - protected boolean isTypeAliasesKey(String key){ + protected boolean isTypeAliasesKey(String key) { return key.startsWith("typeAliases[") || key.equals("typeAliases"); } - protected boolean isTypeHandlersKey(String key){ + protected boolean isTypeHandlersKey(String key) { return key.startsWith("typeHandlers[") || key.equals("typeHandlers"); } - protected boolean isMappersKey(String key){ + protected boolean isMappersKey(String key) { return key.startsWith("mappers[") || key.equals("mappers"); } - protected void initDo() { + protected void loadConfiguration() { //for typeAliases & typeHandlers section dsProps.forEach((k, v) -> { if (k instanceof String && v instanceof String) { @@ -283,9 +276,9 @@ public class MybatisAdapterDefault { MybatisMapperInterceptor handler = new MybatisMapperInterceptor(getFactory(), mapperClz); mapper = Proxy.newProxyInstance( - mapperClz.getClassLoader(), - new Class[]{mapperClz}, - handler); + mapperClz.getClassLoader(), + new Class[]{mapperClz}, + handler); mapperCached.put(mapperClz, mapper); } }