您好,登錄后才能下訂單哦!
這篇文章運用簡單易懂的例子給大家介紹SpringBoot實現(xiàn)添加WebSocket的方法,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
一、WebSocket介紹
網(wǎng)站上的即時通訊是很常見的,比如網(wǎng)頁的QQ,聊天系統(tǒng)等。按照以往的技術(shù)能力通常是采用輪詢、Comet技術(shù)解決。
HTTP協(xié)議是非持久化的,單向的網(wǎng)絡(luò)協(xié)議,在建立連接后只允許瀏覽器向服務(wù)器發(fā)出請求后,服務(wù)器才能返回相應(yīng)的數(shù)據(jù)。當(dāng)需要即時通訊時,通過輪詢在特定的時間間隔(如1秒),由瀏覽器向服務(wù)器發(fā)送Request請求,然后將最新的數(shù)據(jù)返回給瀏覽器。這樣的方法最明顯的缺點就是需要不斷的發(fā)送請求,而且通常HTTP request的Header是非常長的,為了傳輸一個很小的數(shù)據(jù) 需要付出巨大的代價,是很不合算的,占用了很多的寬帶。
缺點:會導(dǎo)致過多不必要的請求,浪費流量和服務(wù)器資源,每一次請求、應(yīng)答,都浪費了一定流量在相同的頭部信息上
然而WebSocket的出現(xiàn)可以彌補這一缺點。在WebSocket中,只需要服務(wù)器和瀏覽器通過HTTP協(xié)議進(jìn)行一個握手的動作,然后單獨建立一條TCP的通信通道進(jìn)行數(shù)據(jù)的傳送。
二、WebSocket運行機制
WebSocket 是 HTML5 一種新的協(xié)議,也是一個典型的應(yīng)用層協(xié)議。它實現(xiàn)了瀏覽器與服務(wù)器全雙工通信,能更好的節(jié)省服務(wù)器資源和帶寬并達(dá)到實時通訊,它建立在 TCP 之上,同 HTTP 一樣通過 TCP 來傳輸數(shù)據(jù),但是它和 HTTP 最大不同是:
WebSocket 是一種雙向通信協(xié)議,在建立連接后,WebSocket 服務(wù)器和 Browser/Client Agent 都能主動的向?qū)Ψ桨l(fā)送或接收數(shù)據(jù),就像 Socket 一樣;
WebSocket 需要類似 TCP 的客戶端和服務(wù)器端通過握手連接,連接成功后才能相互通信。
非 WebSocket 模式傳統(tǒng) HTTP 客戶端與服務(wù)器的交互如下圖所示:
使用 WebSocket 模式客戶端與服務(wù)器的交互如下圖:
三、WebSocket實現(xiàn)
這里通過一個簡單的聊天例程,實現(xiàn)spring boot +websocket代碼的演示。
引入maven
<!-- websocket --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> <version>2.3.4.RELEASE</version> </dependency>
配置類WebConfig
package org.antry.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter; /** * @ClassName WebSocketConfig * @Description TODO * @Autor TT * @Date 2020/10/9 23:00 * @Version 1.0 */ @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
WebSocket類
在這個類里,有一個集合,用來存放所有連接。
當(dāng)有新的連接進(jìn)來時,在onOpen()方法中,我們每個連接都會存下對應(yīng)id作為標(biāo)識。假設(shè)這個id已經(jīng)存過,則會關(guān)閉此連接,防止同一個id多處登錄。
連接斷開時,在onClose()方法中,將此連接移出集合。
當(dāng)有新的消息發(fā)送過來時,會去遍歷連接,找到對應(yīng)接收人id的連接,然后把消息推送給接收人。
package org.antry.websocket; import org.springframework.stereotype.Component; import javax.websocket.OnClose; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; /** * @ClassName MyWebsocket * @Description TODO * @Autor TT * @Date 2020/10/10 11:02 * @Version 1.0 */ @ServerEndpoint(value = "/websocket/{user}") @Component public class MyWebsocket { // 通過類似GET請求方式傳遞參數(shù)的方法(服務(wù)端采用第二種方法"WebSocketHandler"實現(xiàn)) // websocket = new WebSocket("ws://127.0.0.1:18080/testWebsocket?id=23&name=Lebron"); /** * 在線人數(shù) */ public static AtomicInteger onlineNumber = new AtomicInteger(0); /** * 所有的對象,每次連接建立,都會將我們自己定義的MyWebsocket存放到List中, */ public static List<MyWebsocket> webSockets = new CopyOnWriteArrayList<MyWebsocket>(); /** * 會話,與某個客戶端的連接會話,需要通過它來給客戶端發(fā)送數(shù)據(jù) */ private Session session; /** * 每個會話的用戶 */ private String user; /** * 建立連接 * * @param session */ @OnOpen public void onOpen(Session session, @PathParam("user") String user) { System.err.println(user); if (user == null || "".equals(user)) { try { session.close(); } catch (IOException e) { e.printStackTrace(); } return; } onlineNumber.incrementAndGet(); for (MyWebsocket MyWebsocket : webSockets) { if (user.equals(MyWebsocket.user)) { try { session.close(); } catch (IOException e) { e.printStackTrace(); } return; } } this.session = session; this.user = user; webSockets.add(this); } /** * 連接關(guān)閉 */ @OnClose public void onClose() { onlineNumber.decrementAndGet(); webSockets.remove(this); } /** * 收到客戶端的消息 * * @param message 消息 * @param session 會話 */ @OnMessage public void onMessage(String message, Session session, @PathParam("user") String user) { System.err.println(message); String[] strArr = message.split("~"); pushMessage(user,strArr[0],strArr[1]); } /** * 發(fā)送消息 * * @param message 消息 */ public void sendMessage(String message) { try { session.getBasicRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); } } /** * 消息推送 * * @param message * @param uuid uuid為空則推送全部人員 */ public static void pushMessage(String user, String message, String uuid) { if (uuid == null || "".equals(uuid)) { for (MyWebsocket MyWebsocket : webSockets) { MyWebsocket.sendMessage(user + ":" + message); } } else { for (MyWebsocket MyWebsocket : webSockets) { if (uuid.equals(MyWebsocket.user)) { MyWebsocket.sendMessage(message); } } } } }
兩個簡單的前端頁面,他們的不同是,接收id和發(fā)送id不同。
testOne.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>聊天窗口1</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link href="public/dist/lib/uploader/zui.uploader.min.css" rel="external nofollow" rel="external nofollow" rel="stylesheet"> </head> <body> <div> <div class="input-group"> <input type="text" class="form-control" id="msg"> <span class="input-group-btn"> <button class="btn btn-default" type="button" onclick="send()">發(fā)送</button> </span> </div> </div> <script src="public/dist/lib/jquery/jquery.js"></script> <script src="public/dist/js/zui.min.js"></script> <script src="public/layer/layer.js"></script> <script src="public/js/function.js"></script> <script src="public/js/testOne.js"></script> </body> </html>
testOne.js
var websocket = null; var sendId = 0; var receiveId = 1; //--------------------------- /** * 初始化websocket * @param id */ doInit(sendId) function doInit(sendId){ if ('WebSocket' in window) { websocket = new WebSocket("ws:localhost:10086/websocket/" + sendId); } else { alert("瀏覽器不支持"); } websocket.onopen = function () { addMessage("webscoket已經(jīng)連接成功"); }; websocket.onclose = function () { addMessage("webscoket連接失敗"); }; websocket.onmessage = function (event) { alert("收到消息:"+event.data); }; websocket.onerror = function () { addMessage("webscoket連接失敗"); }; } /** * 發(fā)送一條消息 */ function send(){ websocket.send(value('msg')+"~"+receiveId); } /** * 測試打印調(diào)試信息用 * @param msg */ function addMessage(msg) { console.log(msg) }
testTwo.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>聊天窗口2</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link href="public/dist/lib/uploader/zui.uploader.min.css" rel="external nofollow" rel="external nofollow" rel="stylesheet"> </head> <body> <div> <div class="input-group"> <input type="text" class="form-control" id="msg"> <span class="input-group-btn"> <button class="btn btn-default" type="button" onclick="send()">發(fā)送</button> </span> </div> </div> <script src="public/dist/lib/jquery/jquery.js"></script> <script src="public/dist/js/zui.min.js"></script> <script src="public/layer/layer.js"></script> <script src="public/js/function.js"></script> <script src="public/js/testTwo.js"></script> </body> </html>
testTwo.js
var websocket = null; var sendId = 1; var receiveId = 0; //--------------------------- /** * 初始化websocket * @param id */ doInit(sendId) function doInit(receiveId){ if ('WebSocket' in window) { websocket = new WebSocket("ws:localhost:10086/websocket/" + sendId); } else { alert("瀏覽器不支持"); } websocket.onopen = function () { addMessage("webscoket已經(jīng)連接成功"); }; websocket.onclose = function () { addMessage("webscoket連接失敗"); }; websocket.onmessage = function (event) { alert("收到消息:"+event.data); }; websocket.onerror = function () { addMessage("webscoket連接失敗"); }; } /** * 發(fā)送一條消息 */ function send(){ websocket.send(value('msg')+"~"+receiveId); } /** * 測試打印調(diào)試信息用 * @param msg */ function addMessage(msg) { console.log(msg) }
分別用兩個瀏覽器,打開這兩個頁面進(jìn)行訪問。結(jié)果如下
關(guān)于SpringBoot實現(xiàn)添加WebSocket的方法就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。