SpringBoot2 整合 WebSocket 簡單實現聊天室功能
一個很簡單的 Demo,可以用 WebSocket 實現簡易的聊天室功能
個人部落格 : DoubleFJ の Blog
一反常態,我們先來看一下效果,如下:
嫌麻煩的可以直接去我的 GitHub 獲取完整無碼 Demo。
概述
- WebSocket 是什麼?
WebSocket 是一種網路通訊協議。RFC6455 定義了它的通訊標準。
WebSocket 是 HTML5 開始提供的一種在單個 TCP 連線上進行全雙工通訊的協議。
- 為什麼需要 WebSocket ?
瞭解計算機網路協議的人,應該都知道:HTTP 協議是一種無狀態的、無連線的、單向的應用層協議。它採用了請求/響應模型。通訊請求只能由客戶端發起,服務端對請求做出應答處理。
這種通訊模型有一個弊端:HTTP 協議無法實現伺服器主動向客戶端發起訊息。
這種單向請求的特點,註定瞭如果伺服器有連續的狀態變化,客戶端要獲知就非常麻煩。大多數 Web 應用程式將通過頻繁的非同步 JavaScript 和 XML(AJAX)請求實現長輪詢。輪詢的效率低,非常浪費資源(因為必須不停連線,或者 HTTP 連線始終開啟)。
- WebSocket 如何工作?
Web瀏覽器和伺服器都必須實現 WebSockets 協議來建立和維護連線。由於 WebSockets 連線長期存在,與典型的 HTTP 連線不同,對伺服器有重要的影響。
基於多執行緒或多程式的伺服器無法適用於 WebSockets,因為它旨在開啟連線,儘可能快地處理請求,然後關閉連線。任何實際的 WebSockets 伺服器端實現都需要一個非同步伺服器。
實現
首先去 start.spring.io 快速下載一個 springboot Demo,記得選中 Websocket
依賴。
然後將專案匯入你的 IDE 中。
新建一個 config 類用來註冊我們的 websocket bean。
我的是 WebSocketConfig.java
:
@Configuration
public class WebSocketConfig {
/**
* 自動註冊使用了@ServerEndpoint註解宣告的Websocket endpoint
*
* @return
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
該加上的註解別忘了加,專案啟動時 springboot 會自動去掃描註解的類。
然後是訊息接收處理 websocket 連線、關閉等鉤子。
MyWebSocket.java
:
@ServerEndpoint(value = "/websocket")
@Component
public class MyWebSocket {
// 靜態變數,用來記錄當前線上連線數。應該把它設計成執行緒安全的。
private static int onlineCount = 0;
// concurrent包的執行緒安全Set,用來存放每個客戶端對應的MyWebSocket物件。
private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();
// 與某個客戶端的連線會話,需要通過它來給客戶端傳送資料
private Session session;
/**
* 連線建立成功呼叫的方法
*/
@OnOpen
public void onOpen(Session session) {
this.session = session;
webSocketSet.add(this); // 加入set中
addOnlineCount(); // 線上數加1
System.out.println("有新連線加入!當前線上人數為 : " + getOnlineCount());
try {
sendMessage("您已成功連線!");
} catch (IOException e) {
System.out.println("IO異常");
}
}
/**
* 連線關閉呼叫的方法
*/
@OnClose
public void onClose() {
webSocketSet.remove(this); // 從set中刪除
subOnlineCount(); // 線上數減1
System.out.println("有一連線關閉!當前線上人數為 : " + getOnlineCount());
}
/**
* 收到客戶端訊息後呼叫的方法
*
* @param message
* 客戶端傳送過來的訊息
*/
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("來自客戶端的訊息:" + message);
// 群發訊息
for (MyWebSocket item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 發生錯誤時呼叫
*/
@OnError
public void onError(Session session, Throwable error) {
System.out.println("發生錯誤");
error.printStackTrace();
}
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
// this.session.getAsyncRemote().sendText(message);
}
/**
* 群發自定義訊息
*/
public static void sendInfo(String message) throws IOException {
for (MyWebSocket item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
continue;
}
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
MyWebSocket.onlineCount++;
}
public static synchronized void subOnlineCount() {
MyWebSocket.onlineCount--;
}
}
關鍵就是@OnOpen
、@OnClose
等這幾個註解了。每個物件有著各自的 session,其中可以存放個人資訊。當收到一個客戶端訊息時,往所有維護著的物件迴圈 send 了訊息,這就簡單實現了聊天室的聊天功能了。
其中 websocket session 傳送文字訊息有兩個方法:getAsyncRemote()和 getBasicRemote()。 getAsyncRemote 是非阻塞式的,getBasicRemote 是阻塞式的。
然後我用了 Controller 來簡單跳轉測試頁面,也可以直接訪問頁面。
InitController.java
:
@Controller
public class InitController {
@RequestMapping("/websocket")
public String init() {
return "websocket.html";
}
}
websocket.html
:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>My WebSocket Test</title>
</head>
<body>
Welcome<br/>
<input id="text" type="text" />
<button onclick="send()">Send</button>
<button onclick="closeWebSocket()">Close</button>
<div id="message">
</div>
</body>
<script type="text/javascript">
var websocket = null;
//判斷當前瀏覽器是否支援WebSocket
if('WebSocket' in window){
websocket = new WebSocket("ws://localhost:8080/websocket");
}
else{
alert('Not support websocket')
}
//連線發生錯誤的回撥方法
websocket.onerror = function(){
setMessageInnerHTML("error");
};
//連線成功建立的回撥方法
websocket.onopen = function(event){
setMessageInnerHTML("open");
}
//接收到訊息的回撥方法
websocket.onmessage = function(event){
setMessageInnerHTML(event.data);
}
//連線關閉的回撥方法
websocket.onclose = function(){
setMessageInnerHTML("close");
}
//監聽視窗關閉事件,當視窗關閉時,主動去關閉websocket連線,防止連線還沒斷開就關閉視窗,server端會拋異常。
window.onbeforeunload = function(){
websocket.close();
}
//將訊息顯示在網頁上
function setMessageInnerHTML(innerHTML){
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
//關閉連線
function closeWebSocket(){
websocket.close();
}
//傳送訊息
function send(){
var message = document.getElementById('text').value;
websocket.send(message);
}
</script>
</html>
要注意,這裡沒有用到任何模板引擎,所有直接把 websocket.html
放在 static 資料夾下就可以訪問了。
所有的這些搞好就可以執行了,一個簡單的效果就能出來。
End.
參考
相關文章
- SpringBoot 實戰 (十七) | 整合 WebSocket 實現聊天室Spring BootWeb
- 用node實現一個簡單的聊天室——websocket實踐Web
- 基於websocket與nodejs-websocket的簡單聊天室WebNodeJS
- 用Java程式碼實現一個簡單的聊天室功能Java
- springboot2整合websocket,實現服務端推送訊息到客戶端Spring BootWeb服務端客戶端
- gin websocket 簡單分散式實現Web分散式
- Websocket 直播間聊天室教程 - GoEasy 快速實現聊天室WebGo
- uniapp專案實踐總結(十五)使用websocket實現簡易聊天室APPWeb
- websocket+node實現一個最簡單的即時通訊功能Web
- 用Java構建一個簡單的WebSocket聊天室JavaWeb
- 聊天室原始碼開發,如何簡單的實現掃碼登入功能?原始碼
- WinForm的Socket實現簡單的聊天室 IMORM
- C# WebSocket的簡單使用【使用Fleck實現】C#Web
- Node.js+websocket+mongodb實現即時聊天室Node.jsWebMongoDB
- 使用WebSocket實現一個簡單的頁面聊天Web
- 用 hyperf websocket 實現,類似 qq 單機登入功能Web
- Go使用websocket實現彈幕功能GoWeb
- 用node實現一個簡單的聊天室—— 升級版
- 重構 JAVA 聊天室 —— CS 模式的簡單架構實現Java模式架構
- 簡單聊聊WebSocketWeb
- 超簡單整合HMS ML Kit 實現parental control
- SpringBoot整合MongoDB(實現一個簡單快取)Spring BootMongoDB快取
- 超簡單實現iOS列表的索引功能iOS索引
- android 簡單實現指紋識別功能Android
- Java Web簡單登陸功能的實現JavaWeb
- Vue實現簡單的購物車功能Vue
- 基於 WebSocket 的 PPT 遠端控制器簡單實現Web
- netty無縫切換rabbitmq、activemq、rocketmq實現聊天室單聊、群聊功能NettyMQ
- 透過websocket,實現遊戲陪玩系統的聊天室Web遊戲
- Spring Boot系列十六 WebSocket簡介和spring boot整合簡單訊息代理Spring BootWeb
- WebSocket 簡單瞭解Web
- 簡單的websocket demoWeb
- Netty版本 簡單聊天室Netty
- 簡單寫個聊天室
- 超簡單整合ML kit 實現聽寫單詞播報
- 聊天室原始碼開發中防抖節流的簡單實現原始碼
- JSP(ajax)+Servlet實現簡單的登入功能JSServlet
- 如何實現簡單的分散式鏈路功能?分散式