ltkj-framework/src/main/java/com/ltkj/framework/config/WebConfig.java
@@ -1,5 +1,7 @@ package com.ltkj.framework.config; import com.ltkj.framework.interceptor.DBChangeInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -11,6 +13,10 @@ //定义拦截器 @Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private DBChangeInterceptor dbChangeInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new TokenInterceptor()) @@ -24,5 +30,8 @@ "/lis/**","/api/His/**","/pacs/**", "/callBack/**" }); registry.addInterceptor(dbChangeInterceptor) .addPathPatterns("/**"); } } ltkj-framework/src/main/java/com/ltkj/framework/interceptor/DBChangeInterceptor.java
@@ -1,30 +1,64 @@ package com.ltkj.framework.interceptor; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.google.gson.Gson; 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.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @Company: 西安路泰科技有限公司 * @Author: zhaowenxuan * @Date: 2025/2/7 11:07 */ @Component @Order(2) public class DBChangeInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { @Autowired private IDictHospService dictHospService; @Autowired private DataSourceConfig dataSourceConfig; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { String hospId = request.getHeader("hospId"); if (StrUtil.isBlank(hospId)){ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write("{\"message\":\"401:找不到院区编号\"}"); return false; } DataSourceContextHolder.setDataSourceKey("default"); LambdaQueryWrapper<DictHosp> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(DictHosp::getCode,hospId); DictHosp hosp = dictHospService.getOne(wrapper); if (hosp == null || hosp.getDatabase() == null || hosp.getDatabase().trim().isEmpty()) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write("{\"message\":\"401:找不到院区数据\"}"); return false; } dataSourceConfig.addDataSource(hosp.getDatabase()); DataSourceContextHolder.setDataSourceKey(hosp.getDatabase()); return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { DataSourceContextHolder.setDataSourceKey("default"); DataSourceContextHolder.clear(); HandlerInterceptor.super.afterCompletion(request, response, handler, ex); } } ltkj-hosp/src/main/java/com/ltkj/db/DataSourceConfig.java
@@ -1,47 +1,49 @@ package com.ltkj.db; import com.alibaba.druid.pool.DruidDataSource; 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.util.HashMap; import java.util.Map; import java.util.Properties; //@Configuration @Configuration public class DataSourceConfig { // 使用代码 // try { // long id = Long.parseLong(request.getAttribute("id").toString()); // DataSourceContextHolder.setDataSourceKey(String.valueOf(id)); // dataSourceConfig.addDataSource(String.valueOf(id)); // 确保数据源已注册 // if (log.getSize()>50) log.setSize(50); // if (log.getLang().equals("zh-cn")) log.setLang("zh"); // return serverLogService.getLog(log,id); // }finally { // DataSourceContextHolder.setDataSourceKey("default"); // 切换回主库 // } private static final String DEFAULT_DATA_SOURCE_KEY = "default"; // 主库的标识 private final Map<String, DataSource> dataSourceCache = new HashMap<>(); // 数据源缓存 @Value("${config.properties}") private String url; @Value("${config.path}") private String path; // 从 application.yml 中读取主库的配置 @Value("${spring.datasource.url}") // @Value("${spring.datasource.url}") private String primaryUrl; @Value("${spring.datasource.username}") private String primaryPort; // @Value("${spring.datasource.username}") private String primaryUsername; @Value("${spring.datasource.password}") // @Value("${spring.datasource.password}") private String primaryPassword; @Value("${dbUrl}") // @Value("${dbUrl}") private String dbUrl; @Bean public DataSource dynamicDataSource() { DynamicDataSource dynamicDataSource = new DynamicDataSource(); @Bean(name = "hospDynamicDataSources") public DataSource hospDynamicDataSources() { HospDynamicDataSource dynamicDataSource = new HospDynamicDataSource(); // 初始化默认数据源为主库 dynamicDataSource.addTargetDataSource(DEFAULT_DATA_SOURCE_KEY, createDataSource(primaryUrl, primaryUsername, primaryPassword)); @@ -60,15 +62,30 @@ } // 根据用户 ID 动态获取数据源 public void addDataSource(String userId) { String dbName = "scum_admin_user_" + userId; public void addDataSource(String dbName) { FileInputStream fis = null; Properties props = new Properties(); try { fis = new FileInputStream(url); props.load(fis); fis.close(); dbUrl = props.getProperty("ip"); primaryPassword = props.getProperty("password"); primaryPort = props.getProperty("prot"); primaryUsername = props.getProperty("username"); } catch (IOException e) { throw new RuntimeException("读取配置文件失败", e); } // 检查缓存中是否已经存在该数据源 if (!dataSourceCache.containsKey(userId)) { String url = "jdbc:mysql://"+dbUrl+":3306/"+dbName; DataSource dataSource = createDataSource(url, primaryUsername, primaryPassword); dataSourceCache.put(userId, dataSource); DynamicDataSource dynamicDataSource = (DynamicDataSource) dynamicDataSource(); dynamicDataSource.addTargetDataSource(userId, dataSource); if (!dataSourceCache.containsKey(dbName)) { synchronized (this) { String url = "jdbc:mysql://" + dbUrl + ":" + primaryPort + "/" + dbName; DataSource dataSource = createDataSource(url, primaryUsername, primaryPassword); dataSourceCache.put(dbName, dataSource); HospDynamicDataSource dynamicDataSource = (HospDynamicDataSource) hospDynamicDataSources(); dynamicDataSource.addTargetDataSource(dbName, dataSource); } } } } ltkj-hosp/src/main/java/com/ltkj/db/HospDynamicDataSource.java
File was renamed from ltkj-hosp/src/main/java/com/ltkj/db/DynamicDataSource.java @@ -1,14 +1,17 @@ package com.ltkj.db; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; import org.springframework.stereotype.Component; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class DynamicDataSource extends AbstractRoutingDataSource { public class HospDynamicDataSource extends AbstractRoutingDataSource { private final Map<Object, Object> targetDataSources = new HashMap<>(); // 存储所有数据源 private final Map<Object, Object> targetDataSources = new ConcurrentHashMap<>(); // 存储所有数据源 @Override protected Object determineCurrentLookupKey() { @@ -18,7 +21,7 @@ // 添加目标数据源 public void addTargetDataSource(String key, DataSource dataSource) { targetDataSources.put(key, dataSource); super.setTargetDataSources(targetDataSources); // 更新目标数据源 super.setTargetDataSources(new ConcurrentHashMap<>(targetDataSources)); // 更新目标数据源 super.afterPropertiesSet(); // 重新初始化数据源 } ltkj-hosp/src/main/java/com/ltkj/hosp/domain/DictHosp.java
@@ -206,6 +206,7 @@ .append("updateByName", getUpdateByName()) .append("imgbase64", getImgbase64()) .append("deleted", getDeleted()) .append("database", getDatabase()) .toString(); } } ltkj-hosp/src/main/resources/mapper/hosp/DictHospMapper.xml
@@ -31,6 +31,7 @@ <result property="updateByName" column="update_by_name"/> <result property="imgbase64" column="imgBase64"/> <result property="deleted" column="deleted"/> <result property="database" column="database"/> </resultMap> <sql id="selectDictHospVo"> @@ -59,7 +60,7 @@ create_by_name, update_by_name, imgBase64, deleted deleted,database from dict_hosp </sql> @@ -116,6 +117,7 @@ <if test="updateByName != null and updateByName != ''">update_by_name,</if> <if test="imgbase64 != null">imgBase64,</if> <if test="deleted != null">deleted,</if> <if test="database != null">database,</if> </trim> <trim prefix="values (" suffix=")" suffixOverrides=","> <if test="hospAreaId != null">#{hospAreaId},</if> @@ -144,6 +146,7 @@ <if test="updateByName != null and updateByName != ''">#{updateByName},</if> <if test="imgbase64 != null">#{imgbase64},</if> <if test="deleted != null">#{deleted},</if> <if test="database != null">#{database},</if> </trim> </insert> @@ -175,6 +178,7 @@ <if test="updateByName != null and updateByName != ''">update_by_name = #{updateByName},</if> <if test="imgbase64 != null">imgBase64 = #{imgbase64},</if> <if test="deleted != null">deleted = #{deleted},</if> <if test="database != null">database = #{database},</if> </trim> where hosp_area_id = #{hospAreaId} </update> @@ -191,4 +195,4 @@ #{hospAreaId} </foreach> </delete> </mapper> </mapper>