dev
zhang xu 2024-06-09 21:02:21 +08:00
parent aa37b31d18
commit ff1a0b7028
10 changed files with 313 additions and 361 deletions

View File

@ -0,0 +1,28 @@
package com.muyu.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import org.springframework.stereotype.Service;
/**
* @ClassDescription:
* @JdkVersion: 17
* @Author: zhangxu
* @Created: 2024/6/2 11:00
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder
public class Path {
private String Q;
private String R;
private String lng;
private String lat;
}

View File

@ -1,26 +0,0 @@
package com.muyu.config.domain.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @ClassDescription:
* @JdkVersion: 17
* @Author: zhangxu
* @Created: 2024/6/4 14:15
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class EntInfo {
private String entCode;
private String ip;
private Integer port;
}

View File

@ -1,35 +0,0 @@
package com.muyu.config.holder;
import lombok.extern.log4j.Log4j2;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
/**
* @ClassDescription:
* @JdkVersion: 17
* @Author: zhangxu
* @Created: 2024/6/4 14:11
*/
@Slf4j
public class DynamicDataSourceHolder {
private static final ThreadLocal<String> DYNAMIC_DATASOURCE = new ThreadLocal<>();
public static void setDynamicDatasourceKey(String key) {
log.info("数据源切换为:{}", key);
DYNAMIC_DATASOURCE.set(key);
}
public static String getDynamicDatasourceKey() {
String key = DYNAMIC_DATASOURCE.get();
Assert.notNull(key,"请携带数据表示");
return key;
}
public static void removeDynamicDatasourceKey() {
log.info("移除数据源:{}", DYNAMIC_DATASOURCE.get());
DYNAMIC_DATASOURCE.remove();
}
}

View File

@ -1,28 +0,0 @@
# Tomcat
server:
port: 9205
# Spring
spring:
application:
# 应用名称
name: muyu-many-datasource
profiles:
# 环境配置
active: dev
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: 115.159.67.205:8848
config:
# 配置中心地址
server-addr: 115.159.67.205:8848
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
logging:
level:
com.muyu.mapper: DEBUG

View File

@ -1,74 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="log.path" value="logs/muyu-many-datasource"/>
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.muyu" level="info"/>
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn"/>
<root level="info">
<appender-ref ref="console"/>
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info"/>
<appender-ref ref="file_error"/>
</root>
</configuration>

View File

