使用springboot整合websocket實(shí)現(xiàn)群聊教程
先上效果圖:
相對(duì)來說更好看那么一點(diǎn)但是,實(shí)現(xiàn)代碼都是一樣的。
先來準(zhǔn)備工作導(dǎo)入依賴
<!--websocket依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
其實(shí)springboot已經(jīng)內(nèi)置了,直接在主函數(shù)啟動(dòng)就行。但我們這次就講這個(gè)。
導(dǎo)入依賴后掃描啟用
package com.nx.study.springstudy.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Configuration public class WS { @Bean public ServerEndpointExporter serverEndpointExporter(){ return new ServerEndpointExporter(); } }
**@ServerEndpoint("/websocket/{username}")**
接收前端傳回?cái)?shù)據(jù)
@Component啟用
package com.nx.study.springstudy.bean; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import net.sf.json.JSONObject; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestParam; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; @ServerEndpoint("/websocket/{username}") @Component public class Myws { private static Map<String, Myws> webSocketSet = new ConcurrentHashMap<String, Myws>(); private static Map<String, Session> map = new HashMap<String, Session>(); private static List<String> namelist = new ArrayList<String>(); private static JSONObject jsonObject = new JSONObject(); private static JSONObject jsonObject2 = new JSONObject(); private static List<String> nm_msg = new ArrayList<String>(); private SocketMsg socketMsg; private Session session; private String name; @OnOpen public void onpen(Session session, @PathParam(value = "username") String username){ if(username == null){ username = "游客"; } this.session = session; // this.name = "南" + getname(); this.name = username; webSocketSet.put(name, this); map.put(username, session); namelist.clear(); // 清空原來的信息 setonlion(); jsonObject.put("onlinepp", namelist); String message = jsonObject.toString(); broadcast2(message); } @OnClose public void onclose(){ webSocketSet.remove(this.name); // 移除對(duì)象 namelist.clear(); setonlion(); jsonObject.clear(); jsonObject.put("onlinepp", namelist); String message = jsonObject.toString(); broadcast3(message); } @OnMessage public void onmessage(String message){ nm_msg.clear(); jsonObject2.clear(); nm_msg.add(name); nm_msg.add(message); jsonObject2.put("chat", nm_msg); String message2 = jsonObject2.toString(); broadcast(message2); } @OnError public void onError(Session session, Throwable error) { System.out.println("發(fā)生錯(cuò)誤"); error.printStackTrace(); } public void broadcast(String message){ for (Map.Entry<String, Myws> item : webSocketSet.entrySet()){ item.getValue().session.getAsyncRemote().sendText(message); } } public void broadcast2(String message){ for (Map.Entry<String, Myws> item : webSocketSet.entrySet()){ item.getValue().session.getAsyncRemote().sendText(message); } } public void broadcast3(String message){ for (Map.Entry<String, Myws> item : webSocketSet.entrySet()){ if (!item.getKey().equals(name)){ item.getValue().session.getAsyncRemote().sendText(message); } } } public void setonlion(){ for (Map.Entry<String, Myws> item : webSocketSet.entrySet()){ namelist.add(item.getKey()); } } public String getname() { String linkNo = ""; // 用字符數(shù)組的方式隨機(jī) String model = "小大天明畫美麗豪子余多少浩然兄弟朋友美韻紫萱好人壞蛋誤解不要停棲棲遑遑可"; char[] m = model.toCharArray(); for (int j = 0; j < 2; j++) { char c = m[(int) (Math.random() * 36)]; // 保證六位隨機(jī)數(shù)之間沒有重復(fù)的 if (linkNo.contains(String.valueOf(c))) { j--; continue; } linkNo = linkNo + c; } return linkNo; } }
其中重點(diǎn)就是4個(gè)注解
**@OnOpen,@OnClose,@OnMessage,@OnError**
- @OnOpen–>客戶端打開鏈接時(shí)候觸發(fā)執(zhí)行
- @OnClose–>客戶端關(guān)閉鏈接觸發(fā)執(zhí)行
- @OnMessage–>客戶端發(fā)送信息觸發(fā)執(zhí)行
- @OnError–>發(fā)送錯(cuò)誤時(shí)候觸發(fā)執(zhí)行
對(duì)象信息都儲(chǔ)存在Session,可以仔細(xì)看看上面代碼很好理解。
我們只需要理解這4個(gè)注解的作用就可以!
前端頁面代碼
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <link rel="icon" type="image/x-icon" th:href="@{/img/user/head/favicon.ico}" /> <script th:src="@{webjars/jquery/3.1.1/jquery.min.js}"></script> <script th:src="@{webjars/bootstrap/3.3.7/js/bootstrap.min.js}"></script> <link rel="stylesheet" th:href="@{webjars/bootstrap/3.3.7/css/bootstrap.min.css}" /> <link th:href="@{/css/home.css}" rel="stylesheet" type="text/css" /> <meta charset="UTF-8"> <title>在線聊天室</title> </head> <body> <div class="container-fluid"> <div style="width: 100%;height: 100px;text-align: center;margin-bottom: 30px;color: #495e6a;box-shadow: 0px 0px 10px #000000"> <br> <h1>文明用語,快樂你我他</h1> </div> <div style="width: 800px;height: 600px;margin: auto;background-color: #dce9f6;box-shadow: 0px 0px 10px #707074;display: flex"> <div style="width: 200px;height: 600px;background-color: #d4d1d1"> <div style="width: 160px;height: 40px;margin: auto;margin-top: 10px;background-color: #fdffff;text-align: center;box-shadow: 0px 0px 10px #474749;border-radius: 4px"> <span class="glyphicon glyphicon-globe" style="font-size: 30px;padding-top: 2px;padding-bottom: 2px"></span> <span style="font-size: 30px">群聊</span> </div> <div style="width: 160px;height: 40px;margin: auto;margin-top: 10px;background-color: #fdffff;text-align: center;box-shadow: 0px 0px 10px #474749;border-radius: 4px"> <span class="glyphicon glyphicon-star" style="font-size: 30px;padding-top: 2px;padding-bottom: 2px"></span> <span style="font-size: 30px" th:text="${Springuser.username}">游客</span> </div> <hr> <div id="online" style="width: 200px;height: 500px;word-break: break-word;overflow: auto"> </div> </div> <div style="width: 600px;height: 600px"> <div style="width: 600px;height: 500px;padding: 20px 20px 20px 20px;word-break: break-word;overflow: auto" id="message"> </div> <div style="width: 600px;height: 100px;background-color: #ddf1d7;display: flex"> <div style="width: 100px;height: 100px;text-align: center;background-color: #f5d2d2"> <button id="btn1" class="btn btn-success" style="margin-top: 5px">連接上線</button><br> <br> <button id="btn2" class="btn btn-danger">下線</button> </div> <div style="width: 500px;height: 100px;padding: 10px 10px 10px 10px" class="input-group"> <input id="msg" type="text" class="form-control" placeholder="在這里輸入想說的話吧!" /><br> <button id="btn3" class="btn btn-info" style="margin-top: 10px;float: right">發(fā)送消息</button> </div> </div> </div> </div> <div class="div2" style="margin-top: 30px;background-color: #ffffff"> <br><br> <a href="#"><span style="color: #000000;">關(guān)于我們</span></a> | <a href="mailto: 2251798294@qq.com" style="color: #000000;">找我合作</a><br> <a style="color: #202223;">贛ICP備2021004042號(hào)</a> </div> </div> </body> <script th:inline="javascript" language='javascript'> $(document).ready(function(){ var select; var message = ""; var fromuser = ""; var touser = ""; var type = 0; var username = [[${Springuser.username}]]; var websocket = null; $("#btn1").click(function(){ //判斷當(dāng)前瀏覽器是否支持WebSocket if(select === 1){ alert("你已連接上線路,無需重復(fù)連接!") }else { if ('WebSocket'in window) { websocket = new WebSocket("ws://wenhaosuper.top:8000/websocket/" + username); alert("歡迎-->" + username + "<--成功上線!"); select = 1; } else { alert('Not support websocket') } } //連接發(fā)生錯(cuò)誤的回調(diào)方法 websocket.onerror = function() { alert("錯(cuò)誤"); }; //連接成功建立的回調(diào)方法 websocket.onopen = function() { } //接收到消息的回調(diào)方法 websocket.onmessage = function(event) { var msg = event.data var obj = JSON.parse(msg); var zxname = obj.onlinepp; var chat = obj.chat; if (zxname != null){ onlinename(zxname); } if (chat != null){ setchat(chat); } } //連接關(guān)閉的回調(diào)方法 websocket.onclose = function() { alert("離開"); select = 2; $("#online").empty(); } //監(jiān)聽窗口關(guān)閉事件,當(dāng)窗口關(guān)閉時(shí),主動(dòng)去關(guān)閉websocket連接,防止連接還沒斷開就關(guān)閉窗口,server端會(huì)拋異常。 window.onbeforeunload = function() { websocket.onclose; websocket.close(); } }); //將消息顯示在網(wǎng)頁上 function setchat(message) { $("<div style=\"width: 560px;min-height: 40px;display: flex;margin-bottom: 20px\">\n" + " <div style=\"width: 40px;height: 40px;background-color: #ffffff;text-align: center;border-radius: 20px\">\n" + " <span style=\"font-size: 28px;margin-top: 9px\"><strong>N</strong></span>\n" + " </div>\n" + " <div style=\"min-height: 40px;margin-left: 10px\">\n" + " <div style=\"height: 18px\">\n" + " <span style=\"color: #7f7777;font-size: 14px\">"+message[0]+"</span>\n" + " </div>\n" + " <div style=\"min-height: 20px;word-break: break-word;background-color: #ffffff;padding: 10px 10px 10px 10px;border-radius: 6px\">\n" + " <span>"+message[1]+"</span>\n" + " </div>\n" + " </div>\n" + " </div>").appendTo("#message"); } function onlinename(obj){ $("#online").empty(); obj.forEach(function (e){ $("<div style=\"width: 160px;height: 40px;margin: auto;margin-top: 10px;background-color: #fdffff;text-align: center;box-shadow: 0px 0px 10px #474749;border-radius: 4px;overflow: hidden\">\n" + " <span class=\"glyphicon glyphicon-user\" style=\"font-size: 30px;padding-top: 2px;padding-bottom: 2px\"></span>\n" + " <span style=\"font-size: 26px\">"+e+"</span>\n" + " </div>").appendTo("#online"); }); } $("#btn2").click(function(){ websocket.close(); }); //發(fā)送消息 $("#btn3").click(function(){ var message = $("#msg").val(); websocket.send(message); $("#msg").val(""); }); }); </script> </html>
因?yàn)槲疫@個(gè)是springboot項(xiàng)目
模板引擎代碼如下
package com.nx.study.springstudy.controller; import com.nx.study.springstudy.bean.UserPostForm; import com.nx.study.springstudy.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; @Controller public class WebSocketController { @Autowired private UserService userService; @RequestMapping("/websocket") public String webSocket(Model model, HttpServletRequest request){ HttpSession httpSession = request.getSession(); String username = (String) request.getSession().getAttribute("username"); String userpassword = (String) request.getSession().getAttribute("userpassword"); if (username != null){ UserPostForm Springuser = userService.query(username,userpassword); model.addAttribute("Springuser", Springuser); return "index/webSocket"; }else { return "index/ZGZG"; } } }
最后效果圖如下
以上就是使用springboot整合websocket實(shí)現(xiàn)群聊教程的詳細(xì)內(nèi)容,更多關(guān)于springboot整合websocket實(shí)現(xiàn)群聊的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java中try-catch-finally執(zhí)行順序你知道嗎
本文主要介紹了try-catch-finally執(zhí)行順序你知道嗎,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06SpringBoot使用JdbcTemplate操作數(shù)據(jù)庫(kù)
這篇文章主要介紹了SpringBoot使用JdbcTemplate操作數(shù)據(jù)庫(kù),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-07-07SpringBoot訪問web中的靜態(tài)資源的方式小結(jié)
這篇文章主要介紹了SpringBoot訪問web中的靜態(tài)資源的方式,本文給大家介紹了兩種方式,通過代碼示例和圖文講解的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下2024-10-10劍指Offer之Java算法習(xí)題精講數(shù)組與字符串題
跟著思路走,之后從簡(jiǎn)單題入手,反復(fù)去看,做過之后可能會(huì)忘記,之后再做一次,記不住就反復(fù)做,反復(fù)尋求思路和規(guī)律,慢慢積累就會(huì)發(fā)現(xiàn)質(zhì)的變化2022-03-03Java實(shí)現(xiàn)幾十萬條數(shù)據(jù)插入實(shí)例教程(30萬條數(shù)據(jù)插入MySQL僅需13秒)
這篇文章主要給大家介紹了關(guān)于Java如何實(shí)現(xiàn)幾十萬條數(shù)據(jù)插入的相關(guān)資料,30萬條數(shù)據(jù)插入MySQL僅需13秒,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-04-04Java設(shè)計(jì)模式之裝飾者模式詳解和代碼實(shí)例
這篇文章主要介紹了Java設(shè)計(jì)模式之裝飾者模式詳解和代碼實(shí)例,Decorator模式(別名Wrapper):動(dòng)態(tài)將職責(zé)附加到對(duì)象上,若要擴(kuò)展功能,裝飾者提供了比繼承更具彈性的代替方案,需要的朋友可以參考下2014-09-09idea中使用SonarLint進(jìn)行代碼規(guī)范檢測(cè)及使用方法
這篇文章主要介紹了idea中使用SonarLint進(jìn)行代碼規(guī)范檢測(cè),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-08-08Java基于socket編程相關(guān)知識(shí)解析
這篇文章主要為大家詳細(xì)解析了Java基于socket編程的相關(guān)知識(shí),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09java 實(shí)現(xiàn)約瑟夫環(huán)的實(shí)例代碼
這一次是借鑒模仿別人寫的代碼,以前覺得不好將數(shù)據(jù)結(jié)構(gòu)的鏈結(jié)構(gòu)什么的遷移到j(luò)ava上來使用,但這一次確實(shí)讓我感受到了可以自己構(gòu)造數(shù)據(jù)結(jié)構(gòu),然后使用類似鏈的方式來解決約瑟夫環(huán),有所頓悟。不多說,繼續(xù)上代碼2013-10-10Spring Boot LocalDateTime格式化處理的示例詳解
這篇文章主要介紹了Spring Boot LocalDateTime格式化處理的示例詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-10-10