feat:ssh 管理

This commit is contained in:
xiang
2025-08-23 14:34:31 +08:00
parent 78df3b2062
commit e5ef8bc3fd
7 changed files with 92 additions and 5 deletions

View File

@@ -155,6 +155,13 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- ssh -->
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
</dependencies>
<build>

View File

@@ -8,7 +8,7 @@
<artifactId>xservice-basic</artifactId>
<version>1.1</version>
</parent>
<version>1.2</version>
<version>1.3</version>
<artifactId>xservice-common</artifactId>

View File

@@ -0,0 +1,39 @@
package com.xiang.xservice.basic.utils;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import java.util.concurrent.ConcurrentHashMap;
public class SSHManager {
private static final ConcurrentHashMap<String, Session> sessionMap = new ConcurrentHashMap<>();
public static void createTunnel(String key, String sshHost, int sshPort,
String sshUser, String sshPassword,
int localPort, String remoteHost, int remotePort) throws Exception {
if (sessionMap.containsKey(key) && sessionMap.get(key).isConnected()) {
return; // 已存在
}
JSch jsch = new JSch();
Session session = jsch.getSession(sshUser, sshHost, sshPort);
session.setPassword(sshPassword);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
session.setPortForwardingL(localPort, remoteHost, remotePort);
sessionMap.put(key, session);
System.out.println("SSH Tunnel for [" + key + "] established.");
}
public static void closeTunnel(String key) {
Session session = sessionMap.get(key);
if (session != null && session.isConnected()) {
session.disconnect();
sessionMap.remove(key);
System.out.println("SSH Tunnel for [" + key + "] closed.");
}
}
}

View File

@@ -10,11 +10,19 @@
</parent>
<artifactId>xservice-mysql-starter</artifactId>
<version>1.1</version>
<version>2.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.xiang</groupId>
<artifactId>xservice-common</artifactId>
<version>1.3</version>
</dependency>
</dependencies>
</project>

View File

@@ -29,7 +29,7 @@ public class DynamicDataSourceConfig {
targetDataSources.put(key, builder.build());
});
DynamicRoutingDataSource routing = new DynamicRoutingDataSource();
DynamicRoutingDataSource routing = new DynamicRoutingDataSource(props);
routing.setDefaultTargetDataSource(targetDataSources.get(props.getPrimary()));
routing.setTargetDataSources(targetDataSources);
return routing;

View File

@@ -12,5 +12,12 @@ public class DataSourceProperty {
private String username;
private String password;
private String driverClassName = "com.mysql.cj.jdbc.Driver";
private Boolean sshConnect;
private String sshHost;
private Integer sshPort = 22;
private String sshUser;
private String sshPassword;
private Integer localPort; // 本地转发端口
private String remoteHost; // 远端数据库 host
private Integer remotePort; // 远端数据库 port
}

View File

@@ -1,11 +1,37 @@
package com.xiang.xservice.mysql.service;
import com.xiang.xservice.basic.utils.SSHManager;
import com.xiang.xservice.mysql.config.DynamicDataSourceContext;
import com.xiang.xservice.mysql.entity.DataSourceProperty;
import lombok.RequiredArgsConstructor;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import com.xiang.xservice.mysql.entity.DynamicDataSourceProperties;
@RequiredArgsConstructor
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
private final DynamicDataSourceProperties dynamicDataSourceProperties;
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceContext.get();
String key = DynamicDataSourceContext.get();
DataSourceProperty dataSourceProperty = dynamicDataSourceProperties.getDatasource().get(key);
if (Boolean.TRUE.equals(dataSourceProperty.getSshConnect())) {
try {
SSHManager.createTunnel(
key,
dataSourceProperty.getSshHost(),
dataSourceProperty.getSshPort(),
dataSourceProperty.getSshUser(),
dataSourceProperty.getSshPassword(),
dataSourceProperty.getLocalPort(),
dataSourceProperty.getRemoteHost(),
dataSourceProperty.getRemotePort()
);
} catch (Exception e) {
throw new RuntimeException("Failed to establish SSH tunnel for " + key, e);
}
}
return key;
}
}