dataSources = dataSourceProperties.getDataSources();
- // 0索引作为主数据源
- addPrimaryMap(TenantConstant.DEFAULT_TENANT_ID, buildDataSource(TenantConstant.DEFAULT_TENANT_ID, dataSources.get(0)));
- dataSources.remove(0);
- // 非0索引的备用
+ for (int i = 0; i < dataSources.size(); i++) {
+ // 0索引作为主数据源
+ Object dataSource = buildDataSource(TenantConstant.DEFAULT_TENANT_ID, dataSources.get(i));
+ if (Objects.isNull(dataSource)) {
+ // 默认的主数据源挂了
+ // 加入到错误数据源Map 等待重试
+ NotOnlineDatasourceMonitor.addErrorDatasource(TenantConstant.DEFAULT_TENANT_ID, dataSources.get(i));
+ dataSources.remove(i);
+ } else {
+ addPrimaryMap(TenantConstant.DEFAULT_TENANT_ID, dataSource);
+ dataSources.remove(i);
+ break;
+ }
+ }
+
+ if (CollUtil.isEmpty(PRIMARY_DATASOURCE_MAP)) {
+ log.error("主系统配置数据源全部无效, 请检查 yml 中相关配置");
+ }
+ // 其他数据源备用
addBackupMap(TenantConstant.DEFAULT_TENANT_ID, dataSources);
// 刷新数据源
- dataSource.freshDataSource(PRIMARY_DATASOURCE_MAP);
+ this.dataSource.freshDataSource(PRIMARY_DATASOURCE_MAP);
}
private void initTenant() {
@@ -106,10 +122,19 @@ public class DynamicDataSourceConfig {
for (int i = 0; i < dataSources.size(); i++) {
DynamicDataSource dynamicDataSource = dataSources.get(i);
if (BaseEnum.YES.getCode().equals(dynamicDataSource.getIsPrimary())) {
- addPrimaryMap(tenantId, buildDataSource(dataSources.get(i).getTenantId(), dataSources.get(i)));
- // 去除主要数据源,剩下皆为备用数据源
- dataSources.remove(i);
- break;
+ Object dataSource = buildDataSource(dataSources.get(i).getTenantId(), dataSources.get(i));
+ if (Objects.isNull(dataSource)) {
+ // 默认的主数据源挂了
+ // 加入到错误数据源Map 等待重试
+ NotOnlineDatasourceMonitor.addErrorDatasource(tenantId, dataSources.get(i));
+ // 在数据源集合中删除, 防止将错误的数据源加载到备用数据源中
+ dataSources.remove(i);
+ } else {
+ addPrimaryMap(tenantId, dataSource);
+ // 去除主要数据源,剩下皆为备用数据源
+ dataSources.remove(i);
+ break;
+ }
}
}
// 备用数据源
@@ -129,6 +154,17 @@ public class DynamicDataSourceConfig {
public void changePrimaryDatasource(String tenantId, Object datasource) {
PRIMARY_DATASOURCE_MAP.put(tenantId, datasource);
+ // 将数据源的类型保存
+ DruidPooledConnection connection = null;
+ try {
+ connection = ((DruidDataSource) datasource).getConnection();
+ TENANT_DATASOURCE_TYPE_MAP.put(tenantId, connection.getMetaData().getDatabaseProductName());
+ } catch (SQLException e) {
+ e.printStackTrace();
+ } finally {
+ // 归还 connection
+ IoUtil.close(connection);
+ }
dataSource.freshDataSource(PRIMARY_DATASOURCE_MAP);
}
diff --git a/qiaoba-commons/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/monitor/NotOnlineDatasourceMonitor.java b/qiaoba-commons/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/monitor/NotOnlineDatasourceMonitor.java
new file mode 100644
index 0000000..bcabc3e
--- /dev/null
+++ b/qiaoba-commons/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/monitor/NotOnlineDatasourceMonitor.java
@@ -0,0 +1,117 @@
+package com.qiaoba.common.database.monitor;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.ListUtil;
+import com.baomidou.lock.LockInfo;
+import com.baomidou.lock.LockTemplate;
+import com.qiaoba.common.database.config.DynamicDataSourceConfig;
+import com.qiaoba.common.database.entity.DynamicDataSource;
+import com.qiaoba.common.database.utils.JdbcUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 不在线的数据源监控
+ * 尝试连接,如果连接成功,加入到备用数据源
+ *
+ * @author ailanyin
+ * @version 1.0
+ * @since 2023/6/26 10:46
+ */
+@Component
+@Slf4j
+public class NotOnlineDatasourceMonitor {
+
+ /**
+ * 错误数据源(连接中断)
+ *
+ * key: 租户ID
+ * value: 错误数据源 list
+ */
+ public static Map> ERROR_DATASOURCE_MAP = new ConcurrentHashMap<>();
+
+ private static final String LOCK_KEY = "lock4j:notOnlineDatasourceMonitor";
+
+ @Resource
+ private LockTemplate lockTemplate;
+
+
+ @PostConstruct
+ public void init() {
+ // 10s 运行一次
+ new Timer().schedule(new TimerTask() {
+ @Override
+ public void run() {
+ // 项目启动时加载数据源还未完成
+ if (!DynamicDataSourceConfig.COMPLETE_LOAD_DATASOURCE) {
+ return;
+ }
+ // 没有暂时失联的数据源, 直接结束
+ if (CollUtil.isEmpty(ERROR_DATASOURCE_MAP)) {
+ return;
+ }
+ // expire = -1 锁自动续期, 防止数据源过多或异常等待, 超过默认锁 30s
+ final LockInfo lockInfo = lockTemplate.lock(LOCK_KEY, -1, 1000);
+ //申请锁失败 说明集群中其他设备正在执行监控
+ if (null == lockInfo) {
+ return;
+ }
+ //申请锁成功
+ try {
+ log.trace("开始-[错误数据源重试]-线程, 时间: {}", new Date());
+ tryConnect();
+ log.trace("结束-[错误数据源重试]-线程, 时间: {}", new Date());
+ } finally {
+ // 释放锁
+ lockTemplate.releaseLock(lockInfo);
+ }
+
+ }
+ }, 0, 10 * 1000);
+ }
+
+ private void tryConnect() {
+ Set tenantIds = ERROR_DATASOURCE_MAP.keySet();
+ for (String tenantId : tenantIds) {
+ List errorDatasourceList = ERROR_DATASOURCE_MAP.get(tenantId);
+ for (int i = 0; i < errorDatasourceList.size(); i++) {
+ DynamicDataSource errorDatasource = errorDatasourceList.get(i);
+ // 说明连接成功
+ boolean check = JdbcUtil.checkConnect(errorDatasource.getDriver(), errorDatasource.getUrl(), errorDatasource.getUsername(), errorDatasource.getPassword());
+ if (check) {
+ log.info("数据源重连成功, Url: {}", errorDatasource.getUrl());
+ // 从errorMap中删除
+ errorDatasourceList.remove(errorDatasource);
+ if (CollUtil.isEmpty(errorDatasourceList)) {
+ ERROR_DATASOURCE_MAP.remove(tenantId);
+ }
+ // 加入到备用Map中
+ addBackupMap(tenantId, errorDatasource);
+ }
+ }
+ }
+ }
+
+ private void addBackupMap(String tenantId, DynamicDataSource dataSource) {
+ List dataSourceList = DynamicDataSourceConfig.BACKUP_DATASOURCE_MAP.get(tenantId);
+ if (CollUtil.isEmpty(dataSourceList)) {
+ DynamicDataSourceConfig.BACKUP_DATASOURCE_MAP.put(tenantId, ListUtil.toList(dataSource));
+ } else {
+ dataSourceList.add(dataSource);
+ }
+ }
+
+ public static void addErrorDatasource(String tenantId, DynamicDataSource dataSource) {
+ List errorDataSourceList = NotOnlineDatasourceMonitor.ERROR_DATASOURCE_MAP.get(tenantId);
+ if (CollUtil.isEmpty(errorDataSourceList)) {
+ NotOnlineDatasourceMonitor.ERROR_DATASOURCE_MAP.put(tenantId, ListUtil.toList(dataSource));
+ } else {
+ errorDataSourceList.add(dataSource);
+ }
+ }
+}
diff --git a/qiaoba-commons/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/monitor/DatasourceConnectionMonitor.java b/qiaoba-commons/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/monitor/OnlineDatasourceMonitor.java
similarity index 53%
rename from qiaoba-commons/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/monitor/DatasourceConnectionMonitor.java
rename to qiaoba-commons/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/monitor/OnlineDatasourceMonitor.java
index 945cc11..e0b600c 100644
--- a/qiaoba-commons/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/monitor/DatasourceConnectionMonitor.java
+++ b/qiaoba-commons/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/monitor/OnlineDatasourceMonitor.java
@@ -1,5 +1,6 @@
package com.qiaoba.common.database.monitor;
+import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.lock.LockInfo;
@@ -9,39 +10,40 @@ import com.qiaoba.common.base.enums.DataBaseEnum;
import com.qiaoba.common.database.config.DynamicDataSourceConfig;
import com.qiaoba.common.database.entity.DynamicDataSource;
import com.qiaoba.common.database.service.DynamicDatasourceService;
+import com.qiaoba.common.database.utils.JdbcUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.sql.Connection;
-import java.sql.ResultSet;
import java.sql.SQLException;
-import java.sql.Statement;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
- * 监控-数据源连接监控
+ * 在线的数据源监控
+ * 尝试连接, 如果连接不成功, 替换可用数据源, 将失败数据源加入到错误数据源, 等待重试
*
* @author ailanyin
* @version 1.0
- * @since 2023/6/14 14:48
+ * @since 2023/6/26 10:46
*/
@Component
@Slf4j
-public class DatasourceConnectionMonitor {
+public class OnlineDatasourceMonitor {
+
+ private static final String LOCK_KEY = "lock4j:onlineDatasourceMonitor";
+ private static Map WAIT_UPDATE_DATASOURCE_STATUS = new ConcurrentHashMap<>();
+ private static Map> WAIT_ADD_ERROR_MAP = new ConcurrentHashMap<>();
+
+ @Resource
+ private LockTemplate lockTemplate;
@Resource
private DynamicDataSourceConfig dynamicDataSourceConfig;
@Resource
private DynamicDatasourceService dynamicDatasourceService;
- @Resource
- private LockTemplate lockTemplate;
-
- private static Map WAIT_UPDATE_DATASOURCE_STATUS = new ConcurrentHashMap<>();
-
- private static final String LOCK_KEY = "lock4j:datasourceConnectionMonitor";
@PostConstruct
public void init() {
@@ -49,7 +51,7 @@ public class DatasourceConnectionMonitor {
new Timer().schedule(new TimerTask() {
@Override
public void run() {
- // 项目加载数据源还未完成
+ // 项目启动时加载数据源还未完成
if (!DynamicDataSourceConfig.COMPLETE_LOAD_DATASOURCE) {
return;
}
@@ -62,8 +64,9 @@ public class DatasourceConnectionMonitor {
}
//申请锁成功
try {
- // 执行监控
- datasourceConnectionMonitor();
+ log.trace("开始运行数据源监控线程, 时间: {}", new Date());
+ tryConnect();
+ log.trace("结束运行数据源监控线程, 时间: {}", new Date());
} finally {
// 释放锁
lockTemplate.releaseLock(lockInfo);
@@ -73,83 +76,62 @@ public class DatasourceConnectionMonitor {
}, 0, 1000);
}
- /**
- * 核心监控内容
- */
- private void datasourceConnectionMonitor() {
- log.trace("开始运行数据源监控线程, 时间: {}", new Date());
+ private void tryConnect() {
for (String tenantId : DynamicDataSourceConfig.TENANT_IDS) {
Object primary = DynamicDataSourceConfig.PRIMARY_DATASOURCE_MAP.get(tenantId);
+ DynamicDataSourceConfig.BACKUP_DATASOURCE_MAP.get(tenantId);
if (Objects.isNull(primary)) {
// 说明初始化主要数据源的时候出错
log.error("租户[{}]-目前主数据源异常, 开始切换备用数据源", tenantId);
- // 切换备用数据源
- changePrimary(tenantId);
- } else {
- DruidDataSource dataSource = (DruidDataSource) primary;
- Connection connection = null;
- try {
- connection = dataSource.getConnection();
- if (check(connection, tenantId)) {
- // 说明数据源正常
- log.trace("租户[{}]-目前主数据源正常, 无需切换数据源", tenantId);
- // 主数据 处理任务
- if (TenantConstant.DEFAULT_TENANT_ID.equals(tenantId)) {
- handleJob();
- }
- continue;
- }
+ // 切换备用数据源为主数据源
+ backToPrimary(tenantId);
+ continue;
+ }
- log.error("租户[{}]-目前主数据源异常, 开始切换备用数据源", tenantId);
- // 主数据源异常 切换备用数据源
- if (changePrimary(tenantId)) {
- // 备用切换成功, 关闭原有异常数据源
- IoUtil.close(dataSource);
+ DruidDataSource dataSource = (DruidDataSource) primary;
+ Connection connection = null;
+ try {
+ connection = dataSource.getConnection();
+ if (JdbcUtil.checkConnect(connection)) {
+ // 说明数据源正常
+ log.trace("租户[{}]-目前主数据源正常, 无需切换数据源", tenantId);
+ // 系统默认主数据源 处理任务
+ if (TenantConstant.DEFAULT_TENANT_ID.equals(tenantId)) {
+ handleUpdateDatasourceStatus();
+ handleErrorDatasource();
}
- } catch (SQLException e) {
-
- } finally {
- IoUtil.close(connection);
+ continue;
}
+
+ log.error("租户[{}]-目前主数据源异常, 开始切换备用数据源", tenantId);
+ // 主数据源异常 切换备用数据源
+ if (!backToPrimary(tenantId)) {
+ // 备用切换失败
+ // 关闭原有异常数据源
+ IoUtil.close(dataSource);
+ // 在数据源Map中删除
+ DynamicDataSourceConfig.PRIMARY_DATASOURCE_MAP.remove(tenantId);
+ }
+ // 将原有异常数据源加入到错误数据源Map, 等待重试
+ addErrorDatasource(tenantId, dataSource);
+
+ } catch (SQLException e) {
+
+ } finally {
+ IoUtil.close(connection);
}
}
-
- log.trace("结束运行数据源监控线程, 时间: {}", new Date());
}
/**
- * 检查数据源连接可用性
- *
- * @param conn 数据源
- * @param tenantId 租户ID
- * @return 结果
- */
- private Boolean check(Connection conn, String tenantId) {
- Statement stmt = null;
- ResultSet rs = null;
- try {
- stmt = conn.createStatement();
- // 允许 2s 延时
- stmt.setQueryTimeout(2);
- rs = stmt.executeQuery(DataBaseEnum.getCheckSql(DynamicDataSourceConfig.TENANT_DATASOURCE_TYPE_MAP.get(tenantId)));
- return true;
- } catch (Exception e) {
- return false;
- } finally {
- IoUtil.close(rs);
- IoUtil.close(stmt);
- }
- }
-
- /**
- * 切换主数据源
+ * 切换备用数据源为主数据源
*
* @param tenantId 租户ID
*/
- private Boolean changePrimary(String tenantId) {
+ private Boolean backToPrimary(String tenantId) {
// 备用数据源
List dataSources = DynamicDataSourceConfig.BACKUP_DATASOURCE_MAP.get(tenantId);
- if (Objects.isNull(dataSources)) {
+ if (CollUtil.isEmpty(dataSources)) {
log.error("租户:[{}]切换备用数据源失败, 原因: 没有备用数据源", tenantId);
return false;
}
@@ -184,7 +166,7 @@ public class DatasourceConnectionMonitor {
}
}
- private void handleJob() {
+ private void handleUpdateDatasourceStatus() {
Set keys = WAIT_UPDATE_DATASOURCE_STATUS.keySet();
for (String key : keys) {
try {
@@ -195,8 +177,46 @@ public class DatasourceConnectionMonitor {
WAIT_UPDATE_DATASOURCE_STATUS.remove(key);
log.info("更新数据库中租户数据源状态完成, 租户ID: {}", key);
} catch (Exception e) {
- log.error("更新数据库中租户数据源状态完成, 租户ID: {}, 失败原因: {}", key, e.getMessage());
+ log.error("更新数据库中租户数据源状态未完成, 租户ID: {}, 失败原因: {}", key, e.getMessage());
}
}
}
+
+ private void handleErrorDatasource() {
+ Set tenantIds = WAIT_ADD_ERROR_MAP.keySet();
+ for (String tenantId : tenantIds) {
+ List ipList = WAIT_ADD_ERROR_MAP.get(tenantId);
+ for (String ip : ipList) {
+ NotOnlineDatasourceMonitor.addErrorDatasource(tenantId, dynamicDatasourceService.selectByIp(tenantId, ip));
+ }
+ WAIT_ADD_ERROR_MAP.remove(tenantId);
+ }
+ }
+
+ private void addErrorDatasource(String tenantId, DruidDataSource dataSource) {
+ // 主系统
+ if (TenantConstant.DEFAULT_TENANT_ID.equals(tenantId)) {
+ DynamicDataSource dynamicDataSource = new DynamicDataSource();
+ dynamicDataSource.setPassword(dataSource.getPassword());
+ dynamicDataSource.setUsername(dataSource.getUsername());
+ dynamicDataSource.setUrl(dataSource.getUrl());
+ dynamicDataSource.setDriver(dataSource.getDriverClassName());
+ dynamicDataSource.setTenantId(tenantId);
+ dynamicDataSource.setInitialSize(dataSource.getInitialSize());
+ dynamicDataSource.setMaxActive(dataSource.getMaxActive());
+ dynamicDataSource.setMinIdle(dataSource.getMinIdle());
+ NotOnlineDatasourceMonitor.addErrorDatasource(tenantId, dynamicDataSource);
+ return;
+ }
+
+
+ // 普通租户
+ String ip = DataBaseEnum.getIp(dataSource.getUrl(), dataSource.getDriverClassName());
+ List errorIpList = WAIT_ADD_ERROR_MAP.get(tenantId);
+ if (CollUtil.isEmpty(errorIpList)) {
+ WAIT_ADD_ERROR_MAP.put(tenantId, CollUtil.toList(ip));
+ } else {
+ errorIpList.add(ip);
+ }
+ }
}
diff --git a/qiaoba-commons/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/service/DynamicDatasourceService.java b/qiaoba-commons/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/service/DynamicDatasourceService.java
index 6886db8..9729ea2 100644
--- a/qiaoba-commons/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/service/DynamicDatasourceService.java
+++ b/qiaoba-commons/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/service/DynamicDatasourceService.java
@@ -28,4 +28,13 @@ public interface DynamicDatasourceService {
* @param datasourceId 数据源ID
*/
void changePrimaryDatasource(String tenantId, String datasourceId);
+
+ /**
+ * 通过IP查询
+ *
+ * @param tenantId tenantId
+ * @param ip ip
+ * @return obj
+ */
+ DynamicDataSource selectByIp(String tenantId, String ip);
}
diff --git a/qiaoba-commons/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/utils/JdbcUtil.java b/qiaoba-commons/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/utils/JdbcUtil.java
index b9d5ad4..3c5e1b1 100644
--- a/qiaoba-commons/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/utils/JdbcUtil.java
+++ b/qiaoba-commons/qiaoba-common-datasource/src/main/java/com/qiaoba/common/database/utils/JdbcUtil.java
@@ -2,11 +2,15 @@ package com.qiaoba.common.database.utils;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
+import com.qiaoba.common.base.enums.DataBaseEnum;
import com.qiaoba.common.base.exceptions.ServiceException;
+import com.qiaoba.common.database.config.DynamicDataSourceConfig;
import lombok.extern.slf4j.Slf4j;
import java.sql.Connection;
import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.Statement;
/**
* JdbcUtil
@@ -42,6 +46,29 @@ public class JdbcUtil {
}
}
+ /**
+ * 检查数据源连接可用性
+ *
+ * @param conn 数据源
+ * @return 结果
+ */
+ public static boolean checkConnect(Connection conn) {
+ Statement stmt = null;
+ ResultSet rs = null;
+ try {
+ stmt = conn.createStatement();
+ // 允许 2s 延时
+ stmt.setQueryTimeout(2);
+ rs = stmt.executeQuery(DataBaseEnum.getCheckSql(conn.getMetaData().getDatabaseProductName()));
+ return true;
+ } catch (Exception e) {
+ return false;
+ } finally {
+ IoUtil.close(rs);
+ IoUtil.close(stmt);
+ }
+ }
+
public static Connection getConnection(String driver, String url, String username, String password) {
Connection conn = null;
try {
diff --git a/qiaoba-commons/qiaoba-common-datasource/src/main/resources/META-INF/spring.factories b/qiaoba-commons/qiaoba-common-datasource/src/main/resources/META-INF/spring.factories
index d0230dc..ee3a243 100644
--- a/qiaoba-commons/qiaoba-common-datasource/src/main/resources/META-INF/spring.factories
+++ b/qiaoba-commons/qiaoba-common-datasource/src/main/resources/META-INF/spring.factories
@@ -1,6 +1,7 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.qiaoba.common.database.factories.DynamicDataSourceFactory,\
- com.qiaoba.common.database.monitor.DatasourceConnectionMonitor,\
+ com.qiaoba.common.database.monitor.OnlineDatasourceMonitor,\
+ com.qiaoba.common.database.monitor.NotOnlineDatasourceMonitor,\
com.qiaoba.common.database.handlers.schema.SchemaHandlerFactory,\
com.qiaoba.common.database.handlers.schema.MysqlSchemaHandler,\
com.qiaoba.common.database.config.MybatisPlusConfig
diff --git a/qiaoba-modules/pom.xml b/qiaoba-modules/pom.xml
index ff7861b..e16b796 100644
--- a/qiaoba-modules/pom.xml
+++ b/qiaoba-modules/pom.xml
@@ -18,6 +18,7 @@
qiaoba-module-monitor
qiaoba-module-tenant
qiaoba-module-demo
+ qiaoba-module-generator
qiaoba-modules: 新建的模块, 统一放在这个模块下面
diff --git a/qiaoba-modules/qiaoba-module-generator/pom.xml b/qiaoba-modules/qiaoba-module-generator/pom.xml
new file mode 100644
index 0000000..9780049
--- /dev/null
+++ b/qiaoba-modules/qiaoba-module-generator/pom.xml
@@ -0,0 +1,34 @@
+
+
+
+ qiaoba-modules
+ com.qiaoba
+ 1.0
+
+ 4.0.0
+
+ qiaoba-module-generator
+
+ 代码生成
+
+
+
+ com.qiaoba
+ qiaoba-common-base
+
+
+ com.qiaoba
+ qiaoba-common-datasource
+
+
+ com.qiaoba
+ qiaoba-common-web
+
+
+ org.apache.velocity
+ velocity-engine-core
+
+
+
diff --git a/qiaoba-modules/qiaoba-module-generator/src/main/java/com/qiaoba/module/generator/controller/GenController.java b/qiaoba-modules/qiaoba-module-generator/src/main/java/com/qiaoba/module/generator/controller/GenController.java
new file mode 100644
index 0000000..928c111
--- /dev/null
+++ b/qiaoba-modules/qiaoba-module-generator/src/main/java/com/qiaoba/module/generator/controller/GenController.java
@@ -0,0 +1,20 @@
+package com.qiaoba.module.generator.controller;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 代码生成 Web层
+ *
+ * @author ailanyin
+ * @version 1.0
+ * @since 2023/6/26 9:09
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/tool/gen")
+public class GenController {
+}
diff --git a/qiaoba-modules/qiaoba-module-generator/src/main/java/com/qiaoba/module/generator/entity/dto/TableDto.java b/qiaoba-modules/qiaoba-module-generator/src/main/java/com/qiaoba/module/generator/entity/dto/TableDto.java
new file mode 100644
index 0000000..0e7074a
--- /dev/null
+++ b/qiaoba-modules/qiaoba-module-generator/src/main/java/com/qiaoba/module/generator/entity/dto/TableDto.java
@@ -0,0 +1,36 @@
+package com.qiaoba.module.generator.entity.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 数据库表信息
+ *
+ * @author ailanyin
+ * @version 1.0
+ * @since 2023/6/26 9:21
+ */
+@Data
+public class TableDto implements Serializable {
+
+ /**
+ * 表名称
+ */
+ private String tableName;
+
+ /**
+ * 表描述
+ */
+ private String tableComment;
+
+ /**
+ * 数据库类型 Mysql/Oracle/PgSql/Sql Server
+ */
+ private String dbType;
+
+ /**
+ * 模式
+ */
+ private String schema;
+}
diff --git a/qiaoba-modules/qiaoba-module-generator/src/main/java/com/qiaoba/module/generator/entity/vo/DbTableVo.java b/qiaoba-modules/qiaoba-module-generator/src/main/java/com/qiaoba/module/generator/entity/vo/DbTableVo.java
new file mode 100644
index 0000000..48d8e3e
--- /dev/null
+++ b/qiaoba-modules/qiaoba-module-generator/src/main/java/com/qiaoba/module/generator/entity/vo/DbTableVo.java
@@ -0,0 +1,38 @@
+package com.qiaoba.module.generator.entity.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 数据库表信息
+ *
+ * @author ailanyin
+ * @version 1.0
+ * @since 2023/6/26 9:21
+ */
+@Data
+public class DbTableVo implements Serializable {
+
+ /**
+ * 表名称
+ */
+ private String tableName;
+
+ /**
+ * 表描述
+ */
+ private String tableComment;
+
+ /**
+ * 创建时间
+ */
+ private Date createTime;
+
+ /**
+ * 更新时间
+ */
+ private Date updateTime;
+
+}
diff --git a/qiaoba-modules/qiaoba-module-generator/src/main/java/com/qiaoba/module/generator/mapper/TableMapper.java b/qiaoba-modules/qiaoba-module-generator/src/main/java/com/qiaoba/module/generator/mapper/TableMapper.java
new file mode 100644
index 0000000..176e737
--- /dev/null
+++ b/qiaoba-modules/qiaoba-module-generator/src/main/java/com/qiaoba/module/generator/mapper/TableMapper.java
@@ -0,0 +1,25 @@
+package com.qiaoba.module.generator.mapper;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.qiaoba.module.generator.entity.dto.TableDto;
+import com.qiaoba.module.generator.entity.vo.DbTableVo;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 数据库表 数据层
+ *
+ * @author ailanyin
+ * @version 1.0
+ * @since 2023/6/26 9:24
+ */
+public interface TableMapper {
+
+ /**
+ * 查询数据库表
+ *
+ * @param page 分页
+ * @param dto 查询参数
+ * @return list
+ */
+ Page selectPageDbTableList(Page page, @Param("dto") TableDto dto);
+}
diff --git a/qiaoba-modules/qiaoba-module-generator/src/main/java/com/qiaoba/module/generator/service/TableService.java b/qiaoba-modules/qiaoba-module-generator/src/main/java/com/qiaoba/module/generator/service/TableService.java
new file mode 100644
index 0000000..63517ba
--- /dev/null
+++ b/qiaoba-modules/qiaoba-module-generator/src/main/java/com/qiaoba/module/generator/service/TableService.java
@@ -0,0 +1,25 @@
+package com.qiaoba.module.generator.service;
+
+import com.qiaoba.common.database.entity.PageQuery;
+import com.qiaoba.common.database.entity.TableDataInfo;
+import com.qiaoba.module.generator.entity.dto.TableDto;
+import com.qiaoba.module.generator.entity.vo.DbTableVo;
+
+/**
+ * 数据库表 服务层
+ *
+ * @author ailanyin
+ * @version 1.0
+ * @since 2023/6/26 9:24
+ */
+public interface TableService {
+
+ /**
+ * 分页查询数据库表
+ *
+ * @param dto 查询条件
+ * @param pageQuery 分页信息
+ * @return list
+ */
+ TableDataInfo selectPageDbTableList(TableDto dto, PageQuery pageQuery);
+}
diff --git a/qiaoba-modules/qiaoba-module-generator/src/main/java/com/qiaoba/module/generator/service/impl/TableServiceImpl.java b/qiaoba-modules/qiaoba-module-generator/src/main/java/com/qiaoba/module/generator/service/impl/TableServiceImpl.java
new file mode 100644
index 0000000..e6a3a8e
--- /dev/null
+++ b/qiaoba-modules/qiaoba-module-generator/src/main/java/com/qiaoba/module/generator/service/impl/TableServiceImpl.java
@@ -0,0 +1,41 @@
+package com.qiaoba.module.generator.service.impl;
+
+import com.qiaoba.common.base.context.BaseContext;
+import com.qiaoba.common.base.enums.DataBaseEnum;
+import com.qiaoba.common.database.config.DynamicDataSourceConfig;
+import com.qiaoba.common.database.entity.PageQuery;
+import com.qiaoba.common.database.entity.TableDataInfo;
+import com.qiaoba.module.generator.entity.dto.TableDto;
+import com.qiaoba.module.generator.entity.vo.DbTableVo;
+import com.qiaoba.module.generator.mapper.TableMapper;
+import com.qiaoba.module.generator.service.TableService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+/**
+ * 数据库表 服务层实现
+ *
+ * @author ailanyin
+ * @version 1.0
+ * @since 2023/6/26 10:12
+ */
+@Service
+@RequiredArgsConstructor
+public class TableServiceImpl implements TableService {
+
+ private final TableMapper tableMapper;
+
+ @Override
+ public TableDataInfo selectPageDbTableList(TableDto dto, PageQuery pageQuery) {
+ String dbType = DynamicDataSourceConfig.TENANT_DATASOURCE_TYPE_MAP.get(BaseContext.getTenantId());
+ dto.setDbType(dbType);
+ dto.setSchema(selectSchema());
+ return TableDataInfo.build(tableMapper.selectPageDbTableList(pageQuery.build(), dto));
+ }
+
+ private String selectSchema() {
+ // PgSQL 需要设置 schema
+ //DataBaseEnum.POSTGRE_SQL.getType().equals(dbType)
+ return null;
+ }
+}
diff --git a/qiaoba-modules/qiaoba-module-generator/src/main/resources/mapper/TableMapper.xml b/qiaoba-modules/qiaoba-module-generator/src/main/resources/mapper/TableMapper.xml
new file mode 100644
index 0000000..8c36ab9
--- /dev/null
+++ b/qiaoba-modules/qiaoba-module-generator/src/main/resources/mapper/TableMapper.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/qiaoba-modules/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/entity/param/SysTenantDatasourceParam.java b/qiaoba-modules/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/entity/param/SysTenantDatasourceParam.java
index a58e834..a429d0c 100644
--- a/qiaoba-modules/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/entity/param/SysTenantDatasourceParam.java
+++ b/qiaoba-modules/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/entity/param/SysTenantDatasourceParam.java
@@ -24,8 +24,16 @@ public class SysTenantDatasourceParam implements Serializable {
private String isPrimary;
+ private String ip;
+
public SysTenantDatasourceParam(String tenantId) {
this.tenantId = tenantId;
}
+ public SysTenantDatasourceParam(String tenantId, String isPrimary) {
+ this.tenantId = tenantId;
+ this.isPrimary = isPrimary;
+ }
+
+
}
diff --git a/qiaoba-modules/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/service/SysTenantDatasourceService.java b/qiaoba-modules/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/service/SysTenantDatasourceService.java
index 327821a..6a20f70 100644
--- a/qiaoba-modules/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/service/SysTenantDatasourceService.java
+++ b/qiaoba-modules/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/service/SysTenantDatasourceService.java
@@ -22,6 +22,15 @@ public interface SysTenantDatasourceService {
*/
SysTenantDatasource selectPrimary(String tenantId);
+ /**
+ * 通过IP查询
+ *
+ * @param tenantId tenantId
+ * @param ip ip
+ * @return obj
+ */
+ SysTenantDatasource selectByIp(String tenantId, String ip);
+
/**
* 新增
*
diff --git a/qiaoba-modules/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/service/impl/DynamicDatasourceServiceImpl.java b/qiaoba-modules/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/service/impl/DynamicDatasourceServiceImpl.java
index 1ec2f25..ed1bbbb 100644
--- a/qiaoba-modules/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/service/impl/DynamicDatasourceServiceImpl.java
+++ b/qiaoba-modules/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/service/impl/DynamicDatasourceServiceImpl.java
@@ -1,8 +1,10 @@
package com.qiaoba.module.tenant.service.impl;
import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.StrUtil;
import com.qiaoba.common.base.enums.BaseEnum;
import com.qiaoba.common.base.enums.DataBaseEnum;
+import com.qiaoba.common.base.exceptions.ServiceException;
import com.qiaoba.common.database.entity.DynamicDataSource;
import com.qiaoba.common.database.service.DynamicDatasourceService;
import com.qiaoba.module.tenant.entity.SysTenantDatasource;
@@ -11,10 +13,7 @@ import com.qiaoba.module.tenant.service.SysTenantDatasourceService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
/**
* 动态数据源接口
@@ -35,7 +34,7 @@ public class DynamicDatasourceServiceImpl implements DynamicDatasourceService {
List tenantIds = sysTenantDatasourceService.selectTenantIds();
for (String tenantId : tenantIds) {
List datasourceList = sysTenantDatasourceService.selectList(new SysTenantDatasourceParam(tenantId));
- datasourceMap.put(tenantId, transform(datasourceList));
+ datasourceMap.put(tenantId, transformList(datasourceList));
}
return datasourceMap;
}
@@ -51,17 +50,30 @@ public class DynamicDatasourceServiceImpl implements DynamicDatasourceService {
sysTenantDatasourceService.setBackupDatasourceExcludeId(tenantId, datasourceId);
}
- private List transform(List datasourceList) {
+ @Override
+ public DynamicDataSource selectByIp(String tenantId, String ip) {
+ SysTenantDatasource sysTenantDatasource = sysTenantDatasourceService.selectByIp(tenantId, ip);
+ if (Objects.isNull(sysTenantDatasource)) {
+ throw new ServiceException(StrUtil.format("未找到数据源,查询方式: {}", ip));
+ }
+ return transform(sysTenantDatasource);
+ }
+
+ private List transformList(List datasourceList) {
List dynamicDataSourceList = new ArrayList<>();
for (SysTenantDatasource datasource : datasourceList) {
- DynamicDataSource dynamicDataSource = BeanUtil.copyProperties(datasource, DynamicDataSource.class);
- dynamicDataSource.setInitialSize(datasource.getInitCount());
- dynamicDataSource.setMinIdle(datasource.getMinCount());
- dynamicDataSource.setMaxActive(datasource.getMaxCount());
- dynamicDataSource.setDriver(DataBaseEnum.getDriver(datasource.getType()));
- dynamicDataSource.setUrl(DataBaseEnum.getUrl(datasource.getType(), datasource.getIp(), datasource.getPort(), datasource.getName()));
- dynamicDataSourceList.add(dynamicDataSource);
+ dynamicDataSourceList.add(transform(datasource));
}
return dynamicDataSourceList;
}
+
+ private DynamicDataSource transform(SysTenantDatasource datasource) {
+ DynamicDataSource dynamicDataSource = BeanUtil.copyProperties(datasource, DynamicDataSource.class);
+ dynamicDataSource.setInitialSize(datasource.getInitCount());
+ dynamicDataSource.setMinIdle(datasource.getMinCount());
+ dynamicDataSource.setMaxActive(datasource.getMaxCount());
+ dynamicDataSource.setDriver(DataBaseEnum.getDriver(datasource.getType()));
+ dynamicDataSource.setUrl(DataBaseEnum.getUrl(datasource.getType(), datasource.getIp(), datasource.getPort(), datasource.getName()));
+ return dynamicDataSource;
+ }
}
diff --git a/qiaoba-modules/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/service/impl/SysTenantDatasourceServiceImpl.java b/qiaoba-modules/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/service/impl/SysTenantDatasourceServiceImpl.java
index e3ab75f..f3eb95f 100644
--- a/qiaoba-modules/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/service/impl/SysTenantDatasourceServiceImpl.java
+++ b/qiaoba-modules/qiaoba-module-tenant/src/main/java/com/qiaoba/module/tenant/service/impl/SysTenantDatasourceServiceImpl.java
@@ -30,6 +30,13 @@ public class SysTenantDatasourceServiceImpl implements SysTenantDatasourceServic
return sysTenantDatasourceMapper.selectOne(paramToWrapper(new SysTenantDatasourceParam(tenantId, BaseEnum.YES.getCode())));
}
+ @Override
+ public SysTenantDatasource selectByIp(String tenantId, String ip) {
+ SysTenantDatasourceParam param = new SysTenantDatasourceParam(tenantId);
+ param.setIp(ip);
+ return sysTenantDatasourceMapper.selectOne(paramToWrapper(param));
+ }
+
@Override
public int insert(SysTenantDatasource sysTenantDatasource) {
return sysTenantDatasourceMapper.insert(sysTenantDatasource);
@@ -69,6 +76,7 @@ public class SysTenantDatasourceServiceImpl implements SysTenantDatasourceServic
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.lambda()
.eq(StrUtil.isNotBlank(param.getTenantId()), SysTenantDatasource::getTenantId, param.getTenantId())
+ .eq(StrUtil.isNotBlank(param.getIp()), SysTenantDatasource::getIp, param.getIp())
.eq(StrUtil.isNotBlank(param.getIsPrimary()), SysTenantDatasource::getIsPrimary, param.getIsPrimary());
return wrapper;
}