zhaowenxuan
2025-02-08 eca1c2ce8506dfd5ad8f94235382b666ea831dfd
动态切换数据库实现
10个文件已修改
1个文件已添加
470 ■■■■■ 已修改文件
ltkj-admin/src/main/java/com/ltkj/web/controller/system/SysRoleController.java 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-framework/src/main/java/com/ltkj/framework/aspectj/DataSourceAspect.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-framework/src/main/java/com/ltkj/framework/config/DruidConfig.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-framework/src/main/java/com/ltkj/framework/config/WebConfig.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-framework/src/main/java/com/ltkj/framework/datasource/DynamicDataSourceContextHolder.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-framework/src/main/java/com/ltkj/framework/interceptor/DBChangeInterceptor.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-hosp/pom.xml 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-hosp/src/main/java/com/ltkj/db/DataSourceConfig.java 247 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-hosp/src/main/java/com/ltkj/db/DruidProperties.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-hosp/src/main/java/com/ltkj/db/HospDynamicDataSource.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-admin/src/main/java/com/ltkj/web/controller/system/SysRoleController.java
@@ -1,10 +1,30 @@
package com.ltkj.web.controller.system;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import com.ltkj.db.DataSourceConfig;
import com.ltkj.db.DataSourceContextHolder;
import com.ltkj.hosp.domain.DictHosp;
import com.ltkj.hosp.service.IDictHospService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.FileCopyUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
@@ -55,6 +75,13 @@
    @Autowired
    private ISysDeptService deptService;
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private IDictHospService dictHospService;
    @Value("${config.path}")
    private String path;
//    @PreAuthorize("@ss.hasPermi('system:role:list')")
    @GetMapping("/list")
@@ -245,4 +272,54 @@
        ajax.put("depts", deptService.selectDeptTreeList(new SysDept()));
        return ajax;
    }
    @Autowired
    private DataSourceConfig dataSourceConfig;
    /**
     * 从库批量执行sql
     * 读取本地sql文件
     * @return
     */
    @GetMapping("/execUpdateSql")
    public AjaxResult execUpdateSql() {
        DataSourceContextHolder.setDataSourceKey("default");
        List<DictHosp> list = dictHospService.list();
        List<Map<String, Object>> resultList = new ArrayList<>();
        for (DictHosp dictHosp : list) {
            String dbName = dictHosp.getDbname();
            Map<String, Object> dbResult = new HashMap<>();
            dbResult.put("database", dbName);
            List<String> successList = new ArrayList<>();
            List<String> errorList = new ArrayList<>();
            try {
                InputStreamReader reader = new InputStreamReader(Files.newInputStream(Paths.get(path + File.separator + "update.sql")), StandardCharsets.UTF_8);
                String sqlContent = FileCopyUtils.copyToString(reader);
                String[] sqlStatements = sqlContent.split("\\|-\\|");
                for (String sql : sqlStatements) {
                    sql = sql.trim();
                    if (!sql.isEmpty()) {
                        // INSERT INTO `api_config` (`id`, `api_url`, `api_method`, `tab_name`, `is_response`, `primary_keys`, `remark`, `result_code_key`, `result_data_key`, `type`) VALUES (${id}, '${dbName}', '${randowmStr}', '${randowmStr}', 1, 'ResultData', '1.pas 检查申请信息作废', 'ResultCode', 'ResultData', 'pacs');
//                        sql = sql.replace("${dbName}",dbName).replace("${id}", IdUtil.getSnowflake().nextIdStr()).replace("${randowmStr}", RandomUtil.randomString(10));
                        try {
                            dataSourceConfig.addDataSource(dbName);
                            DataSourceContextHolder.setDataSourceKey(dbName);
                            jdbcTemplate.execute(sql);
                            successList.add(sql);
                        } catch (Exception e) {
                            errorList.add(sql + " -> ERROR: " + e.getMessage());
                        }
                    }
                }
            } catch (IOException e) {
                return AjaxResult.error("读取SQL文件失败:" + e.getMessage());
            }
            dbResult.put("successSQL", successList);
            dbResult.put("failedSQL", errorList);
            resultList.add(dbResult);
        }
        DataSourceContextHolder.clear();
        return AjaxResult.success(resultList);
    }
}
ltkj-framework/src/main/java/com/ltkj/framework/aspectj/DataSourceAspect.java
@@ -2,6 +2,7 @@
import java.util.Objects;
import com.ltkj.db.DataSourceContextHolder;
import com.ltkj.framework.datasource.DynamicDataSourceContextHolder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
@@ -38,14 +39,14 @@
        DataSource dataSource = getDataSource(point);
        if (StringUtils.isNotNull(dataSource)) {
            DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
            DataSourceContextHolder.setDataSourceKey(dataSource.value().name());
        }
        try {
            return point.proceed();
        } finally {
            // 销毁数据源 在执行方法之后
            DynamicDataSourceContextHolder.clearDataSourceType();
            DataSourceContextHolder.clear();
        }
    }
