diff --git a/pom.xml b/pom.xml index d1ec1b3..f30f2f6 100644 --- a/pom.xml +++ b/pom.xml @@ -125,10 +125,11 @@ org.springframework.boot spring-boot-starter-web - - org.springframework.boot - spring-boot-starter-actuator - + + + + + commons-io commons-io @@ -174,6 +175,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-message-starter/pom.xml b/xservice-message-starter/pom.xml index 91631df..7ec39ba 100644 --- a/xservice-message-starter/pom.xml +++ b/xservice-message-starter/pom.xml @@ -10,7 +10,7 @@ xservice-message-starter - 1.1 + 2.0 17 @@ -22,7 +22,7 @@ com.xiang xservice-common - 1.0 + 1.2 diff --git a/xservice-message-starter/src/main/java/com/xiang/xservice/basic/xservice/dingTalk/service/DingTalkService.java b/xservice-message-starter/src/main/java/com/xiang/xservice/basic/xservice/dingTalk/service/DingTalkService.java index 132dcb7..a24b972 100644 --- a/xservice-message-starter/src/main/java/com/xiang/xservice/basic/xservice/dingTalk/service/DingTalkService.java +++ b/xservice-message-starter/src/main/java/com/xiang/xservice/basic/xservice/dingTalk/service/DingTalkService.java @@ -12,6 +12,7 @@ import com.dingtalk.api.response.OapiGettokenResponse; import com.dingtalk.api.response.OapiMessageCorpconversationAsyncsendV2Response; import com.dingtalk.api.response.OapiRobotSendResponse; import com.xiang.xservice.basic.xservice.dingTalk.enums.DingTalkUrlEnum; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -46,53 +47,40 @@ public class DingTalkService { private static final String CLIENT_SECRET = "wyapsH6y8P1K_wuTPKGKwG0mquj1uth9Dxn6HcRpta3sh8Syukl0C8nOmR1PeBzs"; - private static final String GRANT_TYPE = "client_credentials"; - - private static final String USER_ID = "450841600726084717"; - - private static final String MSG_TYPE = "text"; + private static final String MSG_TYPE_TEXT = "text"; /** - * 自定义机器人token - */ - private static final String CUSTOM_ROBOT_TOKEN = "4709b708d961846e0aee523c5abc3b67e8fa424ee292501d85efd4e504f15a8b"; - - /** - * 密钥 - */ - private static final String SECRET = "SEC768ed578c0fb31a9aec84b1c1db4f195f5aca203985bbb9d549e23e41c8874d1"; - - /** - * 发送机器人消息 - * @param msg + * 发送机器人消息到指定的群 + * @param robotSecret 机器人密钥 + * @param robotToken 机器人token + * @param userIds @对象 + * @param msg 消息内容 * @return * @throws Exception */ - public String sendRobotMessage(String msg) throws Exception { + public String sendRobotMessage(String robotSecret, String robotToken, List userIds, String msg) throws Exception { Long timestamp = System.currentTimeMillis(); - String stringToSign = timestamp + "\n" + SECRET; + String stringToSign = timestamp + "\n" + robotSecret; Mac mac = Mac.getInstance("HmacSHA256"); - mac.init(new SecretKeySpec(SECRET.getBytes(StandardCharsets.UTF_8), "HmacSHA256")); + mac.init(new SecretKeySpec(robotSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256")); byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8)); String sign = URLEncoder.encode(Base64.getEncoder().encodeToString(signData), StandardCharsets.UTF_8); //sign字段和timestamp字段必须拼接到请求URL上,否则会出现 310000 的错误信息 DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/robot/send?sign=" + sign + "×tamp=" + timestamp); OapiRobotSendRequest req = new OapiRobotSendRequest(); - /** - * 发送文本消息 - */ + //定义文本内容 OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text(); text.setContent(msg); //定义 @ 对象 OapiRobotSendRequest.At at = new OapiRobotSendRequest.At(); - at.setAtUserIds(List.of(USER_ID)); + at.setAtUserIds(userIds); //设置消息类型 - req.setMsgtype("text"); + req.setMsgtype(MSG_TYPE_TEXT); req.setText(text); req.setAt(at); - OapiRobotSendResponse rsp = client.execute(req, CUSTOM_ROBOT_TOKEN); + OapiRobotSendResponse rsp = client.execute(req, robotToken); return rsp.getBody(); } @@ -110,7 +98,7 @@ public class DingTalkService { OapiChatSendRequest.Text text = new OapiChatSendRequest.Text(); text.setContent(message); msg.setText(text); - msg.setMsgtype("text"); + msg.setMsgtype(MSG_TYPE_TEXT); req.setMsg(msg); OapiChatSendResponse rsp = client.execute(req, token); log.info("[DingTalk] send chat message, req:{}, token:{}, response:{}", JSONObject.toJSONString(req), token, JSONObject.toJSONString(rsp)); @@ -133,7 +121,7 @@ public class DingTalkService { req.setUseridList(userId); req.setToAllUser(false); OapiMessageCorpconversationAsyncsendV2Request.Msg obj1 = new OapiMessageCorpconversationAsyncsendV2Request.Msg(); - obj1.setMsgtype(MSG_TYPE); + obj1.setMsgtype(MSG_TYPE_TEXT); OapiMessageCorpconversationAsyncsendV2Request.Text obj2 = new OapiMessageCorpconversationAsyncsendV2Request.Text(); obj2.setContent(message); obj1.setText(obj2); diff --git a/xservice-mysql-starter/pom.xml b/xservice-mysql-starter/pom.xml index 0eebc0a..9cdeee6 100644 --- a/xservice-mysql-starter/pom.xml +++ b/xservice-mysql-starter/pom.xml @@ -10,11 +10,19 @@ xservice-mysql-starter - 1.1 + 2.0 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; } } diff --git a/xservice-schedule-starter/pom.xml b/xservice-schedule-starter/pom.xml index 55cf4e8..b5fb3ee 100644 --- a/xservice-schedule-starter/pom.xml +++ b/xservice-schedule-starter/pom.xml @@ -22,7 +22,7 @@ com.xiang xservice-common - 1.0 + 1.2