WebSocket 是一種在單個 TCP 連線上進行全雙工通訊的協定,它允許在瀏覽器和伺服器之間進行實時的、雙向的通訊。相對於傳統的基於請求和響應的 HTTP 協定,WebSocket 提供了一種更有效、更實時的通訊方式,適用於需要實時更新、實時通知和實時互動的應用。
WebSocket 的一些關鍵特點包括:
在pom.xml中匯入以下依賴,版本由SpringBoot管理
<!-- websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
建立WebSocketConfig設定類,並將其注入到Bean容器中
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
建立WebSocketServer類,並將其注入到Bean容器中
注意:@ServerEndpoint("/WebSocket"),該註解用於設定建立WebSocket連線的路徑,可以按需修改。
該類一般擁有以下功能:
可以將該類理解為WebSocket生命週期中會呼叫的方法。
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
@Slf4j
@Component
@ServerEndpoint("/WebSocket")
public class WebSocketServer {
private Session session;
@OnOpen
public void onOpen(Session session) {
this.session = session;
WebSocketManager.sentToUser(session, "WebSocket is connected!");
WebSocketManager.addWebSocketServer(this);
log.info("與SessionId:{}建立連線", session.getId());
}
@OnClose
public void onClose() {
WebSocketManager.removeWebSocketServer(this);
log.info("WebSocket連線關閉");
}
@OnMessage
public void onMessage(String message, Session session) {
log.info("來自SessionId:{}的訊息:{}", session.getId(), message);
}
@OnError
public void onError(Session session, Throwable error) {
log.error("Session:{}的WebSocket發生錯誤", session.getId(), error);
}
public Session getSession() {
return session;
}
public String getSessionId() {
return session.getId();
}
}
該類用於管理WebSocketServer(其實主要是管理Session),如果不需要傳送訊息給特定使用者,那麼無需建立該類,在WebSocketServer類中維護一個類變數即可。
import lombok.extern.slf4j.Slf4j;
import javax.websocket.Session;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
@Slf4j
public class WebSocketManager {
private final static CopyOnWriteArraySet<WebSocketServer> webSocketServerSet = new CopyOnWriteArraySet<>();
private final static ConcurrentHashMap<String, WebSocketServer> webSocketServerMap = new ConcurrentHashMap<>();
public static void addWebSocketServer(WebSocketServer webSocketServer){
if (webSocketServer != null){
webSocketServerSet.add(webSocketServer);
webSocketServerMap.put(webSocketServer.getSessionId(), webSocketServer);
}
}
public static void removeWebSocketServer(WebSocketServer webSocketServer){
webSocketServerSet.remove(webSocketServer);
webSocketServerMap.remove(webSocketServer.getSessionId());
}
/**
* 通過SessionId傳送訊息給特定使用者
* @param
* @param msg
*/
public static void sentToUser(String sessionId, String msg){
Session session = webSocketServerMap.get(sessionId).getSession();
sentToUser(session, msg);
}
/**
* 通過Session傳送訊息給特定使用者
* @param session
* @param msg
*/
public static void sentToUser(Session session, String msg){
if (session == null){
log.error("不存在該Session,無法傳送訊息");
return;
}
session.getAsyncRemote().sendText(msg);
}
/**
* 傳送訊息給所有使用者
* @param msg
*/
public static void sentToAllUser(String msg){
for (WebSocketServer webSocketServer : webSocketServerSet) {
sentToUser(webSocketServer.getSession(), msg);
}
log.info("向所有使用者傳送WebSocket訊息完畢,訊息:{}", msg);
}
}
使用Postman等工具進行WebSocket連線,連線路徑為WebSocket
(與前文的@ServerEndpoint
內容一致)。建立連線後會收到"WebSocket is connected!"
如果你的專案中有登入功能,那麼應該在你的登入時將使用者的Session記錄下來。你可以將Session記錄在本地快取、Redis和Grava快取等能夠建立關聯關係的地方。