diff --git a/pom.xml b/pom.xml index 5d1c4bc..62d0925 100644 --- a/pom.xml +++ b/pom.xml @@ -155,6 +155,13 @@ com.fasterxml.jackson.core jackson-databind + + + + com.jcraft + jsch + 0.1.55 + diff --git a/xservice-common/pom.xml b/xservice-common/pom.xml index 51b7a8a..b4676bd 100644 --- a/xservice-common/pom.xml +++ b/xservice-common/pom.xml @@ -8,7 +8,7 @@ xservice-basic 1.1 - 1.2 + 1.3 xservice-common diff --git a/xservice-common/src/main/java/com/xiang/xservice/basic/utils/SSHManager.java b/xservice-common/src/main/java/com/xiang/xservice/basic/utils/SSHManager.java new file mode 100644 index 0000000..b1bac91 --- /dev/null +++ b/xservice-common/src/main/java/com/xiang/xservice/basic/utils/SSHManager.java @@ -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 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."); + } + } +} diff --git a/xservice-mysql-starter/pom.xml b/xservice-mysql-starter/pom.xml index 0eebc0a..ca4504a 100644 --- a/xservice-mysql-starter/pom.xml +++ b/xservice-mysql-starter/pom.xml @@ -10,11 +10,19 @@ xservice-mysql-starter - 1.1 + 2.0-SNAPSHOT 17 17 UTF-8 + + + com.xiang + xservice-common + 1.3 + + + \ No newline at end of file diff --git a/xservice-mysql-starter/src/main/java/com/xiang/xservice/mysql/config/DynamicDataSourceConfig.java b/xservice-mysql-starter/src/main/java/com/xiang/xservice/mysql/config/DynamicDataSourceConfig.java index 1a99752..0f27f78 100644 --- a/xservice-mysql-starter/src/main/java/com/xiang/xservice/mysql/config/DynamicDataSourceConfig.java +++ b/xservice-mysql-starter/src/main/java/com/xiang/xservice/mysql/config/DynamicDataSourceConfig.java @@ -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; diff --git a/xservice-mysql-starter/src/main/java/com/xiang/xservice/mysql/entity/DataSourceProperty.java b/xservice-mysql-starter/src/main/java/com/xiang/xservice/mysql/entity/DataSourceProperty.java index 1eb20bd..36d95f3 100644 --- a/xservice-mysql-starter/src/main/java/com/xiang/xservice/mysql/entity/DataSourceProperty.java +++ b/xservice-mysql-starter/src/main/java/com/xiang/xservice/mysql/entity/DataSourceProperty.java @@ -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 } diff --git a/xservice-mysql-starter/src/main/java/com/xiang/xservice/mysql/service/DynamicRoutingDataSource.java b/xservice-mysql-starter/src/main/java/com/xiang/xservice/mysql/service/DynamicRoutingDataSource.java index f058af8..ddff2ae 100644 --- a/xservice-mysql-starter/src/main/java/com/xiang/xservice/mysql/service/DynamicRoutingDataSource.java +++ b/xservice-mysql-starter/src/main/java/com/xiang/xservice/mysql/service/DynamicRoutingDataSource.java @@ -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; } }