一、WebSocket簡介
WebSocket協議是基于TCP的一種新的網絡協議。它實現了瀏覽器與服務器全雙工(full-duplex)通信,允許服務器主動向客戶端推送數據。
與傳統的 HTTP 請求-響應模式不同,WebSocket 在建立連接后,允許服務器和客戶端之間進行雙向實時通信。
WebSocket主要特點:
- 建立在 TCP 協議之上。
- 與 HTTP 協議有著良好的兼容性。
- 數據格式比較輕量,性能開銷小,通信高效。
- 可以發送文本,也可以發送二進制數據。
- 沒有同源限制,客戶端可以與任意服務器通信。
- 協議標識符是ws(如果加密,則為wss),服務器網址就是 URL。
二、SpringBoot3集成WebSocket
引入 WebSocket依賴:
<!-- WebSocket依賴 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>3.4.5</version></dependency>
1、WebSocket配置類
創建 WebSocket 配置類,啟用 WebSocket 功能并注冊端點。
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Autowiredprivate CustomTextWebSocketHandler customTextWebSocketHandler;@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {/*** addHandler方法參數說明* 參數1:添加 WebSocket 處理器* 參數2:WebSocket的連接路徑、端口為項目端口、路徑為自定義。比如:URL = ws://127.0.0.1:38081/ws*/registry.addHandler(customTextWebSocketHandler, "/ws").setAllowedOrigins("*"); // 允許跨域訪問}}
2、自定義WebSocket處理器
創建自定義的 WebSocket 處理器,處理消息收發。
@Slf4j
@Component
@RequiredArgsConstructor
public class CustomTextWebSocketHandler extends TextWebSocketHandler {private final WebSocketSessionManager sessionManager;/*** 用于存儲WebSocket會話*/private final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {String sessionId = session.getId();sessionManager.add(session);log.info("WebSocket連接建立成功:{}", sessionId);}@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {String payload = message.getPayload();log.info("WebSocket收到消息 ==> sessionId = {}, payload = {} ", session.getId(), message.getPayload());boolean open = session.isOpen();if (!open) {log.info("WebSocket發送消息失敗 ==> sessionId = {} 不在線 ", session.getId());return;}try {/*** TODO 發送回復消息*/String replyMessage = "服務器 -> 客戶端 收到了,消息" + payload;session.sendMessage(new TextMessage(replyMessage));} catch (IOException e) {log.info("WebSocket發送消息異常 ==> sessionId = {}, e = ", session.getId(), e);}}@Overridepublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {log.info("WebSocket傳輸錯誤 ==> sessionId = {}, exception = {} ", session.getId(), exception.getMessage());// 傳輸錯誤,關閉連接this.afterConnectionClosed(session, CloseStatus.PROTOCOL_ERROR);}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {log.info("WebSocket連接關閉 ==> sessionId = {}, CloseStatus = {} ", session.getId(), status);sessionManager.remove(session);}/*** 廣播發送消息給所有連接的 WebSocket客戶端** @param message*/public void sendMessageByBroadcast(String message) {sessionManager.getAllSession().stream().filter(WebSocketSession::isOpen).forEach(session -> {try {session.sendMessage(new TextMessage(message));} catch (IOException e) {log.info("WebSocket 廣播發送消息異常 ==> sessionId = {}, e = ", session.getId(), e);}});}}
3、創建WebSocket會話管理類
自定義創建 WebSocket會話管理類,根據業務我們可以擴展存儲不同的信息。
@Slf4j
@Component
public class WebSocketSessionManager {/*** 用于存儲 WebSocket會話* key: sessionId* value: WebSocketSession*/private final Map<String, WebSocketSession> wsSessionMap = new ConcurrentHashMap<>();/*** 添加 WebSocket會話** @param session*/public void add(WebSocketSession session) {wsSessionMap.put(session.getId(), session);}/*** 移除 WebSocket會話** @param session*/public void remove(WebSocketSession session) {wsSessionMap.remove(session.getId());}/*** 獲取 WebSocket會話** @param sessionId* @return*/public WebSocketSession get(String sessionId) {return wsSessionMap.get(sessionId);}/*** 獲取所有 WebSocket會話*/public List<WebSocketSession> getAllSession() {Collection<WebSocketSession> sessions = wsSessionMap.values();return Optional.ofNullable(sessions).orElse(new ArrayList<>()).stream().toList();}
}
4、controller
創建測試controller,用來測試消息廣播。
@RestController
@RequestMapping("/api/wsTest")
@RequiredArgsConstructor
public class WSTestController {private final CustomTextWebSocketHandler customTextWebSocketHandler;/*** 廣播發送消息接口* 給所有連接的 WebSocket 客戶端** @param message* @return*/@GetMapping("/sendMessageByBroadcast")public ResponseEntity<String> sendMessageByBroadcast(@RequestParam("message") String message) {customTextWebSocketHandler.sendMessageByBroadcast(message);return ResponseEntity.ok("廣播發送消息接口 => 發送成功");}}
啟動項目,使用 WebSocket 在線測試工具等,測試ok。
WebSocket 在線測試工具:https://wstool.js.org/
根據業務還可以自定義握手攔截器校驗token,配置最大閑置時間,比如3分鐘沒動自動關閉連接等配置。
– 求知若饑,虛心若愚。