diff --git a/backend/src/main/java/com/yfd/platform/datasource/DynamicDataSource.java b/backend/src/main/java/com/yfd/platform/datasource/DynamicDataSource.java index 79dc807c..7517cb93 100644 --- a/backend/src/main/java/com/yfd/platform/datasource/DynamicDataSource.java +++ b/backend/src/main/java/com/yfd/platform/datasource/DynamicDataSource.java @@ -3,6 +3,7 @@ package com.yfd.platform.datasource; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; import javax.sql.DataSource; +import java.util.HashMap; import java.util.Map; /****************************** @@ -13,9 +14,9 @@ import java.util.Map; public class DynamicDataSource extends AbstractRoutingDataSource { private static final ThreadLocal contextHolder = new ThreadLocal<>(); - public DynamicDataSource(DataSource defaultTargetDataSource, Map targetDataSources) { + public DynamicDataSource(DataSource defaultTargetDataSource, Map targetDataSources) { super.setDefaultTargetDataSource(defaultTargetDataSource); - super.setTargetDataSources(targetDataSources); + super.setTargetDataSources(new HashMap(targetDataSources)); super.afterPropertiesSet(); } diff --git a/backend/src/main/java/com/yfd/platform/datasource/DynamicDataSourceConfig.java b/backend/src/main/java/com/yfd/platform/datasource/DynamicDataSourceConfig.java index d9e984ae..e0d4b0a0 100644 --- a/backend/src/main/java/com/yfd/platform/datasource/DynamicDataSourceConfig.java +++ b/backend/src/main/java/com/yfd/platform/datasource/DynamicDataSourceConfig.java @@ -1,6 +1,9 @@ package com.yfd.platform.datasource; import com.alibaba.druid.pool.DruidDataSource; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -11,7 +14,10 @@ import java.util.HashMap; import java.util.Map; /** - * 动态数据源配置,支持 达梦(DM) 和 Oracle 两种数据库,每种各有主从(master/slave) + * 动态数据源配置,支持 达梦(DM) 和 Oracle 两种数据库,每种各有主从(master/slave)。 + *

+ * 每个数据源可通过配置项 {@code spring.datasource.druid..enabled} 按需开启/关闭, + * 关闭后不会创建对应的连接池,也不会注册到路由数据源中。 * * @author yfd */ @@ -22,56 +28,68 @@ public class DynamicDataSourceConfig { @Bean @ConfigurationProperties("spring.datasource.druid.dm-master") + @ConditionalOnProperty(prefix = "spring.datasource.druid.dm-master", name = "enabled", havingValue = "true", matchIfMissing = true) public DataSource dmMasterDataSource() { - DruidDataSource dataSource = new DruidDataSource(); - dataSource.setBreakAfterAcquireFailure(true); - dataSource.setConnectionErrorRetryAttempts(0); - return dataSource; + return newDruidDataSource(); } @Bean @ConfigurationProperties("spring.datasource.druid.dm-slave") + @ConditionalOnProperty(prefix = "spring.datasource.druid.dm-slave", name = "enabled", havingValue = "true", matchIfMissing = true) public DataSource dmSlaveDataSource() { - DruidDataSource dataSource = new DruidDataSource(); - dataSource.setBreakAfterAcquireFailure(true); - dataSource.setConnectionErrorRetryAttempts(0); - return dataSource; + return newDruidDataSource(); } // ==================== Oracle 数据源 ==================== @Bean @ConfigurationProperties("spring.datasource.druid.oracle-master") + @ConditionalOnProperty(prefix = "spring.datasource.druid.oracle-master", name = "enabled", havingValue = "true", matchIfMissing = true) public DataSource oracleMasterDataSource() { - DruidDataSource dataSource = new DruidDataSource(); - dataSource.setBreakAfterAcquireFailure(true); - dataSource.setConnectionErrorRetryAttempts(0); - return dataSource; + return newDruidDataSource(); } @Bean @ConfigurationProperties("spring.datasource.druid.oracle-slave") + @ConditionalOnProperty(prefix = "spring.datasource.druid.oracle-slave", name = "enabled", havingValue = "true", matchIfMissing = true) public DataSource oracleSlaveDataSource() { - DruidDataSource dataSource = new DruidDataSource(); - dataSource.setBreakAfterAcquireFailure(true); - dataSource.setConnectionErrorRetryAttempts(0); - return dataSource; + return newDruidDataSource(); } // ==================== 路由数据源 ==================== @Bean @Primary - public DynamicDataSource dataSource(DataSource dmMasterDataSource, - DataSource dmSlaveDataSource, - DataSource oracleMasterDataSource, - DataSource oracleSlaveDataSource) { - Map targetDataSources = new HashMap<>(); - targetDataSources.put(DataSourceKeys.DM_MASTER, dmMasterDataSource); - targetDataSources.put(DataSourceKeys.DM_SLAVE, dmSlaveDataSource); - targetDataSources.put(DataSourceKeys.ORACLE_MASTER, oracleMasterDataSource); - targetDataSources.put(DataSourceKeys.ORACLE_SLAVE, oracleSlaveDataSource); - // 默认使用达梦主库 - return new DynamicDataSource(dmMasterDataSource, targetDataSources); + public DynamicDataSource dataSource(@Qualifier("dmMasterDataSource") ObjectProvider dmMaster, + @Qualifier("dmSlaveDataSource") ObjectProvider dmSlave, + @Qualifier("oracleMasterDataSource") ObjectProvider oracleMaster, + @Qualifier("oracleSlaveDataSource") ObjectProvider oracleSlave) { + Map targetDataSources = new HashMap<>(); + putIfPresent(targetDataSources, DataSourceKeys.DM_MASTER, dmMaster); + putIfPresent(targetDataSources, DataSourceKeys.DM_SLAVE, dmSlave); + putIfPresent(targetDataSources, DataSourceKeys.ORACLE_MASTER, oracleMaster); + putIfPresent(targetDataSources, DataSourceKeys.ORACLE_SLAVE, oracleSlave); + + // 默认优先使用达梦主库;若未开启则回退到任意一个已开启的数据源 + DataSource defaultDataSource = dmMaster.getIfAvailable(); + if (defaultDataSource == null) { + defaultDataSource = targetDataSources.values().stream().findFirst() + .orElseThrow(() -> new IllegalStateException("未开启任何数据源,请至少启用一个数据源")); + } + return new DynamicDataSource(defaultDataSource, targetDataSources); + } + + private DruidDataSource newDruidDataSource() { + DruidDataSource dataSource = new DruidDataSource(); + dataSource.setBreakAfterAcquireFailure(true); + dataSource.setConnectionErrorRetryAttempts(0); + return dataSource; + } + + private void putIfPresent(Map targetDataSources, String key, ObjectProvider provider) { + DataSource dataSource = provider.getIfAvailable(); + if (dataSource != null) { + targetDataSources.put(key, dataSource); + } } } diff --git a/backend/src/main/resources/application-dev.yml b/backend/src/main/resources/application-dev.yml index 2053da47..c9f2713d 100644 --- a/backend/src/main/resources/application-dev.yml +++ b/backend/src/main/resources/application-dev.yml @@ -1,72 +1,231 @@ server: port: 8093 - + tomcat: + connection-timeout: 300000 + max-swallow-size: 500MB spring: - #应用名称 - application: - name: Project-plateform - datasource: - type: com.alibaba.druid.pool.DruidDataSource - druid: - # ==================== 达梦(DM) 数据源 ==================== - dm-master: - driverClassName: dm.jdbc.driver.DmDriver - url: "${DB_DM_MASTER_URL:jdbc:dm://localhost:5236/WPPDB}" - username: "${DB_DM_MASTER_USERNAME:WPPDB}" - password: "${DB_DM_MASTER_PASSWORD:}" - dm-slave: - driverClassName: dm.jdbc.driver.DmDriver - url: "${DB_DM_SLAVE_URL:jdbc:dm://localhost:5236/WPPDB}" - username: "${DB_DM_SLAVE_USERNAME:WPPDB}" - password: "${DB_DM_SLAVE_PASSWORD:}" - # ==================== Oracle 数据源 ==================== - oracle-master: - driverClassName: oracle.jdbc.OracleDriver - url: "${DB_ORACLE_MASTER_URL:jdbc:oracle:thin:@localhost:1521/ORCL}" - username: "${DB_ORACLE_MASTER_USERNAME:}" - password: "${DB_ORACLE_MASTER_PASSWORD:}" - connection-properties: oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=60000;oracle.net.READ_TIMEOUT=60000 - oracle-slave: - driverClassName: oracle.jdbc.OracleDriver - url: "${DB_ORACLE_SLAVE_URL:jdbc:oracle:thin:@localhost:1521/ORCL}" - username: "${DB_ORACLE_SLAVE_USERNAME:}" - password: "${DB_ORACLE_SLAVE_PASSWORD:}" - connection-properties: oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=60000;oracle.net.READ_TIMEOUT=60000 - - mvc: - pathmatch: - matching-strategy: ant_path_matcher - data: - redis: - host: ${REDIS_HOST:localhost} - port: ${REDIS_PORT:6379} - password: ${REDIS_PASSWORD:} - timeout: 10000ms - lettuce: - pool: - max-active: 8 - max-idle: 8 - min-idle: 2 - max-wait: 10000ms - servlet: - multipart: - max-file-size: 300MB - max-request-size: 500MB - file-size-threshold: 1KB - location: /tmp/upload - resolve-lazily: true - + #应用名称 + application: + name: Project-plateform + datasource: + type: com.alibaba.druid.pool.DruidDataSource + druid: + # ==================== 达梦(DM) 数据源 ==================== + dm-master: + driverClassName: dm.jdbc.driver.DmDriver + url: "${DB_DM_MASTER_URL:jdbc:dm://172.16.21.143:5236/QGC_REFA_TEST}" + username: "${DB_DM_MASTER_USERNAME:QGC_REFA_TEST}" + password: "${DB_DM_MASTER_PASSWORD:Y4M4K1oCkL8U}" + initial-size: 5 + min-idle: 5 + max-active: 50 + max-wait: 60000 + async-init: true + keep-alive-between-time-millis: 120000 + time-between-eviction-runs-millis: 60000 + min-evictable-idle-time-millis: 180000 + max-evictable-idle-time-millis: 300000 + phy-timeout-millis: 25200000 + validation-query: SELECT 1 FROM DUAL + validation-query-timeout: 3 + test-while-idle: true + test-on-borrow: false + test-on-return: false + keep-alive: true + remove-abandoned: true + remove-abandoned-timeout: 1800 + log-abandoned: true + break-after-acquire-failure: true + time-between-connect-error-millis: 30000 + pool-prepared-statements: true + max-open-prepared-statements: 100 + max-pool-prepared-statement-per-connection-size: 100 + dm-slave: + driverClassName: dm.jdbc.driver.DmDriver + url: "${DB_DM_SLAVE_URL:jdbc:dm://172.16.21.143:5236/QGC_REFA_TEST}" + username: "${DB_DM_SLAVE_USERNAME:QGC_REFA_TEST}" + password: "${DB_DM_SLAVE_PASSWORD:Y4M4K1oCkL8U}" + initial-size: 5 + min-idle: 5 + max-active: 50 + max-wait: 60000 + async-init: true + keep-alive-between-time-millis: 120000 + time-between-eviction-runs-millis: 60000 + min-evictable-idle-time-millis: 180000 + max-evictable-idle-time-millis: 300000 + phy-timeout-millis: 25200000 + validation-query: SELECT 1 FROM DUAL + validation-query-timeout: 3 + test-while-idle: true + test-on-borrow: false + test-on-return: false + keep-alive: true + remove-abandoned: true + remove-abandoned-timeout: 1800 + log-abandoned: true + break-after-acquire-failure: true + time-between-connect-error-millis: 30000 + pool-prepared-statements: true + max-open-prepared-statements: 100 + max-pool-prepared-statement-per-connection-size: 100 + # ==================== Oracle 数据源 ==================== + # enabled=false 时不创建连接池,也不注册到路由数据源(按需开启) + oracle-master: + enabled: false + driverClassName: oracle.jdbc.OracleDriver + url: "${DB_ORACLE_MASTER_URL:jdbc:oracle:thin:@172.16.31.172:1521/SDLYZ}" + username: "${DB_ORACLE_MASTER_USERNAME:SDLY_QX}" + password: "${DB_ORACLE_MASTER_PASSWORD:jNHnqv3hH7}" + initial-size: 5 + min-idle: 5 + max-active: 20 + max-wait: 30000 + async-init: true + keep-alive-between-time-millis: 120000 + time-between-eviction-runs-millis: 60000 + min-evictable-idle-time-millis: 180000 + max-evictable-idle-time-millis: 300000 + phy-timeout-millis: 25200000 + validation-query: SELECT 1 FROM DUAL + validation-query-timeout: 3 + test-while-idle: true + test-on-borrow: false + test-on-return: false + keep-alive: true + remove-abandoned: true + remove-abandoned-timeout: 1800 + log-abandoned: true + break-after-acquire-failure: true + time-between-connect-error-millis: 30000 + pool-prepared-statements: true + max-open-prepared-statements: 100 + max-pool-prepared-statement-per-connection-size: 100 + connection-properties: oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=60000;oracle.net.READ_TIMEOUT=60000 + oracle-slave: + enabled: false + driverClassName: oracle.jdbc.OracleDriver + url: "${DB_ORACLE_SLAVE_URL:jdbc:oracle:thin:@172.16.31.172:1521/SDLYZ}" + username: "${DB_ORACLE_SLAVE_USERNAME:SDLY_QX}" + password: "${DB_ORACLE_SLAVE_PASSWORD:jNHnqv3hH7}" + initial-size: 5 + min-idle: 5 + max-active: 20 + max-wait: 30000 + async-init: true + keep-alive-between-time-millis: 120000 + time-between-eviction-runs-millis: 60000 + min-evictable-idle-time-millis: 180000 + max-evictable-idle-time-millis: 300000 + phy-timeout-millis: 25200000 + validation-query: SELECT 1 FROM DUAL + validation-query-timeout: 3 + test-while-idle: true + test-on-borrow: false + test-on-return: false + keep-alive: true + remove-abandoned: true + remove-abandoned-timeout: 1800 + log-abandoned: true + break-after-acquire-failure: true + time-between-connect-error-millis: 30000 + pool-prepared-statements: true + max-open-prepared-statements: 100 + max-pool-prepared-statement-per-connection-size: 100 + connection-properties: oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=60000;oracle.net.READ_TIMEOUT=60000 + filter: + stat: + enabled: true + log-slow-sql: true + slow-sql-millis: 3000 + merge-sql: true + slf4j: + enabled: true + wall: + enabled: true + log-violation: true + throw-exception: true + config: + select-where-alway-true-check: true + select-having-alway-true-check: true + delete-where-alway-true-check: true + update-where-alay-true-check: true + update-where-alway-true-check: true + update-where-none-check: true + multi-statement-allow: false + web-stat-filter: + enabled: true + url-pattern: /* + exclusions: '*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*' + session-stat-enable: true + principal-session-name: admin + profile-enable: true + stat-view-servlet: + enabled: true + url-pattern: /druid/* + login-username: admin + login-password: admin + reset-enable: false + jackson: + date-format: yyyy-MM-dd HH:mm:ss + time-zone: GMT+8 + mvc: + pathmatch: + matching-strategy: ant_path_matcher + data: + redis: + # host: "${REDIS_HOST:172.16.21.142}" + host: "${REDIS_HOST:localhost}" + port: "${REDIS_PORT:6379}" + password: "${REDIS_PASSWORD:}" + # password: "${REDIS_PASSWORD:zny5678}" + database: "${REDIS_DATABASE:15}" + timeout: 10000ms + lettuce: + pool: + max-active: 8 + max-idle: 8 + min-idle: 2 + max-wait: 10000ms + servlet: + multipart: + max-file-size: 300MB + max-request-size: 500MB + file-size-threshold: 1KB + location: /tmp/upload + resolve-lazily: true logging: - file: - name: logs/projectname.log - level: - com.genersoft.iot: debug - com.genersoft.iot.vmp.storager.dao: info - com.genersoft.iot.vmp.gb28181: info + file: + name: logs/platform-dev.log + level: + root: info + com.yfd.platform: info + com.yfd.platform.common.MicroservicDynamicSQLMapper: info + # ... existing code ... +# com.yfd.platform.*.mapper: trace # 在线文档: swagger-ui(生产环境建议关闭) swagger-ui: - enabled: true + enabled: true + +mybatis-plus: + # mapper-locations: classpath*:**/mapper/*Mapper.xml,classpath*:**/mapping/*Mapper.xml + global-config: + banner: false + db-config: + id-type: ASSIGN_ID + insert-strategy: not_null + update-strategy: not_null + select-strategy: not_empty + table-underline: true + logic-delete-value: 1 + logic-not-delete-value: 0 + logic-delete-field: isDeleted + configuration: + map-underscore-to-camel-case: true + cache-enabled: false + log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl +# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 登录相关配置 @@ -84,7 +243,7 @@ login: app: # ZIP导入临时目录配置 zip-import: - temp-dir: ${ZIP_IMPORT_TEMP_DIR:D:\qgc-platform\zip_import_temp} + temp-dir: ${ZIP_IMPORT_TEMP_DIR:/qgc-platform/tmp/zip_import_temp} init: enabled: false schema: classpath:db-init/sql/min-schema.sql @@ -111,8 +270,8 @@ ip: file-space: #项目文档空间 - files: D:\qgc-platform\files\ #单独上传的文件附件 - system: D:\qgc-platform\system\ #单独上传的文件 + files: /qgc-platform/files/ #单独上传的文件附件 + system: /qgc-platform/system/ #单独上传的文件 task: pool: @@ -129,4 +288,4 @@ attachment: token: ${ATTACHMENT_TOKEN:qgcBkod25ngBa4wu8BtfCPYsJ7lQGVDoexH} upload-url: ${ATTACHMENT_UPLOAD_URL:http://172.16.31.185:18200/upload} video-url: ${ATTACHMENT_VIDEO_URL:http://172.16.31.185:18200/upload} - delete-url: ${ATTACHMENT_DELETE_URL:http://172.16.31.185:18200/FileDelete} + delete-url: ${ATTACHMENT_DELETE_URL:http://172.16.31.185:18200/FileDelete} \ No newline at end of file diff --git a/backend/src/main/resources/application-prod.yml b/backend/src/main/resources/application-prod.yml index b7c9abc9..5d3ae588 100644 --- a/backend/src/main/resources/application-prod.yml +++ b/backend/src/main/resources/application-prod.yml @@ -18,8 +18,8 @@ spring: password: "${DB_DM_MASTER_PASSWORD:Y4M4K1oCkL8U}" initial-size: 5 min-idle: 5 - max-active: 20 - max-wait: 30000 + max-active: 50 + max-wait: 60000 async-init: true keep-alive-between-time-millis: 120000 time-between-eviction-runs-millis: 60000 @@ -47,8 +47,8 @@ spring: password: "${DB_DM_SLAVE_PASSWORD:Y4M4K1oCkL8U}" initial-size: 5 min-idle: 5 - max-active: 20 - max-wait: 30000 + max-active: 50 + max-wait: 60000 async-init: true keep-alive-between-time-millis: 120000 time-between-eviction-runs-millis: 60000 @@ -70,7 +70,9 @@ spring: max-open-prepared-statements: 100 max-pool-prepared-statement-per-connection-size: 100 # ==================== Oracle 数据源 ==================== + # enabled=false 时不创建连接池,也不注册到路由数据源(按需开启) oracle-master: + enabled: false driverClassName: oracle.jdbc.OracleDriver url: "${DB_ORACLE_MASTER_URL:jdbc:oracle:thin:@172.16.31.172:1521/SDLYZ}" username: "${DB_ORACLE_MASTER_USERNAME:SDLY_QX}" @@ -101,6 +103,7 @@ spring: max-pool-prepared-statement-per-connection-size: 100 connection-properties: oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=60000;oracle.net.READ_TIMEOUT=60000 oracle-slave: + enabled: false driverClassName: oracle.jdbc.OracleDriver url: "${DB_ORACLE_SLAVE_URL:jdbc:oracle:thin:@172.16.31.172:1521/SDLYZ}" username: "${DB_ORACLE_SLAVE_USERNAME:SDLY_QX}"