@ -42,7 +42,7 @@ import java.util.UUID;
@DS("networking")
public class EnterpriseServiceImpl extends ServiceImpl<EnterpriseMapper,Enterprise> implements EnterpriseService
{
@Autowired
@Autowired(required = false)
private EnterpriseMapper enterpriseMapper;
/**

View File

@ -5,12 +5,12 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.muyu</groupId>
<artifactId>muyu-networking</artifactId>
<artifactId>muyu</artifactId>
<version>3.6.3</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<artifactId>muyu-networking-many-datasources</artifactId>
<description>动态多数据源</description>
<artifactId>muyu-vehicle-service</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
@ -20,7 +20,19 @@
<dependencies>
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.muyu</groupId>
<artifactId>muyu-networking-common</artifactId>
<version>3.6.3</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.27</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
@ -81,6 +93,12 @@
<artifactId>muyu-common-swagger</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,193 +1,193 @@
package com.muyu.vehicle.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.alibaba.druid.stat.DruidDataSourceStatManager;
import com.muyu.domain.datasources.Datasource;
import com.muyu.vehicle.context.DataSourceContextHolder;
import lombok.Data;
import lombok.extern.log4j.Log4j2;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* @ClassName
* @Author
* @Date 2024/4/28 17:01
*/
@Data
@Log4j2
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
private boolean debug = true;
/**
*
*/
private volatile Map<Object, Object> customDataSources;
@Override
protected Object determineCurrentLookupKey() {
Long datasourceId = DataSourceContextHolder.getDataSource(); // 获取当前数据源
if(!Objects.isNull(datasourceId)){
Map<Object, Object> map = this.customDataSources; // 存储我们注册的数据源
if(map.containsKey(datasourceId)){
log.info("当前数据源是:{}",datasourceId);
}else{
log.info("不存在数据源:{}",datasourceId);
return null;
}
}else{
log.info("当前是默认数据源");
}
return datasourceId;
}
@Override
public void setTargetDataSources(Map<Object, Object> param) {
super.setTargetDataSources(param);
this.customDataSources = param; // 存储我们注册的数据源
}
/**
* ID
* @param dataSource
*/
public void checkCreateDataSource(Datasource dataSource){
// 获取数据源ID
Long datasourceId = dataSource.getId();
// 获取已注册的数据源映射
Map<Object, Object> map = this.customDataSources;
// 检查是否已存在对应ID的数据源
if(map.containsKey(datasourceId)){
// 尝试获取并验证数据源连接
// 这里检查一下之前创建的数据源,现在是否连接正常
DruidDataSource druidDataSource = (DruidDataSource) map.get(datasourceId);
boolean flag = true;
DruidPooledConnection connection = null;
try {
// 尝试获取数据源连接
connection = druidDataSource.getConnection();
} catch (SQLException throwable) {
// 如果获取连接失败,则记录错误信息并标记需要重新创建数据源
log.error(throwable.getMessage());
flag = false;
// 删除已失效的数据源
delDataSources(datasourceId); // 删除数据源
}finally {
// 确保关闭连接
//如果连接正常记得关闭
if(null != connection){
try {
connection.close();
} catch (SQLException e) {
log.error(e.getMessage());
}
}
}
// 如果标记为需要重新创建数据源,则进行创建
if(!flag){
createDataSource(dataSource); // 创建数据源
}
}else {
// 如果不存在对应ID的数据源则直接创建
createDataSource(dataSource); // 创建数据源
}
}
/**
*
* 使Druid
*
*
* @param dataSource
*/
public void createDataSource(Datasource dataSource) { // 数据源对象
try {
// 构建数据库连接URL
String url="jdbc:mysql://"+dataSource.getIp(); // 数据库ip
String driverType="com.mysql.cj.jdbc.Driver";
url+="/"+dataSource.getDatabase()+"?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC&useSSL=false&zeroDateTimeBehavior=CONVERT_TO_NULL&allowPublicKeyRetrieval=true"; // 数据库
// 加载MySQL驱动类
Class.forName(driverType);
// 尝试建立与数据库的连接
Connection connection = DriverManager.getConnection(url, dataSource.getUsername(), dataSource.getPassword()); // 用户名 | 密码
// 如果连接成功,则关闭连接;如果连接失败,则记录错误日志
if(connection==null){
log.error("数据源配置有错误DataSource{}",dataSource);
}else{
connection.close();
}
// 创建DruidDataSource实例用于配置和管理数据库连接
DruidDataSource druidDataSource = new DruidDataSource();
// 设置数据源名称
druidDataSource.setName(dataSource.getId().toString()); // 编号
// 设置驱动类名
druidDataSource.setDriverClassName(driverType);
// 设置数据库连接URL
druidDataSource.setUrl(url);
// 设置数据库用户名
druidDataSource.setUsername(dataSource.getUsername()); // 用户名
// 设置数据库密码
druidDataSource.setPassword(dataSource.getPassword()); // 密码
// 配置连接池的最大活动连接数
druidDataSource.setMaxActive(20);
// 配置连接池的最小空闲连接数
druidDataSource.setMinIdle(5);
// 设置连接的最大等待时间
// 获取连接最大等待时间,单位毫秒
druidDataSource.setMaxWait(6000);
// 设置用于检查连接有效性的SQL查询
String validationQuery = "select 1";
// 开启在获取连接时执行有效性检查的特性
// 申请连接时执行validationQuery检测连接是否有效防止取到的连接不可用
druidDataSource.setTestOnBorrow(true);
druidDataSource.setValidationQuery(validationQuery);
// 初始化Druid数据源
druidDataSource.init();
// 将创建的数据源添加到自定义数据源映射中
this.customDataSources.put(dataSource.getId(),druidDataSource); // 编号
// 更新父类的TargetDataSources以包含新的数据源
// 将map赋值给父类的TargetDataSources
setTargetDataSources(this.customDataSources); // 存储我们注册的数据源
// 标记属性已设置,以触发数据源的初始化
// 将TargetDataSources中的连接信息放入resolvedDataSources管理
super.afterPropertiesSet();
} catch (Exception e) {
// 记录数据源创建过程中的任何异常
log.error("数据源创建失败",e);
}
}
/**
*
* @param datasourceId
*/
private void delDataSources(Long datasourceId) {
Map<Object, Object> map = this.customDataSources; // 存储我们注册的数据源
Set<DruidDataSource> druidDataSourceInstances = DruidDataSourceStatManager.getDruidDataSourceInstances();
for (DruidDataSource dataSource : druidDataSourceInstances) {
if (datasourceId.toString().equals(dataSource.getName())) {
map.remove(datasourceId);
//从实例中移除当前dataSource
DruidDataSourceStatManager.removeDataSource(dataSource);
// 将map赋值给父类的TargetDataSources
setTargetDataSources(map);
// 将TargetDataSources中的连接信息放入resolvedDataSources管理
super.afterPropertiesSet();
}
}
}
}
//package com.muyu.vehicle.config;
//
//import com.alibaba.druid.pool.DruidDataSource;
//import com.alibaba.druid.pool.DruidPooledConnection;
//import com.alibaba.druid.stat.DruidDataSourceStatManager;
//
//import com.muyu.domain.datasources.Datasource;
//
//import com.muyu.vehicle.context.DataSourceContextHolder;
//import lombok.Data;
//import lombok.extern.log4j.Log4j2;
//import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
//import java.sql.Connection;
//import java.sql.DriverManager;
//import java.sql.SQLException;
//import java.util.Map;
//import java.util.Objects;
//import java.util.Set;
//
///**
// * @ClassName
// * @Author
// * @Date 2024/4/28 17:01
// */
//@Data
//@Log4j2
//public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
//
// private boolean debug = true;
//
// /**
// * 存储我们注册的数据源
// */
// private volatile Map<Object, Object> customDataSources;
//
// @Override
// protected Object determineCurrentLookupKey() {
// Long datasourceId = DataSourceContextHolder.getDataSource(); // 获取当前数据源
// if(!Objects.isNull(datasourceId)){
// Map<Object, Object> map = this.customDataSources; // 存储我们注册的数据源
// if(map.containsKey(datasourceId)){
// log.info("当前数据源是:{}",datasourceId);
// }else{
// log.info("不存在数据源:{}",datasourceId);
// return null;
// }
// }else{
// log.info("当前是默认数据源");
// }
// return datasourceId;
// }
//
// @Override
// public void setTargetDataSources(Map<Object, Object> param) {
// super.setTargetDataSources(param);
// this.customDataSources = param; // 存储我们注册的数据源
// }
//
//
// /**
// * 检查是否已存在指定ID的数据源如果存在则验证其连接是否有效如果无效则重新创建数据源如果不存在则直接创建数据源。
// * @param dataSource 需要检查或创建的数据源对象。
// */
// public void checkCreateDataSource(Datasource dataSource){
// // 获取数据源ID
// Long datasourceId = dataSource.getId();
// // 获取已注册的数据源映射
// Map<Object, Object> map = this.customDataSources;
// // 检查是否已存在对应ID的数据源
// if(map.containsKey(datasourceId)){
// // 尝试获取并验证数据源连接
// // 这里检查一下之前创建的数据源,现在是否连接正常
// DruidDataSource druidDataSource = (DruidDataSource) map.get(datasourceId);
// boolean flag = true;
// DruidPooledConnection connection = null;
// try {
// // 尝试获取数据源连接
// connection = druidDataSource.getConnection();
// } catch (SQLException throwable) {
// // 如果获取连接失败,则记录错误信息并标记需要重新创建数据源
// log.error(throwable.getMessage());
// flag = false;
// // 删除已失效的数据源
// delDataSources(datasourceId); // 删除数据源
// }finally {
// // 确保关闭连接
// //如果连接正常记得关闭
// if(null != connection){
// try {
// connection.close();
// } catch (SQLException e) {
// log.error(e.getMessage());
// }
// }
// }
// // 如果标记为需要重新创建数据源,则进行创建
// if(!flag){
// createDataSource(dataSource); // 创建数据源
// }
// }else {
// // 如果不存在对应ID的数据源则直接创建
// createDataSource(dataSource); // 创建数据源
// }
// }
//
//
// /**
// * 创建数据源。
// * 使用Druid数据源工厂类来配置并创建数据源实例。
// * 此方法主要用于初始化一个特定数据库配置的数据源,并将其添加到自定义数据源的映射中。
// *
// * @param dataSource 数据源配置对象,包含数据库连接所需的全部信息。
// */
// public void createDataSource(Datasource dataSource) { // 数据源对象
// try {
// // 构建数据库连接URL
// String url="jdbc:mysql://"+dataSource.getIp(); // 数据库ip
// String driverType="com.mysql.cj.jdbc.Driver";
// url+="/"+dataSource.getDatabase()+"?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC&useSSL=false&zeroDateTimeBehavior=CONVERT_TO_NULL&allowPublicKeyRetrieval=true"; // 数据库
// // 加载MySQL驱动类
// Class.forName(driverType);
// // 尝试建立与数据库的连接
// Connection connection = DriverManager.getConnection(url, dataSource.getUsername(), dataSource.getPassword()); // 用户名 | 密码
// // 如果连接成功,则关闭连接;如果连接失败,则记录错误日志
// if(connection==null){
// log.error("数据源配置有错误DataSource{}",dataSource);
// }else{
// connection.close();
// }
// // 创建DruidDataSource实例用于配置和管理数据库连接
// DruidDataSource druidDataSource = new DruidDataSource();
// // 设置数据源名称
// druidDataSource.setName(dataSource.getId().toString()); // 编号
// // 设置驱动类名
// druidDataSource.setDriverClassName(driverType);
// // 设置数据库连接URL
// druidDataSource.setUrl(url);
// // 设置数据库用户名
// druidDataSource.setUsername(dataSource.getUsername()); // 用户名
// // 设置数据库密码
// druidDataSource.setPassword(dataSource.getPassword()); // 密码
// // 配置连接池的最大活动连接数
// druidDataSource.setMaxActive(20);
// // 配置连接池的最小空闲连接数
// druidDataSource.setMinIdle(5);
// // 设置连接的最大等待时间
// // 获取连接最大等待时间,单位毫秒
// druidDataSource.setMaxWait(6000);
// // 设置用于检查连接有效性的SQL查询
// String validationQuery = "select 1";
// // 开启在获取连接时执行有效性检查的特性
// // 申请连接时执行validationQuery检测连接是否有效防止取到的连接不可用
// druidDataSource.setTestOnBorrow(true);
// druidDataSource.setValidationQuery(validationQuery);
// // Druid数据源
// druidDataSource.init();
// // 将创建的数据源添加到自定义数据源映射中
// this.customDataSources.put(dataSource.getId(),druidDataSource); // 编号
// // 更新父类的TargetDataSources以包含新的数据源
// // 将map赋值给父类的TargetDataSources
// setTargetDataSources(this.customDataSources); // 存储我们注册的数据源
// // 标记属性已设置,以触发数据源的初始化
// // 将TargetDataSources中的连接信息放入resolvedDataSources管理
// super.afterPropertiesSet();
//
// } catch (Exception e) {
// // 记录数据源创建过程中的任何异常
// log.error("数据源创建失败",e);
// }
// }
//
// /**
// * 删除数据源
// * @param datasourceId 数据源编号
// */
// private void delDataSources(Long datasourceId) {
// Map<Object, Object> map = this.customDataSources; // 存储我们注册的数据源
// Set<DruidDataSource> druidDataSourceInstances = DruidDataSourceStatManager.getDruidDataSourceInstances();
// for (DruidDataSource dataSource : druidDataSourceInstances) {
// if (datasourceId.toString().equals(dataSource.getName())) {
// map.remove(datasourceId);
// //从实例中移除当前dataSource
// DruidDataSourceStatManager.removeDataSource(dataSource);
// // 将map赋值给父类的TargetDataSources
// setTargetDataSources(map);
// // 将TargetDataSources中的连接信息放入resolvedDataSources管理
// super.afterPropertiesSet();
// }
// }
// }
//
//}
//

