From 5589aef37bfffc2e8335e8a308f89af184e3d2ea Mon Sep 17 00:00:00 2001 From: "1378012178@qq.com" <1378012178@qq.com> Date: Tue, 14 Oct 2025 13:58:33 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A8=E6=80=81=E6=95=B0=E6=8D=AE=E6=BA=90?= =?UTF-8?q?=E6=97=A0=E9=9C=80=E9=87=8D=E5=90=AF=E5=88=B7=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/nu/modules/common/SysUtilsApi.java | 24 ++++++ .../org/jeecg/config/shiro/ShiroConfig.java | 2 +- .../modules/data/loader/DataSourceLoader.java | 84 +++++++++++++++---- 3 files changed, 95 insertions(+), 15 deletions(-) create mode 100644 nursing-unit-api/src/main/java/com/nu/modules/common/SysUtilsApi.java diff --git a/nursing-unit-api/src/main/java/com/nu/modules/common/SysUtilsApi.java b/nursing-unit-api/src/main/java/com/nu/modules/common/SysUtilsApi.java new file mode 100644 index 0000000..bf2c44f --- /dev/null +++ b/nursing-unit-api/src/main/java/com/nu/modules/common/SysUtilsApi.java @@ -0,0 +1,24 @@ +package com.nu.modules.common; + +import org.jeecg.modules.data.loader.DataSourceLoader; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 系统工具 + */ +@RestController +@RequestMapping("/api/sysUtils") +public class SysUtilsApi { + + @Autowired + private DataSourceLoader dataSourceLoader; + + @PostMapping("/refreshDS") + public String refresh() { + dataSourceLoader.refreshDataSources(); + return "数据源已刷新"; + } +} diff --git a/nursing-unit-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java b/nursing-unit-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java index 779ad06..e59e4a1 100644 --- a/nursing-unit-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java +++ b/nursing-unit-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java @@ -119,7 +119,7 @@ public class ShiroConfig { filterChainDefinitionMap.put("/sys/sysDepart/queryInstitutionsList", "anon");//授权接口排除 filterChainDefinitionMap.put("/h5Api/nuBizAdvisoryInfo/**", "anon"); //授权接口排除 filterChainDefinitionMap.put("/weixin/**", "anon"); //授权接口排除 - + filterChainDefinitionMap.put("/api/sysUtils/refreshDS", "anon");//刷新数据源 filterChainDefinitionMap.put("/sys/getLoginQrcode/**", "anon"); //登录二维码 filterChainDefinitionMap.put("/sys/getQrcodeToken/**", "anon"); //监听扫码 diff --git a/nursing-unit-base-core/src/main/java/org/jeecg/modules/data/loader/DataSourceLoader.java b/nursing-unit-base-core/src/main/java/org/jeecg/modules/data/loader/DataSourceLoader.java index c87af68..9349b99 100644 --- a/nursing-unit-base-core/src/main/java/org/jeecg/modules/data/loader/DataSourceLoader.java +++ b/nursing-unit-base-core/src/main/java/org/jeecg/modules/data/loader/DataSourceLoader.java @@ -12,6 +12,7 @@ import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.sql.DataSource; import java.util.List; +import java.util.stream.Collectors; @Slf4j @Service @@ -27,11 +28,50 @@ public class DataSourceLoader { refreshDataSources(); } +// public void refreshDataSources() { +// DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; +// DataSource mainDataSource = ds.getDataSource(""); +// +// // 从主数据源读取配置 +// List configs = new JdbcTemplate(mainDataSource).query( +// "SELECT id, code, name, db_type, db_driver, db_url, db_name, db_username ,db_password ,sys_org_code FROM sys_data_source", +// (rs, rowNum) -> new DataSourceEntity( +// rs.getString("id"), +// rs.getString("code"), +// rs.getString("name"), +// rs.getString("db_type"), +// rs.getString("db_driver"), +// rs.getString("db_url"), +// rs.getString("db_name"), +// rs.getString("db_username"), +// rs.getString("db_password"), +// rs.getString("sys_org_code") +// ) +// ); +// +// // 创建并添加数据源 +// configs.forEach(config -> { +// DataSourceProperty dataSourceProperty = new DataSourceProperty(); +// dataSourceProperty.setUrl(config.getDbUrl()); +// dataSourceProperty.setUsername(config.getDbUsername()); +// String dbPassword = SecurityUtil.jiemi(config.getDbPassword()); +// dataSourceProperty.setPassword(dbPassword); +// dataSourceProperty.setDriverClassName(config.getDbDriver()); +// DataSource dynamicDataSource = dataSourceCreator.createDataSource(dataSourceProperty); +// ds.addDataSource(config.getCode(), dynamicDataSource); +// }); +// } + public void refreshDataSources() { DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; - DataSource mainDataSource = ds.getDataSource(""); - // 从主数据源读取配置 + // 1. 从固定的主数据源(如 devops)读取最新的动态数据源配置 + DataSource mainDataSource = ds.getDataSource(""); // 必须是静态配置的,不能被动态删除! + if (mainDataSource == null) { + log.error("无法获取主数据源 'devops',刷新动态数据源失败!"); + return; + } + List configs = new JdbcTemplate(mainDataSource).query( "SELECT id, code, name, db_type, db_driver, db_url, db_name, db_username ,db_password ,sys_org_code FROM sys_data_source", (rs, rowNum) -> new DataSourceEntity( @@ -48,17 +88,33 @@ public class DataSourceLoader { ) ); - // 创建并添加数据源 - configs.forEach(config -> { - DataSourceProperty dataSourceProperty = new DataSourceProperty(); - dataSourceProperty.setUrl(config.getDbUrl()); - dataSourceProperty.setUsername(config.getDbUsername()); - String dbPassword = SecurityUtil.jiemi(config.getDbPassword()); - dataSourceProperty.setPassword(dbPassword); - dataSourceProperty.setDriverClassName(config.getDbDriver()); - DataSource dynamicDataSource = dataSourceCreator.createDataSource(dataSourceProperty); - ds.addDataSource(config.getCode(), dynamicDataSource); - }); - } + // 2. 新增或更新 + for (DataSourceEntity config : configs) { + String code = config.getCode(); + if (code == null || code.isEmpty()) { + log.warn("跳过无效数据源配置(code 为空): {}", config); + continue; + } + + try { + DataSourceProperty prop = new DataSourceProperty(); + prop.setUrl(config.getDbUrl()); + prop.setUsername(config.getDbUsername()); + prop.setPassword(SecurityUtil.jiemi(config.getDbPassword())); + prop.setDriverClassName(config.getDbDriver()); + + DataSource newDs = dataSourceCreator.createDataSource(prop); + ds.addDataSource(code, newDs); // 如果已存在,会先 close 旧的再替换(DynamicRoutingDataSource 内部逻辑) + log.info("已添加/更新动态数据源: {}", code); + } catch (Exception e) { + log.error("创建/更新数据源失败,code={}", code, e); + } + } + + log.info("动态数据源同步完成。当前动态数据源列表: {}", + ds.getDataSources().keySet().stream() + .filter(name -> !name.equals("master")) + .collect(Collectors.toList())); + } }