ltkj-framework/src/main/java/com/ltkj/framework/config/DruidConfig.java
@@ -35,7 +35,7 @@
 *
 * @author ltkj
 */
@Configuration
//@Configuration
@Slf4j
public class DruidConfig {
@@ -69,7 +69,7 @@
    private String dbName;
    @Bean
//    @Bean
//    @ConfigurationProperties("spring.datasource.druid.master")
    public DataSource masterDataSource(DruidProperties druidProperties) {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
@@ -150,7 +150,7 @@
        return druidProperties.dataSource(dataSource);
    }
    @Bean
//    @Bean
//    @ConfigurationProperties("spring.datasource.druid.slavehis")
//    @ConditionalOnProperty(prefix = "spring.datasource.druid.slavehis", name = "enabled", havingValue = "true")
    public DataSource slaveHisDataSource(DruidProperties druidProperties) {
@@ -193,7 +193,7 @@
        return druidProperties.dataSource(dataSource);
    }
    @Bean
//    @Bean
//    @ConfigurationProperties("spring.datasource.druid.slavelis")
//    @ConditionalOnProperty(prefix = "spring.datasource.druid.slavelis", name = "enabled", havingValue = "true")
    public DataSource slaveDataLisSource(DruidProperties druidProperties) {
@@ -235,7 +235,7 @@
        return druidProperties.dataSource(dataSource);
    }
    @Bean
//    @Bean
//    @ConfigurationProperties("spring.datasource.druid.slavepacs")
//    @ConditionalOnProperty(prefix = "spring.datasource.druid.slavepacs", name = "enabled", havingValue = "true")
    public DataSource slaveDataPacsSource(DruidProperties druidProperties) {
@@ -278,7 +278,7 @@
        return druidProperties.dataSource(dataSource);
    }
    @Bean
//    @Bean
//    @ConfigurationProperties("spring.datasource.druid.slavepacs")
//    @ConditionalOnProperty(prefix = "spring.datasource.druid.slavepacs", name = "enabled", havingValue = "true")
    public DataSource slaveDataWsSource(DruidProperties druidProperties) {
@@ -427,8 +427,8 @@
    }
    @Bean(name = "dynamicDataSource")
    @Primary
//    @Bean(name = "dynamicDataSource")
//    @Primary
    public DynamicDataSource dataSource(DataSource masterDataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
@@ -458,8 +458,8 @@
     * 去除监控页面底部的广告
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    @Bean
    @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true")
//    @Bean
//    @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true")
    public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties) {
        // 获取web监控页面的参数
        DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
ltkj-framework/src/main/java/com/ltkj/framework/config/WebConfig.java
@@ -38,7 +38,8 @@
                .excludePathPatterns(new String[]{
                        "/system/dict/data/**",
                        "/system/dict/type/**",
                        "/captchaImage","/getCaptchaConfigKey/**"
                        "/captchaImage","/getCaptchaConfigKey/**",
                        "/system/role/execUpdateSql"
//                        ,
//                        "/login", "/register", "/captchaImage","/cus/**","/getCaptchaConfigKey","/report/jmreport/**",
//                        "/sqlserver/getdata/**","/api/His/**","/system/config/zx","/system/config/gxxmpym","/system/report/savePdf",
ltkj-framework/src/main/java/com/ltkj/framework/datasource/DynamicDataSourceContextHolder.java
@@ -1,5 +1,6 @@
package com.ltkj.framework.datasource;
import com.ltkj.db.DataSourceContextHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -22,20 +23,23 @@
     */
    public static void setDataSourceType(String dsType) {
        log.info("切换到{}数据源", dsType);
        CONTEXT_HOLDER.set(dsType);
//        CONTEXT_HOLDER.set(dsType);
        DataSourceContextHolder.setDataSourceKey(dsType);
    }
    /**
     * 获得数据源的变量
     */
    public static String getDataSourceType() {
        return CONTEXT_HOLDER.get();
//        return CONTEXT_HOLDER.get();
        return DataSourceContextHolder.getDataSourceKey();
    }
    /**
     * 清空数据源变量
     */
    public static void clearDataSourceType() {
        CONTEXT_HOLDER.remove();
//        CONTEXT_HOLDER.remove();
        DataSourceContextHolder.clear();
    }
}
ltkj-framework/src/main/java/com/ltkj/framework/interceptor/DBChangeInterceptor.java
@@ -29,10 +29,10 @@
    @Autowired
    private IDictHospService dictHospService;
//    @Autowired
//    private DataSourceConfig dataSourceConfig;
    @Autowired
    private DruidConfig druidConfig;
    private DataSourceConfig dataSourceConfig;
//    @Autowired
//    private DruidConfig druidConfig;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
@@ -55,8 +55,8 @@
                response.getWriter().write("{\"message\":\"401:找不到院区数据\"}");
                return false;
            }
//            dataSourceConfig.addDataSource(hosp.getDbname());
            druidConfig.addDataSource(hosp.getDbname());
            dataSourceConfig.addDataSource(hosp.getDbname());
//            druidConfig.addDataSource(hosp.getDbname());
            DataSourceContextHolder.setDataSourceKey(hosp.getDbname());
        } catch (IOException e) {
            return false;
ltkj-hosp/pom.xml
@@ -28,6 +28,12 @@
        <dependency>
            <groupId>com.ltkj</groupId>
            <artifactId>ltkj-common</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>com.alibaba</groupId>
                    <artifactId>druid</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- 集成积木报表-->
@@ -35,6 +41,12 @@
            <groupId>org.jeecgframework.jimureport</groupId>
            <artifactId>jimureport-spring-boot-starter</artifactId>
            <version>1.5.4</version>
            <exclusions>
                <exclusion>
                    <groupId>com.alibaba</groupId>
                    <artifactId>druid</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- 阿里数据库连接池 -->
@@ -43,6 +55,11 @@
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
    </dependencies>
</project>
ltkj-hosp/src/main/java/com/ltkj/db/DataSourceConfig.java
@@ -1,20 +1,23 @@
package com.ltkj.db;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.ltkj.common.enums.DataSourceType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.*;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
//@Configuration
@Slf4j
@Configuration
public class DataSourceConfig {
    private static final String DEFAULT_DATA_SOURCE_KEY = "default"; // 主库的标识
@@ -64,6 +67,13 @@
        // 初始化默认数据源为主库
        dynamicDataSource.addTargetDataSource(DEFAULT_DATA_SOURCE_KEY, createDataSource(url, primaryUsername, primaryPassword));
        DruidProperties properties = new DruidProperties();
        dynamicDataSource.addTargetDataSource(DataSourceType.MASTER.name(),masterDataSource(properties));
        dynamicDataSource.addTargetDataSource(DataSourceType.SLAVE_HIS.name(),slaveHisDataSource(properties));
        dynamicDataSource.addTargetDataSource(DataSourceType.SLAVE_LIS.name(),slaveDataLisSource(properties));
        dynamicDataSource.addTargetDataSource(DataSourceType.SLAVE_PACS.name(),slaveDataPacsSource(properties));
        dynamicDataSource.addTargetDataSource(DataSourceType.SLAVE_WS.name(),slaveDataWsSource(properties));
        dynamicDataSource.setDefaultTargetDataSource(dynamicDataSource.getTargetDataSources().get(DEFAULT_DATA_SOURCE_KEY)); // 设置默认数据源
        return dynamicDataSource;
    }
@@ -104,4 +114,233 @@
            }
        }
    }
    private DataSource masterDataSource(DruidProperties druidProperties) {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        Properties props = new Properties();
        try {
            // 从文件中读取配置信息
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(url);
            } catch (FileNotFoundException e) {
                log.info("数据库连接文件找不到!");
            }
            props.load(fis);
            fis.close();
            // 获取属性值并赋值
            String hisenabled = props.getProperty("hisenabled");
            if (hisenabled.equals("false"))
                return null;
            dataSource = creatMysql(hisenabled, props.getProperty("ip"),props.getProperty("prot"),props.getProperty("name"),props.getProperty("username"),props.getProperty("password"));
            log.info("his数据库连接成功!!!");
        } catch (Exception e) {
            log.info("数据库连接失败  请联系管理员!");
            e.printStackTrace();
        }
        return druidProperties.dataSource(dataSource);
    }
    private DataSource slaveHisDataSource(DruidProperties druidProperties) {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        Properties props = new Properties();
        try {
            // 从文件中读取配置信息
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(url);
            } catch (FileNotFoundException e) {
                log.info("数据库连接文件找不到!");
            }
            props.load(fis);
            fis.close();
            // 获取属性值并赋值
            String hisenabled = props.getProperty("hisenabled");
            if (hisenabled.equals("false"))
                return null;
            String hisdbtype = props.getProperty("hisdbtype");
            switch (hisdbtype){
                case "sqlserver":
                    dataSource = creatSqlServer(hisenabled, props.getProperty("hisip"),props.getProperty("hisprot"),props.getProperty("hisname"),props.getProperty("hisusername"),props.getProperty("hispassword"));
                    break;
                case "mysql":
                    dataSource = creatMysql(hisenabled, props.getProperty("hisip"),props.getProperty("hisprot"),props.getProperty("hisname"),props.getProperty("hisusername"),props.getProperty("hispassword"));
                    break;
                case "oracle":
                    dataSource = creatOracle(hisenabled, props.getProperty("hisip"),props.getProperty("hisprot"),props.getProperty("hisname"),props.getProperty("hisusername"),props.getProperty("hispassword"));
                    break;
                default:
                    dataSource = creatSqlServer(hisenabled, props.getProperty("hisip"),props.getProperty("hisprot"),props.getProperty("hisname"),props.getProperty("hisusername"),props.getProperty("hispassword"));
                    break;
            }
            log.info("his数据库连接成功!!!");
        } catch (Exception e) {
            log.info("数据库连接失败  请联系管理员!");
            e.printStackTrace();
        }
        return druidProperties.dataSource(dataSource);
    }
    private DataSource slaveDataLisSource(DruidProperties druidProperties) {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        Properties props = new Properties();
        try {
            // 从文件中读取配置信息
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(url);
            } catch (FileNotFoundException e) {
                log.info("数据库连接文件找不到!");
            }
            props.load(fis);
            fis.close();
            String lisenabled = props.getProperty("lisenabled");
            if (lisenabled.equals("false"))
                return null;
            String lisdbtype = props.getProperty("lisdbtype");
            switch (lisdbtype){
                case "sqlserver":
                    dataSource = creatSqlServer(lisenabled, props.getProperty("lisip"),props.getProperty("lisprot"),props.getProperty("lisname"),props.getProperty("lisusername"),props.getProperty("lispassword"));
                    break;
                case "mysql":
                    dataSource = creatMysql(lisenabled, props.getProperty("lisip"),props.getProperty("lisprot"),props.getProperty("lisname"),props.getProperty("lisusername"),props.getProperty("lispassword"));
                    break;
                case "oracle":
                    dataSource = creatOracle(lisenabled, props.getProperty("lisip"),props.getProperty("lisprot"),props.getProperty("lisname"),props.getProperty("lisusername"),props.getProperty("lispassword"));
                    break;
                default:
                    dataSource = creatMysql(lisenabled, props.getProperty("lisip"),props.getProperty("lisprot"),props.getProperty("lisname"),props.getProperty("lisusername"),props.getProperty("lispassword"));
                    break;
            }
            log.info("Lis数据库连接成功!!!");
        } catch (Exception e) {
            log.info("数据库连接失败  请联系管理员!");
            e.printStackTrace();
        }
        return druidProperties.dataSource(dataSource);
    }
    private DataSource slaveDataPacsSource(DruidProperties druidProperties) {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        Properties props = new Properties();
        try {
            // 从文件中读取配置信息
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(url);
            } catch (FileNotFoundException e) {
                log.info("数据库连接文件找不到");
            }
            props.load(fis);
            fis.close();
            // 这里是测试写法,具体的value可以通过请求参数传递过来
            String pacsenabled = props.getProperty("pacsenabled");
            if (pacsenabled.equals("false"))
                return null;
            String pacsdbtype = props.getProperty("pacsdbtype");
            switch (pacsdbtype){
                case "sqlserver":
                    dataSource = creatSqlServer(pacsenabled, props.getProperty("pacsip"),props.getProperty("pacsprot"),props.getProperty("pacsname"),props.getProperty("pacsusername"),props.getProperty("pacspassword"));
                    break;
                case "mysql":
                    dataSource = creatMysql(pacsenabled, props.getProperty("pacsip"),props.getProperty("pacsprot"),props.getProperty("pacsname"),props.getProperty("pacsusername"),props.getProperty("pacspassword"));
                    break;
                case "oracle":
                    dataSource = creatOracle(pacsenabled, props.getProperty("pacsip"),props.getProperty("pacsprot"),props.getProperty("pacsname"),props.getProperty("pacsusername"),props.getProperty("pacspassword"));
                    break;
                default:
                    dataSource = creatOracle(pacsenabled, props.getProperty("pacsip"),props.getProperty("pacsprot"),props.getProperty("pacsname"),props.getProperty("pacsusername"),props.getProperty("pacspassword"));
                    break;
            }
            log.info("数据库连接成功!!!");
        } catch (Exception e) {
            log.info("数据库连接失败  请联系管理员!");
            e.printStackTrace();
        }
        return druidProperties.dataSource(dataSource);
    }
    private DataSource slaveDataWsSource(DruidProperties druidProperties) {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        Properties props = new Properties();
        try {
            // 从文件中读取配置信息
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(url);
            } catch (FileNotFoundException e) {
                log.info("数据库连接文件找不到");
            }
            props.load(fis);
            fis.close();
            // 这里是测试写法,具体的value可以通过请求参数传递过来
            String pacsenabled = props.getProperty("wsenabled");
            if (pacsenabled.equals("false"))
                return null;
            String pacsdbtype = props.getProperty("wsdbtype");
            switch (pacsdbtype){
                case "sqlserver":
                    dataSource = creatSqlServer(pacsenabled, props.getProperty("wsip"),props.getProperty("wsprot"),
                            props.getProperty("wsname"),props.getProperty("wsusername"),props.getProperty("wspassword"));
                    break;
                case "mysql":
                    dataSource = creatMysql(pacsenabled, props.getProperty("wsip"),
                            props.getProperty("wsprot"),props.getProperty("wsname"),props.getProperty("wsusername"),props.getProperty("wspassword"));
                    break;
                case "oracle":
                    dataSource = creatOracle(pacsenabled, props.getProperty("wsip"),
                            props.getProperty("wsprot"),props.getProperty("wsname"),props.getProperty("wsusername"),props.getProperty("wspassword"));
                    break;
                default:
                    dataSource = creatOracle(pacsenabled, props.getProperty("wsip"),props.getProperty("wsprot"),props.getProperty("wsname"),props.getProperty("wsusername")
                            ,props.getProperty("wspassword"));
                    break;
            }
            log.info("数据库连接成功!!!");
        } catch (Exception e) {
            log.info("数据库连接失败  请联系管理员!");
            e.printStackTrace();
        }
        return druidProperties.dataSource(dataSource);
    }
    private DruidDataSource creatSqlServer(String enabled, String ip,String port,String db,String user,String password) throws SQLException {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        Properties properties = new Properties();
        properties.setProperty("druid.enabled", enabled);
        properties.setProperty("druid.driverClassName","com.microsoft.sqlserver.jdbc.SQLServerDriver");
        properties.setProperty("druid.url","jdbc:sqlserver://"+ ip+":"+ port+";DatabaseName="+ db+
                ";&characterEncoding=utf8");
        properties.setProperty("druid.username", user);
        properties.setProperty("druid.password", password);
        dataSource.restart(properties);
        return dataSource;
    }
    private DruidDataSource creatMysql(String enabled, String ip,String port,String db,String user,String password) throws SQLException {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        Properties properties = new Properties();
        properties.setProperty("druid.enabled",enabled);
        properties.setProperty("druid.url","jdbc:mysql://"+ip+":"+port+"/"+db+"" +
                "?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8");
        properties.setProperty("druid.username",user);
        properties.setProperty("druid.password",password);
        dataSource.restart(properties);
        return dataSource;
    }
    private DruidDataSource creatOracle(String enabled, String ip,String port,String db,String user,String password) throws SQLException {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        Properties properties = new Properties();
        properties.setProperty("druid.enabled",enabled);
        properties.setProperty("druid.driverClassName","oracle.jdbc.OracleDriver");
        properties.setProperty("druid.url","jdbc:oracle:thin:@//"+ip+"/"+db);
        properties.setProperty("druid.username",user);
        properties.setProperty("druid.password",password);
        dataSource.restart(properties);
        return dataSource;
    }
}
ltkj-hosp/src/main/java/com/ltkj/db/DruidProperties.java
New file
@@ -0,0 +1,61 @@
package com.ltkj.db;
import com.alibaba.druid.pool.DruidDataSource;
/**
 * druid 配置属性
 *
 * @author ruoyi
 */