View File

@ -0,0 +1,48 @@
//package com.muyu.vehicle.interceptor;
//
//
//import com.muyu.vehicle.service.DataSourceService;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.stereotype.Component;
//import org.springframework.web.method.HandlerMethod;
//import org.springframework.web.servlet.AsyncHandlerInterceptor;
//
//import javax.servlet.http.HttpServletRequest;
//import javax.servlet.http.HttpServletResponse;
//
///**
// * @ClassName SaasInterceptor
// * @Author zhangxu
// * @Date 2024/6/3 21:09
// */
//@Component
//public class SaasInterceptor implements AsyncHandlerInterceptor {
//
// @Autowired
// private DataSourceService changeDataSourceService;
//
// @Override
// public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// // 解决跨域问题
// //1.如果请求不是动态的,handler对象不是HandlerMethod的实例(静态页面).放行
// //2.如果请求是跨域请求(请求方法是:OPTIONS),handler对象不是HandlerMethod
// if (!(handler instanceof HandlerMethod)) {
// return true;
// }
// String datasourceCode = request.getHeader("datasource-code");
// if(datasourceCode==null){
// throw new RuntimeException("请求不合法");
// }
// changeDataSourceService.changeDS(Long.valueOf(datasourceCode));
// return true;
// }
//
// @Override
// public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// // 切换为默认数据源
// changeDataSourceService.toDefaultDS();
// }
//
//
//}
//

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.muyu</groupId>
<artifactId>muyu</artifactId>
<version>3.6.3</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>muyu-vehicle</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>