springboot結(jié)合websocket聊天室實(shí)現(xiàn)私聊+群聊
?? 先看效果
一人分飾多角(bushi)
?? 后端代碼
?? 先引入websocket依賴
<!-- websocket消息推送 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
???? 添加 WebSocketConfig 配置
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(); } }
?????? 實(shí)體bean接收客戶端發(fā)過來(lái)的信息
@Data public class SocketMsg { /** * 聊天類型 0 群聊 1 單聊 **/ private int type; /** * 發(fā)送者 **/ private String sendOutUser; /** * 接受者 **/ private String receiveUser; /** * 消息 **/ private String msg; }
???????? WebSocketUtil
import cn.hutool.json.JSONUtil; import org.springframework.stereotype.Component; import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; /** * WebSocket 連接測(cè)試 */ @Component @ServerEndpoint("/web-socket/{userName}") public class WebSocketUtil { private String userName; private Session session; /** 固定前綴 */ private static final String USER_NAME_PREFIX = "user_name_"; /** * 用來(lái)存放每個(gè)客戶端對(duì)應(yīng)的MyWebSocket對(duì)象。 **/ private static CopyOnWriteArraySet<WebSocketUtil> webSocketSet = new CopyOnWriteArraySet<>(); /** * 存放Session集合,方便推送消息 (javax.websocket.Session) */ private static ConcurrentHashMap<String, Session> sessionMap = new ConcurrentHashMap<>(); /** * 私聊:向指定客戶端推送消息 */ public synchronized static void privateMessage(SocketMsg socketMsg) { //接收消息的用戶 Session receiveUser = sessionMap.get(USER_NAME_PREFIX + socketMsg.getReceiveUser()); //發(fā)送給接收者 if(receiveUser != null){ //發(fā)送給接收者 System.out.println(socketMsg.getSendOutUser()+" 向 "+socketMsg.getReceiveUser()+" 發(fā)送了一條消息:"+socketMsg.getMsg()); receiveUser.getAsyncRemote().sendText(socketMsg.getSendOutUser()+":"+socketMsg.getMsg()); }else{ //發(fā)送消息的用戶 System.out.println(socketMsg.getSendOutUser()+" 私聊的用戶 "+socketMsg.getReceiveUser()+" 不在線或者輸入的用戶名不對(duì)"); Session sendOutUser = sessionMap.get(USER_NAME_PREFIX + socketMsg.getSendOutUser()); //將系統(tǒng)提示推送給發(fā)送者 sendOutUser.getAsyncRemote().sendText("系統(tǒng)消息:對(duì)方不在線或者您輸入的用戶名不對(duì)"); } } /** * 群聊:公開聊天記錄 * @param userName 發(fā)送者的用戶名稱(當(dāng)前用戶) * @param message 發(fā)送的消息 * @param flag 用來(lái)標(biāo)識(shí) 是否要將消息推送給 當(dāng)前用戶 */ public synchronized static void publicMessage(String userName,String message,boolean flag) { for (WebSocketUtil item : webSocketSet) { Session session = item.session; if (flag){ session.getAsyncRemote().sendText(message); }else { //獲取發(fā)送這條消息的用戶 Session currentUser = sessionMap.get(USER_NAME_PREFIX + userName); //消息不用推送到發(fā)送者的客戶端 if (!session.getId().equals(currentUser.getId())){ session.getAsyncRemote().sendText(message); } } } System.out.println("公共頻道接收了一條消息:"+message); } /** * 監(jiān)聽:連接成功 * @param session * @param userName 連接的用戶名 */ @OnOpen public void onOpen(Session session, @PathParam("userName") String userName) { this.userName = userName; this.session = session; sessionMap.put(USER_NAME_PREFIX + userName, session); webSocketSet.add(this); //在線數(shù)加1 String tips = userName+" 加入聊天室。當(dāng)前聊天室人數(shù)為" + webSocketSet.size(); System.out.println(tips); publicMessage(userName,tips,true); } /** * 監(jiān)聽:收到客戶端發(fā)送的消息 * @param message 發(fā)送的信息(json格式,里面是 SocketMsg 的信息) */ @OnMessage public void onMessage(String message) { if (JSONUtil.isTypeJSONObject(message)) { SocketMsg socketMsg = JSONUtil.toBean(message, SocketMsg.class); if(socketMsg.getType() == 1){ //單聊,需要找到發(fā)送者和接受者 privateMessage(socketMsg); }else{ //群發(fā)消息 publicMessage(socketMsg.getSendOutUser(),socketMsg.getSendOutUser()+": "+socketMsg.getMsg(),false); } } } /** * 監(jiān)聽: 連接關(guān)閉 */ @OnClose public void onClose() { if (sessionMap.containsKey(USER_NAME_PREFIX + userName)) { //連接關(guān)閉后,將此websocket從set中刪除 sessionMap.remove(USER_NAME_PREFIX + userName); webSocketSet.remove(this); } String tips = userName+" 退出聊天室。當(dāng)前聊天室人數(shù)為" + webSocketSet.size(); System.out.println(tips); publicMessage(userName,tips,true); } /** * 監(jiān)聽:發(fā)生異常 * @param error */ @OnError public void onError(Throwable error) { System.out.println("userName為:" + userName + ",發(fā)生錯(cuò)誤:" + error.getMessage()); error.printStackTrace(); } }
?? 前端代碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>聊天室</title> <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> <style type="text/css"> input{ width: 150px; height: 30px; line-height: 25px; padding: 5px 10px; border-radius: 5px; border: 2px solid; font-size: 16px; } #msg{ width: 300px; } button{ width: 80px; height: 44px; padding: 5px 20px; border-radius: 5px; } </style> </head> <body> 聊天室<br/><br/> <input type="text" id="sendOutUser" placeholder="自己的用戶名"> <button onclick="connectWebSocket()">上線</button> <button onclick="closeWebSocket()">下線</button> <br/><br> <input type="text" id="msg" placeholder="要發(fā)送的信息"/> <input type="text" id="receiveUser" placeholder="接收人的用戶名"/> <button onclick="send()">發(fā)送</button> <br><br> <hr> <div id="msgList"></div> <script type="text/javascript"> var websocket = null; //連接WebSocket function connectWebSocket() { var sendOutUser = document.getElementById("sendOutUser").value; if (sendOutUser === "") { alert("請(qǐng)輸入用戶名"); return; } //判斷當(dāng)前瀏覽器是否支持websocket if ('WebSocket' in window) { websocket = new WebSocket("ws://localhost:7070/web-socket/"+document.getElementById("sendOutUser").value); } else { alert('當(dāng)前瀏覽器 not support websocket') } //連接發(fā)生錯(cuò)誤的回調(diào)方法 websocket.onerror = function () { alert("連接發(fā)生錯(cuò)誤"); }; //連接成功建立的回調(diào)方法 websocket.onopen = function () { var sendOutUser = document.getElementById("sendOutUser") sendOutUser.readOnly = true sendOutUser.style.backgroundColor='#ddd' } //接收到消息的回調(diào)方法 websocket.onmessage = function (event) { console.log(event.data) innerdiv("",event.data) } //連接關(guān)閉的回調(diào)方法 websocket.onclose = function () { innerdiv("","websocket連接關(guān)閉"); } //監(jiān)聽窗口關(guān)閉事件,當(dāng)窗口關(guān)閉時(shí),主動(dòng)去關(guān)閉websocket連接,防止連接還沒斷開就關(guān)閉窗口,server端會(huì)拋異常。 window.onbeforeunload = function () { closewebsocket(); } } //關(guān)閉連接 function closeWebSocket() { websocket.close(); } //發(fā)送消息 function send() { var m = new Map(); // 空Map var sendOutId = document.getElementById("sendOutUser") //發(fā)送者 var msg = document.getElementById("msg").value //發(fā)送消息 if (msg === "") { alert("請(qǐng)輸入消息"); return; } var receiveUser = document.getElementById("receiveUser").value //接收者 m.set("sendOutUser",sendOutUser.value); m.set("msg",msg) // 接收者為空時(shí),type為群聊,否則為私聊 if (receiveUser === "") { m.set("type",0) }else{ m.set("receiveUser",receiveUser) m.set("type",1) } json = mapToJson(m) websocket.send(json) innerdiv("我",msg) } //map轉(zhuǎn)換為json function mapToJson(map) { var obj= Object.create(null); for (var[k,v] of map) { obj[k] = v; } return JSON.stringify(obj); } //顯示聊天記錄到頁(yè)面 function innerdiv(id,txt){ var msgList = document.getElementById("msgList") if (id === "") { msgList.innerHTML += "<div>" + txt + "</div><br>" }else{ msgList.innerHTML += "<div>"+ id +": "+txt+ "</div><br>" } } </script> </body> </html>
到此這篇關(guān)于springboot結(jié)合websocket聊天室實(shí)現(xiàn)私聊+群聊的文章就介紹到這了,更多相關(guān)springboot websocket聊天室內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot整合websocket實(shí)現(xiàn)即時(shí)通信聊天
- SpringBoot+WebSocket實(shí)現(xiàn)多人在線聊天案例實(shí)例
- SpringBoot中webSocket實(shí)現(xiàn)即時(shí)聊天
- Springboot+WebSocket實(shí)現(xiàn)一對(duì)一聊天和公告的示例代碼
- Springboot基于websocket實(shí)現(xiàn)簡(jiǎn)單在線聊天功能
- SpringBoot+WebSocket搭建簡(jiǎn)單的多人聊天系統(tǒng)
- SpringBoot+Websocket實(shí)現(xiàn)一個(gè)簡(jiǎn)單的網(wǎng)頁(yè)聊天功能代碼
- SpringBoot結(jié)合WebSocket實(shí)現(xiàn)聊天功能
相關(guān)文章
SpringBoot最簡(jiǎn)潔的國(guó)際化配置
這篇文章主要介紹了SpringBoot最簡(jiǎn)潔的國(guó)際化配置,Spring Boot是一個(gè)用于構(gòu)建獨(dú)立的、生產(chǎn)級(jí)別的Spring應(yīng)用程序的框架,國(guó)際化是一個(gè)重要的功能,它允許應(yīng)用程序根據(jù)用戶的語(yǔ)言和地區(qū)顯示不同的內(nèi)容,在Spring Boot中,實(shí)現(xiàn)國(guó)際化非常簡(jiǎn)單,需要的朋友可以參考下2023-10-10springboot讀取application.yml報(bào)錯(cuò)問題及解決
這篇文章主要介紹了springboot讀取application.yml報(bào)錯(cuò)問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06pdf2swf+flexpapers實(shí)現(xiàn)類似百度文庫(kù)pdf在線閱讀
這篇文章主要介紹了pdf2swf+flexpapers實(shí)現(xiàn)類似百度文庫(kù)pdf在線閱讀的相關(guān)資料,需要的朋友可以參考下2014-10-10Java以編程方式實(shí)現(xiàn)JAR文件的創(chuàng)建
在這篇文章中,我們將為大家詳細(xì)介紹一下利用Java語(yǔ)言以編程方式創(chuàng)建jar文件的過程。文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-07-07