public class DruidProperties {
    private int initialSize=5;
    private int minIdle=10;
    private int maxActive=20;
    private int maxWait=60000;
    private int timeBetweenEvictionRunsMillis=60000;
    private int minEvictableIdleTimeMillis=300000;
    private int maxEvictableIdleTimeMillis=900000;
    private boolean testWhileIdle=true;
    private boolean testOnBorrow=false;
    private boolean testOnReturn=false;
    public DruidDataSource dataSource(DruidDataSource datasource) {
        /** 配置初始化大小、最小、最大 */
        datasource.setInitialSize(initialSize);
        datasource.setMaxActive(maxActive);
        datasource.setMinIdle(minIdle);
        /** 配置获取连接等待超时的时间 */
        datasource.setMaxWait(maxWait);
        /** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */
        datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        /** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */
        datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
        /**
         * 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
         */
//        datasource.setValidationQuery(validationQuery);
        /** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */
        datasource.setTestWhileIdle(testWhileIdle);
        /** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
        datasource.setTestOnBorrow(testOnBorrow);
        /** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
        datasource.setTestOnReturn(testOnReturn);
        return datasource;
    }
}
ltkj-hosp/src/main/java/com/ltkj/db/HospDynamicDataSource.java
@@ -1,25 +1,31 @@
package com.ltkj.db;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Slf4j
public class HospDynamicDataSource extends AbstractRoutingDataSource {
    private final Map<Object, Object> targetDataSources = new ConcurrentHashMap<>(); // 存储所有数据源
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSourceKey(); // 根据上下文获取当前数据源的键
        String key = DataSourceContextHolder.getDataSourceKey();
        log.info("当前数据源 ->{}",key);
        return key; // 根据上下文获取当前数据源的键
    }
    // 添加目标数据源
    public void addTargetDataSource(String key, DataSource dataSource) {
        if (dataSource != null) {
        targetDataSources.put(key, dataSource);
        super.setTargetDataSources(new ConcurrentHashMap<>(targetDataSources)); // 更新目标数据源
        super.afterPropertiesSet(); // 重新初始化数据源
    }
    }
    // 允许外部访问所有目标数据源
    @Override
pom.xml
@@ -126,6 +126,18 @@
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>${druid.version}</version>
                <exclusions>
                    <exclusion>
                        <groupId>com.alibaba</groupId>
                        <artifactId>druid</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <!-- 解析客户端操作系统、浏览器等 -->