Merge branch 'master' into feat/auth_dev_v1
This commit is contained in:
16
pom.xml
16
pom.xml
@@ -125,10 +125,11 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<!-- <dependency>-->
|
||||||
<groupId>org.springframework.boot</groupId>
|
<!-- <groupId>org.springframework.boot</groupId>-->
|
||||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
<!-- <artifactId>spring-boot-starter-actuator</artifactId>-->
|
||||||
</dependency>
|
<!-- <version>${spring.boot.version}</version>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-io</groupId>
|
<groupId>commons-io</groupId>
|
||||||
<artifactId>commons-io</artifactId>
|
<artifactId>commons-io</artifactId>
|
||||||
@@ -174,6 +175,13 @@
|
|||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- ssh -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.jcraft</groupId>
|
||||||
|
<artifactId>jsch</artifactId>
|
||||||
|
<version>0.1.55</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<artifactId>xservice-basic</artifactId>
|
<artifactId>xservice-basic</artifactId>
|
||||||
<version>1.1</version>
|
<version>1.1</version>
|
||||||
</parent>
|
</parent>
|
||||||
<version>1.2</version>
|
<version>1.3</version>
|
||||||
|
|
||||||
<artifactId>xservice-common</artifactId>
|
<artifactId>xservice-common</artifactId>
|
||||||
|
|
||||||
|
|||||||
@@ -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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>xservice-message-starter</artifactId>
|
<artifactId>xservice-message-starter</artifactId>
|
||||||
<version>1.1</version>
|
<version>2.0</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>17</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.xiang</groupId>
|
<groupId>com.xiang</groupId>
|
||||||
<artifactId>xservice-common</artifactId>
|
<artifactId>xservice-common</artifactId>
|
||||||
<version>1.0</version>
|
<version>1.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- 钉钉jar包 -->
|
<!-- 钉钉jar包 -->
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import com.dingtalk.api.response.OapiGettokenResponse;
|
|||||||
import com.dingtalk.api.response.OapiMessageCorpconversationAsyncsendV2Response;
|
import com.dingtalk.api.response.OapiMessageCorpconversationAsyncsendV2Response;
|
||||||
import com.dingtalk.api.response.OapiRobotSendResponse;
|
import com.dingtalk.api.response.OapiRobotSendResponse;
|
||||||
import com.xiang.xservice.basic.xservice.dingTalk.enums.DingTalkUrlEnum;
|
import com.xiang.xservice.basic.xservice.dingTalk.enums.DingTalkUrlEnum;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@@ -46,53 +47,40 @@ public class DingTalkService {
|
|||||||
|
|
||||||
private static final String CLIENT_SECRET = "wyapsH6y8P1K_wuTPKGKwG0mquj1uth9Dxn6HcRpta3sh8Syukl0C8nOmR1PeBzs";
|
private static final String CLIENT_SECRET = "wyapsH6y8P1K_wuTPKGKwG0mquj1uth9Dxn6HcRpta3sh8Syukl0C8nOmR1PeBzs";
|
||||||
|
|
||||||
private static final String GRANT_TYPE = "client_credentials";
|
private static final String MSG_TYPE_TEXT = "text";
|
||||||
|
|
||||||
private static final String USER_ID = "450841600726084717";
|
|
||||||
|
|
||||||
private static final String MSG_TYPE = "text";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义机器人token
|
* 发送机器人消息到指定的群
|
||||||
*/
|
* @param robotSecret 机器人密钥
|
||||||
private static final String CUSTOM_ROBOT_TOKEN = "4709b708d961846e0aee523c5abc3b67e8fa424ee292501d85efd4e504f15a8b";
|
* @param robotToken 机器人token
|
||||||
|
* @param userIds @对象
|
||||||
/**
|
* @param msg 消息内容
|
||||||
* 密钥
|
|
||||||
*/
|
|
||||||
private static final String SECRET = "SEC768ed578c0fb31a9aec84b1c1db4f195f5aca203985bbb9d549e23e41c8874d1";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送机器人消息
|
|
||||||
* @param msg
|
|
||||||
* @return
|
* @return
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public String sendRobotMessage(String msg) throws Exception {
|
public String sendRobotMessage(String robotSecret, String robotToken, List<String> userIds, String msg) throws Exception {
|
||||||
Long timestamp = System.currentTimeMillis();
|
Long timestamp = System.currentTimeMillis();
|
||||||
String stringToSign = timestamp + "\n" + SECRET;
|
String stringToSign = timestamp + "\n" + robotSecret;
|
||||||
Mac mac = Mac.getInstance("HmacSHA256");
|
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));
|
byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
|
||||||
String sign = URLEncoder.encode(Base64.getEncoder().encodeToString(signData), StandardCharsets.UTF_8);
|
String sign = URLEncoder.encode(Base64.getEncoder().encodeToString(signData), StandardCharsets.UTF_8);
|
||||||
|
|
||||||
//sign字段和timestamp字段必须拼接到请求URL上,否则会出现 310000 的错误信息
|
//sign字段和timestamp字段必须拼接到请求URL上,否则会出现 310000 的错误信息
|
||||||
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/robot/send?sign=" + sign + "×tamp=" + timestamp);
|
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/robot/send?sign=" + sign + "×tamp=" + timestamp);
|
||||||
OapiRobotSendRequest req = new OapiRobotSendRequest();
|
OapiRobotSendRequest req = new OapiRobotSendRequest();
|
||||||
/**
|
|
||||||
* 发送文本消息
|
|
||||||
*/
|
|
||||||
//定义文本内容
|
//定义文本内容
|
||||||
OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text();
|
OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text();
|
||||||
text.setContent(msg);
|
text.setContent(msg);
|
||||||
//定义 @ 对象
|
//定义 @ 对象
|
||||||
OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();
|
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.setText(text);
|
||||||
req.setAt(at);
|
req.setAt(at);
|
||||||
OapiRobotSendResponse rsp = client.execute(req, CUSTOM_ROBOT_TOKEN);
|
OapiRobotSendResponse rsp = client.execute(req, robotToken);
|
||||||
return rsp.getBody();
|
return rsp.getBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +98,7 @@ public class DingTalkService {
|
|||||||
OapiChatSendRequest.Text text = new OapiChatSendRequest.Text();
|
OapiChatSendRequest.Text text = new OapiChatSendRequest.Text();
|
||||||
text.setContent(message);
|
text.setContent(message);
|
||||||
msg.setText(text);
|
msg.setText(text);
|
||||||
msg.setMsgtype("text");
|
msg.setMsgtype(MSG_TYPE_TEXT);
|
||||||
req.setMsg(msg);
|
req.setMsg(msg);
|
||||||
OapiChatSendResponse rsp = client.execute(req, token);
|
OapiChatSendResponse rsp = client.execute(req, token);
|
||||||
log.info("[DingTalk] send chat message, req:{}, token:{}, response:{}", JSONObject.toJSONString(req), token, JSONObject.toJSONString(rsp));
|
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.setUseridList(userId);
|
||||||
req.setToAllUser(false);
|
req.setToAllUser(false);
|
||||||
OapiMessageCorpconversationAsyncsendV2Request.Msg obj1 = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
|
OapiMessageCorpconversationAsyncsendV2Request.Msg obj1 = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
|
||||||
obj1.setMsgtype(MSG_TYPE);
|
obj1.setMsgtype(MSG_TYPE_TEXT);
|
||||||
OapiMessageCorpconversationAsyncsendV2Request.Text obj2 = new OapiMessageCorpconversationAsyncsendV2Request.Text();
|
OapiMessageCorpconversationAsyncsendV2Request.Text obj2 = new OapiMessageCorpconversationAsyncsendV2Request.Text();
|
||||||
obj2.setContent(message);
|
obj2.setContent(message);
|
||||||
obj1.setText(obj2);
|
obj1.setText(obj2);
|
||||||
|
|||||||
@@ -10,11 +10,19 @@
|
|||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>xservice-mysql-starter</artifactId>
|
<artifactId>xservice-mysql-starter</artifactId>
|
||||||
<version>1.1</version>
|
<version>2.0</version>
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>17</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>17</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.xiang</groupId>
|
||||||
|
<artifactId>xservice-common</artifactId>
|
||||||
|
<version>1.3</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
@@ -29,7 +29,7 @@ public class DynamicDataSourceConfig {
|
|||||||
targetDataSources.put(key, builder.build());
|
targetDataSources.put(key, builder.build());
|
||||||
});
|
});
|
||||||
|
|
||||||
DynamicRoutingDataSource routing = new DynamicRoutingDataSource();
|
DynamicRoutingDataSource routing = new DynamicRoutingDataSource(props);
|
||||||
routing.setDefaultTargetDataSource(targetDataSources.get(props.getPrimary()));
|
routing.setDefaultTargetDataSource(targetDataSources.get(props.getPrimary()));
|
||||||
routing.setTargetDataSources(targetDataSources);
|
routing.setTargetDataSources(targetDataSources);
|
||||||
return routing;
|
return routing;
|
||||||
|
|||||||
@@ -12,5 +12,12 @@ public class DataSourceProperty {
|
|||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
private String driverClassName = "com.mysql.cj.jdbc.Driver";
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,37 @@
|
|||||||
package com.xiang.xservice.mysql.service;
|
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.config.DynamicDataSourceContext;
|
||||||
|
import com.xiang.xservice.mysql.entity.DataSourceProperty;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
|
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
|
||||||
|
import com.xiang.xservice.mysql.entity.DynamicDataSourceProperties;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
|
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
|
||||||
|
|
||||||
|
private final DynamicDataSourceProperties dynamicDataSourceProperties;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object determineCurrentLookupKey() {
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.xiang</groupId>
|
<groupId>com.xiang</groupId>
|
||||||
<artifactId>xservice-common</artifactId>
|
<artifactId>xservice-common</artifactId>
|
||||||
<version>1.0</version>
|
<version>1.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user