Initial commit
Made-with: Cursor
This commit is contained in:
2
astral-service/astral-core/.gitattributes
vendored
Normal file
2
astral-service/astral-core/.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/mvnw text eol=lf
|
||||
*.cmd text eol=crlf
|
||||
33
astral-service/astral-core/.gitignore
vendored
Normal file
33
astral-service/astral-core/.gitignore
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
HELP.md
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
27
astral-service/astral-core/pom.xml
Normal file
27
astral-service/astral-core/pom.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.astral</groupId>
|
||||
<artifactId>astral-parent</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>astral-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.astral</groupId>
|
||||
<artifactId>astral-system</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.springframework.boot</groupId>-->
|
||||
<!-- <artifactId>spring-boot-starter-security</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.astral.core.config.mybatis;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
@EnableTransactionManagement(proxyTargetClass = true)
|
||||
@Configuration
|
||||
public class MyBatisPlusConfig {
|
||||
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
// 分页插件
|
||||
interceptor.addInnerInterceptor(paginationInnerInterceptor());
|
||||
// 乐观锁插件
|
||||
interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor());
|
||||
// 阻断插件
|
||||
interceptor.addInnerInterceptor(blockAttackInnerInterceptor());
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页插件,自动识别数据库类型
|
||||
*/
|
||||
public PaginationInnerInterceptor paginationInnerInterceptor() {
|
||||
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
|
||||
// 设置数据库类型
|
||||
paginationInnerInterceptor.setDbType(DbType.POSTGRE_SQL);
|
||||
// 设置最大单页限制数量,默认 500 条,-1 不受限制
|
||||
paginationInnerInterceptor.setMaxLimit(-1L);
|
||||
return paginationInnerInterceptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 乐观锁插件
|
||||
*/
|
||||
public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() {
|
||||
return new OptimisticLockerInnerInterceptor();
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果是对全表的删除和更新操作,就会终止该操作
|
||||
*/
|
||||
public BlockAttackInnerInterceptor blockAttackInnerInterceptor() {
|
||||
return new BlockAttackInnerInterceptor();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.astral.core.config.mybatis;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import org.apache.ibatis.reflection.MetaObject;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Component
|
||||
public class MybatisPlusMetaobjectHandler implements MetaObjectHandler {
|
||||
@Override
|
||||
public void insertFill(MetaObject metaObject) {
|
||||
this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
|
||||
this.setFieldValByName("isDeleted", 0, metaObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFill(MetaObject metaObject) {
|
||||
this.strictInsertFill(metaObject, "updateTime", Date.class, new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录用户名
|
||||
*/
|
||||
private String getLoginUsername() {
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
//package com.astral.core.config.webSocketConfig;
|
||||
//
|
||||
//import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
//
|
||||
//import javax.websocket.Session;
|
||||
//import java.util.Collections;
|
||||
//import java.util.Iterator;
|
||||
//import java.util.LinkedList;
|
||||
//import java.util.List;
|
||||
//import java.util.concurrent.BlockingQueue;
|
||||
//import java.util.concurrent.LinkedBlockingQueue;
|
||||
//import java.util.concurrent.TimeUnit;
|
||||
//
|
||||
//public class ChatRoomWebSocket {
|
||||
//
|
||||
// private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
//
|
||||
// // Message types
|
||||
// public static final String TYPE_ERROR = "error";
|
||||
// public static final String TYPE_BIM2GLTF = "bim2gltf";
|
||||
// public static final String TYPE_CAD = "cad";
|
||||
// public static final String TYPE_CHATROOM_JOIN = "chatroom-join";
|
||||
// public static final String TYPE_CHATROOM_LEAVE = "chatroom-leave";
|
||||
//
|
||||
// // Message class
|
||||
// public static class Message {
|
||||
// private String name;
|
||||
// private ResponseMessage message;
|
||||
//
|
||||
// public Message() {}
|
||||
//
|
||||
// public Message(String name, ResponseMessage message) {
|
||||
// this.name = name;
|
||||
// this.message = message;
|
||||
// }
|
||||
//
|
||||
// // Getters and setters
|
||||
// public String getName() {
|
||||
// return name;
|
||||
// }
|
||||
//
|
||||
// public void setName(String name) {
|
||||
// this.name = name;
|
||||
// }
|
||||
//
|
||||
// public ResponseMessage getMessage() {
|
||||
// return message;
|
||||
// }
|
||||
//
|
||||
// public void setMessage(ResponseMessage message) {
|
||||
// this.message = message;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // ResponseMessage class
|
||||
// public static class ResponseMessage {
|
||||
// private String type;
|
||||
// private String subscriber;
|
||||
// private Object data;
|
||||
//
|
||||
// public ResponseMessage() {}
|
||||
//
|
||||
// public ResponseMessage(String type, String subscriber, Object data) {
|
||||
// this.type = type;
|
||||
// this.subscriber = subscriber;
|
||||
// this.data = data;
|
||||
// }
|
||||
//
|
||||
// // Getters and setters
|
||||
// public String getType() {
|
||||
// return type;
|
||||
// }
|
||||
//
|
||||
// public void setType(String type) {
|
||||
// this.type = type;
|
||||
// }
|
||||
//
|
||||
// public String getSubscriber() {
|
||||
// return subscriber;
|
||||
// }
|
||||
//
|
||||
// public void setSubscriber(String subscriber) {
|
||||
// this.subscriber = subscriber;
|
||||
// }
|
||||
//
|
||||
// public Object getData() {
|
||||
// return data;
|
||||
// }
|
||||
//
|
||||
// public void setData(Object data) {
|
||||
// this.data = data;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Connection class
|
||||
// public static class Connection {
|
||||
// private String uname;
|
||||
// private Session wsConn;
|
||||
//
|
||||
// public Connection(String uname, Session wsConn) {
|
||||
// this.uname = uname;
|
||||
// this.wsConn = wsConn;
|
||||
// }
|
||||
//
|
||||
// public String getUname() {
|
||||
// return uname;
|
||||
// }
|
||||
//
|
||||
// public Session getWsConn() {
|
||||
// return wsConn;
|
||||
// }
|
||||
//
|
||||
// public void close() {
|
||||
// try {
|
||||
// if (wsConn != null && wsConn.isOpen()) {
|
||||
// wsConn.close();
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Channels
|
||||
// private static final BlockingQueue<Connection> subscribeQueue = new LinkedBlockingQueue<>(10);
|
||||
// private static final BlockingQueue<String> unsubscribeQueue = new LinkedBlockingQueue<>(10);
|
||||
// private static final BlockingQueue<Message> publishQueue = new LinkedBlockingQueue<>(10);
|
||||
//
|
||||
// // Subscribers list
|
||||
// private static final List<Connection> subscribers = Collections.synchronizedList(new LinkedList<>());
|
||||
//
|
||||
// static {
|
||||
// // Start the chatroom thread
|
||||
// new Thread(ChatRoomWebSocket::chatroom).start();
|
||||
// }
|
||||
//
|
||||
// public static void join(Connection conn) {
|
||||
// subscribeQueue.offer(conn);
|
||||
// }
|
||||
//
|
||||
// public static void leave(String user) {
|
||||
// unsubscribeQueue.offer(user);
|
||||
// }
|
||||
//
|
||||
// public static void publish(Message message) {
|
||||
// publishQueue.offer(message);
|
||||
// }
|
||||
//
|
||||
// public static Connection getConnByUName(String uname) {
|
||||
// synchronized (subscribers) {
|
||||
// for (Connection conn : subscribers) {
|
||||
// if (conn.getUname().equals(uname)) {
|
||||
// return conn;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// private static boolean isUserExist(String user) {
|
||||
// synchronized (subscribers) {
|
||||
// for (Connection conn : subscribers) {
|
||||
// if (conn.getUname().equals(user)) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// private static void broadcastWebSocket(Message message) {
|
||||
// synchronized (subscribers) {
|
||||
// Iterator<Connection> iterator = subscribers.iterator();
|
||||
// while (iterator.hasNext()) {
|
||||
// Connection conn = iterator.next();
|
||||
// Session ws = conn.getWsConn();
|
||||
// if (ws != null && ws.isOpen()) {
|
||||
// try {
|
||||
// ResponseMessage msg = message.getMessage();
|
||||
// if (msg.getSubscriber() == null || msg.getSubscriber().isEmpty()) {
|
||||
// msg.setSubscriber(message.getName());
|
||||
// }
|
||||
//
|
||||
// String msgJson = objectMapper.writeValueAsString(msg);
|
||||
// ws.getBasicRemote().sendText(msgJson);
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// iterator.remove();
|
||||
// unsubscribeQueue.offer(conn.getUname());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private static void chatroom() {
|
||||
// while (true) {
|
||||
// try {
|
||||
// Connection subConn = subscribeQueue.poll(100, TimeUnit.MILLISECONDS);
|
||||
// if (subConn != null) {
|
||||
// if (!isUserExist(subConn.getUname())) {
|
||||
// synchronized (subscribers) {
|
||||
// subscribers.add(subConn);
|
||||
// }
|
||||
//
|
||||
// ResponseMessage msgJson = new ResponseMessage(
|
||||
// TYPE_CHATROOM_JOIN,
|
||||
// subConn.getUname(),
|
||||
// subConn.getUname() + " has joined the room."
|
||||
// );
|
||||
// publishQueue.offer(new Message(subConn.getUname(), msgJson));
|
||||
// System.out.println("User {} join the room." + subConn.getUname());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Check publish queue
|
||||
// Message message = publishQueue.poll(100, TimeUnit.MILLISECONDS);
|
||||
// if (message != null) {
|
||||
// broadcastWebSocket(message);
|
||||
// }
|
||||
//
|
||||
// // Check unsubscribe queue
|
||||
// String unsub = unsubscribeQueue.poll(100, TimeUnit.MILLISECONDS);
|
||||
// if (unsub != null) {
|
||||
// synchronized (subscribers) {
|
||||
// Iterator<Connection> iterator = subscribers.iterator();
|
||||
// while (iterator.hasNext()) {
|
||||
// Connection conn = iterator.next();
|
||||
// if (conn.getUname().equals(unsub)) {
|
||||
// iterator.remove();
|
||||
// conn.close();
|
||||
//
|
||||
// // Broadcast leave message
|
||||
// ResponseMessage msgJson = new ResponseMessage(
|
||||
// TYPE_CHATROOM_LEAVE,
|
||||
// unsub,
|
||||
// unsub + " exit the room."
|
||||
// );
|
||||
// publishQueue.offer(new Message(unsub, msgJson));
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } catch (InterruptedException e) {
|
||||
// e.printStackTrace();
|
||||
// Thread.currentThread().interrupt();
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
@@ -0,0 +1,54 @@
|
||||
//package com.astral.core.config.webSocketConfig;
|
||||
//
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.beans.factory.annotation.Value;
|
||||
//import org.springframework.context.annotation.Configuration;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//
|
||||
//import javax.annotation.PostConstruct;
|
||||
//
|
||||
//@Component
|
||||
//public class RevitWebSocketConfig {
|
||||
//
|
||||
// // 从配置文件中读取Revit的地址、端口、路径和超时时间
|
||||
// @Value("${revit.address}")
|
||||
// private String address;
|
||||
//
|
||||
// @Value("${revit.port}")
|
||||
// private String port;
|
||||
//
|
||||
// @Value("${revit.path}")
|
||||
// private String path;
|
||||
//
|
||||
// @Value("${revit.timeout}")
|
||||
// private int timeout;
|
||||
//
|
||||
// private RevitWsClient revitWs;
|
||||
//
|
||||
// public RevitWsClient getRevitWs() {
|
||||
// return revitWs;
|
||||
// }
|
||||
//
|
||||
// public RevitWsClient createRevitWs() {
|
||||
// // 启动WebSocket连接Revit
|
||||
// RevitWsClient revitWs = new RevitWsClient(address, port, path, timeout);
|
||||
// revitWs.start();
|
||||
//
|
||||
// // 设置8小时自动重连(以毫秒为单位)
|
||||
// long reconnectInterval = 8 * 60 * 60 * 1000; // 8小时
|
||||
// new Thread(() -> {
|
||||
// while (true) {
|
||||
// try {
|
||||
// Thread.sleep(reconnectInterval);
|
||||
// if (!revitWs.isConnected()) {
|
||||
// revitWs.reconnect();
|
||||
// }
|
||||
// } catch (InterruptedException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// }).start();
|
||||
// return revitWs;
|
||||
// }
|
||||
//
|
||||
//}
|
||||
@@ -0,0 +1,180 @@
|
||||
package com.astral.core.config.webSocketConfig;
|
||||
|
||||
import com.astral.common.utils.CommonUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.websocket.*;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
@Component
|
||||
@ClientEndpoint
|
||||
public class RevitWsClient {
|
||||
|
||||
private Session session;
|
||||
private String address;
|
||||
private String port;
|
||||
private String path;
|
||||
private int timeout;
|
||||
|
||||
// 使用BlockingQueue作为消息队列
|
||||
private final BlockingQueue<String> sendMsgQueue = new LinkedBlockingQueue<>();
|
||||
|
||||
private final BlockingQueue<String> recvMsgQueue = new LinkedBlockingQueue<>();
|
||||
|
||||
private WebSocketContainer container;
|
||||
|
||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||
|
||||
public RevitWsClient() {
|
||||
|
||||
}
|
||||
|
||||
public RevitWsClient(String address, String port, String path, int timeout) {
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
this.path = path;
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
try {
|
||||
URI uri = new URI("ws://" + address + ":" + port + path);
|
||||
container = ContainerProvider.getWebSocketContainer();
|
||||
container.setDefaultMaxSessionIdleTimeout(timeout);
|
||||
session = container.connectToServer(this, uri);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void startHeartbeat() {
|
||||
scheduler.scheduleAtFixedRate(() -> {
|
||||
try {
|
||||
if (session != null && session.isOpen()) {
|
||||
session.getBasicRemote().sendText("ping");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}, 0, 30, TimeUnit.SECONDS); // 每 30 秒发送一次心跳
|
||||
}
|
||||
|
||||
public void reconnect() {
|
||||
if (session != null && session.isOpen()) {
|
||||
try {
|
||||
session.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
start();
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return session != null && session.isOpen();
|
||||
}
|
||||
|
||||
@OnOpen
|
||||
public void onOpen(Session session) {
|
||||
this.session = session;
|
||||
System.out.println("Connected to Revit WebSocket server");
|
||||
startHeartbeat();
|
||||
}
|
||||
|
||||
@OnMessage
|
||||
public void onMessage(String message) {
|
||||
System.out.println("Received message from Revit: " + message);
|
||||
try {
|
||||
if(Objects.equals(message, "pong")) return;
|
||||
|
||||
if(CommonUtils.isJsonValid(message)){
|
||||
recvMsgQueue.put(message);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
System.err.println("Failed to save message: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@OnClose
|
||||
public void onClose(Session session, CloseReason closeReason) {
|
||||
System.out.println("Disconnected from Revit WebSocket server: " + closeReason);
|
||||
// this.session = null;
|
||||
reconnect();
|
||||
}
|
||||
|
||||
@OnError
|
||||
public void onError(Session session, Throwable throwable) {
|
||||
System.out.println("WebSocket error: " + throwable.getMessage());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 服务器端推送消息
|
||||
*/
|
||||
public void sendMsg(String message) {
|
||||
try {
|
||||
// 将消息放入队列
|
||||
sendMsgQueue.put(message);
|
||||
startMessageSender();
|
||||
} catch (InterruptedException e) {
|
||||
// 处理中断异常
|
||||
Thread.currentThread().interrupt();
|
||||
System.err.println("Failed to send message: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务器端推送消息
|
||||
*/
|
||||
public void pushMessage(String message) {
|
||||
if (session != null && session.isOpen()) {
|
||||
try {
|
||||
synchronized (session){
|
||||
session.getBasicRemote().sendText(message);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动一个线程从队列中取出消息并发送
|
||||
*/
|
||||
public void startMessageSender() {
|
||||
Thread senderThread = new Thread(() -> {
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
try {
|
||||
// 从队列中取出消息
|
||||
String msg = sendMsgQueue.take();
|
||||
pushMessage(msg);
|
||||
} catch (InterruptedException e) {
|
||||
// 处理中断异常
|
||||
Thread.currentThread().interrupt();
|
||||
System.err.println("Message sender thread interrupted: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
senderThread.setDaemon(true); // 设置为守护线程
|
||||
senderThread.start();
|
||||
}
|
||||
|
||||
|
||||
public String readMsg() {
|
||||
try {
|
||||
// 从队列中取出消息,如果队列为空则阻塞
|
||||
return recvMsgQueue.take();
|
||||
} catch (InterruptedException e) {
|
||||
// 处理中断异常
|
||||
Thread.currentThread().interrupt();
|
||||
System.err.println("Failed to read message: " + e.getMessage());
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package com.astral.core.config.webSocketConfig;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.websocket.*;
|
||||
import javax.websocket.server.PathParam;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
//@ServerEndpoint("/websocket")
|
||||
@ServerEndpoint("/sys/ws")
|
||||
public class WebSocket {
|
||||
|
||||
private Session session;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
|
||||
/**
|
||||
* 缓存 webSocket连接到单机服务class中(整体方案支持集群)
|
||||
*/
|
||||
private static CopyOnWriteArraySet<WebSocket> webSockets = new CopyOnWriteArraySet<>();
|
||||
/**
|
||||
* 线程安全Map
|
||||
*/
|
||||
private static ConcurrentHashMap<String, Session> sessionPool = new ConcurrentHashMap<>();
|
||||
|
||||
@OnOpen
|
||||
public void onOpen(Session session) {
|
||||
try {
|
||||
String userId = session.getRequestParameterMap().get("uname").get(0);
|
||||
this.session = session;
|
||||
this.userId = userId;
|
||||
webSockets.add(this);
|
||||
sessionPool.put(userId, session);
|
||||
log.info("【websocket消息】有新的连接,总数为:" + webSockets.size());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@OnMessage
|
||||
public void onMessage(Session session, ByteBuffer byteBuffer) {
|
||||
System.out.println("收到Ping消息");
|
||||
if (byteBuffer.remaining() == 1 && byteBuffer.get(0) == (byte) 0x9) {
|
||||
try {
|
||||
byteBuffer.rewind();
|
||||
session.getBasicRemote().sendBinary(ByteBuffer.wrap(new byte[]{0xA}));
|
||||
// session.getBasicRemote().sendText("pong");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OnClose
|
||||
public void onClose() {
|
||||
try {
|
||||
webSockets.remove(this);
|
||||
sessionPool.remove(this.userId);
|
||||
log.info("【websocket消息】连接断开,总数为:" + webSockets.size());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@OnError
|
||||
public void onError(Session session, Throwable t) {
|
||||
log.info("【websocket消息】出现未知错误 ");
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 服务端推送消息
|
||||
*
|
||||
* @param userId
|
||||
* @param message
|
||||
*/
|
||||
public void pushMessage(String userId, String message) {
|
||||
if (StringUtils.isEmpty(userId)) {
|
||||
return;
|
||||
}
|
||||
Session session = sessionPool.get(userId);
|
||||
if (session != null && session.isOpen()) {
|
||||
try {
|
||||
synchronized (session){
|
||||
log.info("【websocket消息】 单点消息:" + message);
|
||||
session.getBasicRemote().sendText(message);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务器端推送消息
|
||||
*/
|
||||
public void pushMessage(String message) {
|
||||
try {
|
||||
webSockets.forEach(ws -> ws.session.getAsyncRemote().sendText(message));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 后台发送消息到redis
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
public void sendMessage(String message) {
|
||||
this.pushMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 此为单点消息
|
||||
*
|
||||
* @param userId
|
||||
* @param message
|
||||
*/
|
||||
public void sendMessage(String userId, String message) {
|
||||
log.info("【websocket消息】单点消息用户:" + userId + "内容:" + message);
|
||||
this.pushMessage(userId, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 此为单点消息(多人)
|
||||
*
|
||||
* @param userIds
|
||||
* @param message
|
||||
*/
|
||||
public void sendMessage(String[] userIds, String message) {
|
||||
for (String userId : userIds) {
|
||||
sendMessage(userId, message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.astral.core.config.webSocketConfig;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
|
||||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
|
||||
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
||||
//
|
||||
//@Configuration
|
||||
//@EnableWebSocketMessageBroker
|
||||
//public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
|
||||
//
|
||||
// @Override
|
||||
// public void configureMessageBroker(MessageBrokerRegistry config) {
|
||||
// // 配置消息代理
|
||||
// // 客户端订阅的前缀
|
||||
// config.enableSimpleBroker("/topic");
|
||||
// // 客户端发送消息的前缀
|
||||
// config.setApplicationDestinationPrefixes("/app");
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
// // 注册一个WebSocket端点,客户端将使用它连接到WebSocket服务器
|
||||
// registry.addEndpoint("/sys/ws").withSockJS(); // 支持SockJS
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
@Configuration
|
||||
public class WebSocketConfig {
|
||||
|
||||
@Bean
|
||||
public ServerEndpointExporter serverEndpointExporter() {
|
||||
return new ServerEndpointExporter();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user