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 d95ab65..0634afd 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,6 +119,7 @@ public class ShiroConfig { filterChainDefinitionMap.put("/weixin/**", "anon"); //授权接口排除 filterChainDefinitionMap.put("/api/pad/loginApi/**", "anon"); //pad登录-信息获取接口 filterChainDefinitionMap.put("/sys/common/open/static/**", "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 9c86a43..97a73b6 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("devops"); +// +// // 从主数据源读取配置 +// 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("devops"); - // 从主数据源读取配置 + // 1. 从固定的主数据源(如 devops)读取最新的动态数据源配置 + DataSource mainDataSource = ds.getDataSource("devops"); // 必须是静态配置的,不能被动态删除! + 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())); + } }