springboot項目跟JavaScript簡單websocket使用方式
websocket 簡紹
WebSocket 是一種在單個 TCP 連接上進行全雙工通信的協(xié)議。WebSocket 使得客戶端和服務器之間的數(shù)據(jù)交換變得更加簡單,允許服務端主動向客戶端推送數(shù)據(jù)。
在 WebSocket API 中,瀏覽器和服務器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性的連接,并進行雙向數(shù)據(jù)傳輸。
WebSocket 的優(yōu)勢包括
- 全雙工通信:允許服務器主動向客戶端發(fā)送信息,同時也能夠提供客戶端到服務器的低延遲通信。
- 減少帶寬消耗:一旦建立連接之后,通信開銷很小,因為不需要HTTP頭部。
創(chuàng)建更豐富的交互體驗:實時更新數(shù)據(jù)的能力,使得應用能夠更加流暢地響應用戶的動作
可以通過 JavaScript 的 WebSocket 對象來創(chuàng)建一個 WebSocket 連接。
var ws = new WebSocket('ws://localhost:8080');
JavaScript 設置
處理事件
WebSocket 對象提供了幾個事件處理器來處理連接的狀態(tài)變化:
- open:連接成功建立時觸發(fā)。
- message:接收到消息時觸發(fā)。
- error:發(fā)生錯誤時觸發(fā)。
- close:連接關閉時觸發(fā)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebSocket Example</title>
<script>
document.addEventListener('DOMContentLoaded', function () {
const socket = new WebSocket('ws://localhost:8080/websocket');
socket.onopen = function (event) {
console.log('WebSocket connection established.');
};
socket.onmessage = function (event) {
console.log('Received from server:', event.data);
};
socket.onclose = function (event) {
console.log('WebSocket connection closed.');
};
socket.onerror = function (error) {
console.error('WebSocket error:', error);
};
function sendMessage() {
let message = document.getElementById('message').value;
socket.send(message);
console.log('Sent message:', message);
}
});
</script>
</head>
<body>
<input type="text" id="message" placeholder="Type your message here">
<button onclick="sendMessage()">Send Message</button>
</body>
</html>
確保你的服務器端已正確配置,并且能夠接收來自客戶端的連接請求。
使用HTTPS和WSS(加密的WebSocket)可以提高安全性,特別是在生產環(huán)境中。
如果你的服務器部署在不同的域上,請確保服務器配置允許跨域訪問。
Java 服務端設置
導jar包
通過 maven 導入 spring boot 中 集成的 websocket jar 包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
創(chuàng)建WebSocket端點
@EnableWebSocket
@EnableWebSocket 是 Spring 框架中的一個注解,用于啟用 WebSocket 支持。當一個類被標記為此注解時,Spring 會自動配置必要的組件來處理 WebSocket 請求。這個注解通常應用在一個配置類上,該類負責設置 WebSocket 的處理邏輯。
registerWebSocketHandlers
- registerWebSocketHandlers 是 Spring WebSocket 框架中的一個重要方法,它用來注冊 WebSocket 處理器(WebSocketHandler)。這個方法是 WebSocketConfigurer 接口中定義的一個抽象方法,需要在你的配置類中實現(xiàn)。通過這個方法,你可以指定哪些路徑映射到特定的 WebSocket 處理器,并可以配置其他相關選項。
- addHandler 方法:接受兩個參數(shù),一個是 WebSocketHandler 的實例,另一個是 WebSocket 終結點的 URL 映射。
- setAllowedOrigins 方法:指定哪些源(域名)可以訪問你的 WebSocket 終結點。如果設置為 “*”,則表示任何源都可以訪問。
- withSockJS 方法:這是一個可選的配置項,用于啟用 SockJS,它是一種兼容性更好的 WebSocket 實現(xiàn),能夠在不支持原生 WebSocket 的瀏覽器上使用其他傳輸方式(如長輪詢)。
接下來,定義一個WebSocket處理器類,并配置一個端點來接受WebSocket連接:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
private final WebSocketHandler webSocketHandler;
public WebSocketConfig(WebSocketHandler webSocketHandler) {
this.webSocketHandler = webSocketHandler;
}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(webSocketHandler, "/websocket").setAllowedOrigins("*");
}
}
這里我們定義了一個WebSocket配置類,并注冊了WebSocket處理器。/websocket 是WebSocket的端點路徑。
實現(xiàn)WebSocket處理器
afterConnectionEstablished
void afterConnectionEstablished(WebSocketSession session) throws Exception;
- afterConnectionEstablished 是 WebSocketHandler 接口中定義的一個方法,它會在 WebSocket 連接成功建立之后被調用。這個方法為你提供了一個機會來執(zhí)行一些初始化操作,例如記錄連接信息、將連接加入到一個管理連接的集合中,或者發(fā)送初始消息給客戶端。
- WebSocketSession session —— 表示新建立的 WebSocket 會話。
- Exception —— 如果處理過程中出現(xiàn)任何異常,可以拋出
afterConnectionClosed
void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception;
- afterConnectionClosed 是 WebSocketHandler 接口中定義的一個方法,它會在 WebSocket 連接關閉時被調用。這個方法允許你在連接關閉后執(zhí)行一些清理操作,例如從會話管理器中移除會話、記錄關閉事件或者發(fā)送通知給其他客戶端。
- WebSocketSession session:表示已關閉的 WebSocket 會話。
- CloseStatus status:表示關閉狀態(tài)的原因。CloseStatus 是一個枚舉類型,提供了標準的關閉碼和關閉原因,例如 NORMAL_CLOSURE(正常關閉)、GOING_AWAY(離開)、PROTOCOL_ERROR(協(xié)議錯誤)等。
- 拋出:Exception —— 如果處理過程中出現(xiàn)任何異常,可以拋出。
handleTextMessage
void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception;
- handleTextMessage 是 WebSocketHandler 接口中定義的一個方法,用于處理從客戶端接收到的文本消息。當客戶端發(fā)送文本消息時,這個方法會被調用。對于二進制消息,則會調用 handleBinaryMessage 方法。
- WebSocketSession session:表示當前的 WebSocket 會話。
- TextMessage message:包含從客戶端接收到的文本消息。
- 拋出:Exception —— 如果處理過程中出現(xiàn)任何異常,可以拋出
- 現(xiàn)在我們需要實現(xiàn)一個WebSocket處理器類來處理連接事件:
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.util.concurrent.ConcurrentHashMap;
public class WebSocketHandler extends TextWebSocketHandler {
private static final ConcurrentHashMap<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
super.afterConnectionEstablished(session);
String id = session.getId();
sessions.put(id, session);
System.out.println("WebSocket connection established with session ID: " + id);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
super.afterConnectionClosed(session, status);
String id = session.getId();
sessions.remove(id);
System.out.println("WebSocket connection closed with session ID: " + id);
}
public void sendMessageToSession(String sessionId, String message) {
WebSocketSession session = sessions.get(sessionId);
if (session != null && session.isOpen()) {
try {
session.sendMessage(new TextMessage(message));
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void broadcastMessage(String message) {
for (WebSocketSession session : sessions.values()) {
if (session.isOpen()) {
try {
session.sendMessage(new TextMessage(message));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
現(xiàn)在我們可以使用WebSocketHandler類中的sendMessageToSession或broadcastMessage方法來發(fā)送數(shù)據(jù)給前端。
發(fā)送給特定會話:如果想要向特定的客戶端發(fā)送消息,可以使用sendMessageToSession方法。你需要知道客戶端的會話ID。
webSocketHandler.sendMessageToSession(sessionId, "Hello, client!");
廣播消息:如果你想向所有已連接的客戶端廣播消息,可以使用broadcastMessage方法
webSocketHandler.broadcastMessage("Hello, everyone!")
注銷WebSocket連接
要在Java后端注銷WebSocket連接,可以通過調用 WebSocketHandler 類中的 removeSession 方法來實現(xiàn)。例如,你可以從HTTP請求或其他服務中調用此方法:
@GetMapping("/logout/{sessionId}")
public ResponseEntity<String> logout(@PathVariable String sessionId) {
WebSocketHandler handler = new WebSocketHandler(); // 或者通過依賴注入獲取
handler.removeSession(sessionId);
return ResponseEntity.ok("Session " + sessionId + " has been closed.");
}
自己定義一個 固定id 方便使用
前端 JavaScript 代碼
- 創(chuàng)建WebSocket連接:在DOM加載完成后,創(chuàng)建一個WebSocket連接。
- 發(fā)送握手消息:在連接建立后,發(fā)送一個包含固定ID的握手消息。
- 處理接收到的消息:設置消息接收處理函數(shù),用于接收后端發(fā)送的數(shù)據(jù)。
后端 Java 代碼
- 配置WebSocket處理器:配置WebSocket處理器,注冊WebSocket路徑。
- 處理握手消息:接收前端發(fā)送的握手消息,并根據(jù)消息內容保存客戶端ID與WebSocket會話的映射。
- 發(fā)送消息:提供方法根據(jù)客戶端ID發(fā)送消息。
前端 javascript
<!DOCTYPE html>
<html l ang="en">
<head>
<meta charset="UTF-8">
<title>WebSocket Client Example</title>
</head>
<body>
<input type="text" id="messageInput" placeholder="Enter your message here">
<button id="sendButton">Send Message</button>
<div id="log"></div>
<script>
document.addEventListener('DOMContentLoaded', function () {
const socket = new WebSocket('ws://example.com/websocket');
socket.onopen = function (event) {
console.log('WebSocket connection established.');
// 固定的客戶端ID
const clientId = 'client-123';
// 發(fā)送握手消息
socket.send(JSON.stringify({
type: 'handshake',
clientId: clientId,
message: 'Hello, server!'
}));
};
socket.onmessage = function (event) {
console.log('Received from server:', event.data);
document.getElementById('log').textContent += 'Received from server: ' + event.data + '\n';
};
socket.onclose = function (event) {
console.log('WebSocket connection closed.');
document.getElementById('log').textContent += 'WebSocket connection closed.\n';
};
socket.onerror = function (error) {
console.error('WebSocket error:', error);
document.getElementById('log').textContent += 'WebSocket error: ' + error + '\n';
};
document.getElementById('sendButton').addEventListener('click', function () {
let message = document.getElementById('messageInput').value;
if (socket.readyState === WebSocket.OPEN) {
socket.send(message);
document.getElementById('log').textContent += 'Sent message: ' + message + '\n';
} else {
alert('WebSocket connection is not open.');
}
});
});
</script>
</body>
</html>
java 服務器端配置
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.utils.socket.HandshakeMessage;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class WebSocketHandler extends TextWebSocketHandler {
private static final Map<String, WebSocketSession> clientSessions = new ConcurrentHashMap<>();
private static final ObjectMapper objectMapper = new ObjectMapper();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
super.afterConnectionEstablished(session);
String sessionId = session.getId();
System.out.println("WebSocket connection established with session ID: " + sessionId);
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
HandshakeMessage handshakeMessage = objectMapper.readValue(payload, HandshakeMessage.class);
if ("handshake".equals(handshakeMessage.getType())) {
String clientId = handshakeMessage.getClientId();
String sessionId = session.getId();
// 存儲clientId與sessionId的映射關系
clientSessions.put(clientId, session);
// 可以選擇回復客戶端確認握手成功的消息
session.sendMessage(new TextMessage("Handshake successful"));
}
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
super.afterConnectionClosed(session, status);
String sessionId = session.getId();
System.out.println("WebSocket connection closed with session ID: " + sessionId);
// 移除會話
clientSessions.values().removeIf(s -> s.getId().equals(sessionId));
}
public void sendMessageToClient(String clientId, String message) {
WebSocketSession session = clientSessions.get(clientId);
if (session != null && session.isOpen()) {
try {
session.sendMessage(new TextMessage(message));
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 定義握手消息模型
private static class HandshakeMessage {
private String type;
private String clientId;
private String message;
// Getters and setters
}
}
總結
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
springmvc字符編碼過濾器CharacterEncodingFilter的使用
這篇文章主要介紹了springmvc字符編碼過濾器CharacterEncodingFilter的使用,具有很好的參考價值,希望對大家有所幫助。2021-08-08
Spring?Boot整合Zookeeper實現(xiàn)分布式鎖的場景分析
這篇文章主要介紹了Spring?Boot整合Zookeeper實現(xiàn)分布式鎖,zk實現(xiàn)分布式鎖完全是依靠zk節(jié)點類型當中的臨時序號節(jié)點來實現(xiàn)的,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下2022-06-06
springboot 使用poi進行數(shù)據(jù)的導出過程詳解
這篇文章主要介紹了springboot 使用poi進行數(shù)據(jù)的導出過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-09-09
詳解JFX11+IDEA跨平臺打包發(fā)布的完美解決辦法
這篇文章主要介紹了詳解JFX11+IDEA跨平臺打包發(fā)布的完美解決辦法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-06-06

