當前位置:
首頁 >
前端技术
> javascript
>内容正文
javascript
SpringBoot+websocket实现私聊和群聊(可以发送文字和图片)
生活随笔
收集整理的這篇文章主要介紹了
SpringBoot+websocket实现私聊和群聊(可以发送文字和图片)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Websocket實現私聊和群聊
- 1. websocket的概念
- 1.1. 全雙工概念
- 2. websocket實現聊天室
- 2.1. WebSocket API
- 2.1.1. 構造方法
- 2.1.1.1. 語法
- 2.1.1.2. 參數
- 2.1.1.3. 拋出異常
- 2.1.2. 常量
- 2.1.3. 屬性
- 2.1.4. 方法
- 2.1.5. 事件
- 3. websocket實現群聊或私聊或圖片發送
- 3.1. 項目的最終目錄結構
- 3.2. 依賴注入
- 3.3. yml文件配置
- 3.4. 注入ServerEndpointExporter
- 3.5. Controller代碼
- 3.5. websocket實現群聊
- 3.5.1. 服務器端代碼
- 3.5.2. 客戶端代碼
- 3.5.3. 測試結果
- 3.6. websocket實現私聊+群聊
- 3.6.1. 服務器端代碼
- 3.6.2. 客戶端代碼
- 3.6.3. SocketConfig代碼
- 3.6.4. 測試結果
- 3.7. websocket實現聊天圖片發送
- 3.7.1. 服務端代碼
- 3.7.2. 客戶端代碼
- 3.7.3. SocketConfig代碼
- 3.7.4. 測試結果
1. websocket的概念
websocket是一種在單個TCP連接上進行全雙工通信的協議。websocket使得客戶端和服務器之間的數據交換變得更加簡單,允許服務端主動向客戶端推送數據。在websocket API中瀏覽器和服務器只需要完成一次握手,兩者之間就可以直接創建持久性的連接,并進行雙向數據傳輸。
1.1. 全雙工概念
全雙工是通訊傳輸的一個術語。通信允許數據在兩個方面上同時傳輸,它在能力上相當于兩個單工通信方式的結合。全雙工指可以同時進行信號的雙向傳輸(A—>B的同時B—>A)。單工指:只允許A向B傳送信息,而B不能向A傳送。
2. websocket實現聊天室
2.1. WebSocket API
WebSocket對象提供了用戶創建和管理WebSocket連接,以及通過該連接發送和接收數據的API。
2.1.1. 構造方法
2.1.1.1. 語法
WebSocket(url [, protocols]);
2.1.1.2. 參數
2.1.1.3. 拋出異常
SECURITY_ERR:正在嘗試連接的端口被阻止。
2.1.2. 常量
2.1.3. 屬性
2.1.4. 方法
2.1.5. 事件
使用addEventListener()監聽或將一個事件監聽器賦值給本接口的oneventname屬性,來監聽下面的事件:
3. websocket實現群聊或私聊或圖片發送
本文使用springboot+freemarker+websocket實現代碼
3.1. 項目的最終目錄結構
3.2. 依賴注入
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.AttackingApe.demo</groupId><artifactId>webSocket</artifactId><version>1.0-SNAPSHOT</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.6.RELEASE</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>net.sourceforge.nekohtml</groupId><artifactId>nekohtml</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.72</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins><resources><resource><directory>src/main/resources</directory></resource></resources></build> </project>3.3. yml文件配置
server:port: 20713tomcat:uri-encoding: UTF-8 spring:freemarker:suffix: .ftlcharset: UTF-8content-type: text/htmlhttp:encoding:charset: UTF-8force: trueenabled: true3.4. 注入ServerEndpointExporter
package com.AttackingApe.demo.webSocket.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** @author PengPan* @version 1.0* @date 2020/7/14 18:50*/ @Configuration public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();} }3.5. Controller代碼
package com.AttackingApe.demo.webSocket.Controller;import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.ModelAndView;import java.io.IOException; import java.util.Map;/*** websocket應用* @author PengPan* @version 1.0* @date 2020/7/13 14:34*/ @RestController @Slf4j public class WebsocketController {@RequestMapping("/websocketTest")public ModelAndView sendMessage(Map<String, Object> map) throws IOException{try{log.info("跳轉到websocket頁面上");return new ModelAndView("webSocketClients", map);}catch (Exception e){log.info("頁面跳轉發生錯誤:{}", e.getMessage());map.put("msg", "請求錯誤");return new ModelAndView("error", map);}} }3.5. websocket實現群聊
實現內容:連接websocket的用戶都可以進行聊天并顯示所有人聊天以及對應的昵稱。
3.5.1. 服務器端代碼
package com.AttackingApe.demo.webSocket.util;import com.AttackingApe.demo.webSocket.Pojo.SocketConfig; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component;import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CopyOnWriteArraySet;/*** @author PengPan* @version 1.0* @date 2020/7/15 18:23*/ @ServerEndpoint(value = "/websocket/{nickname}") @Component @Slf4j public class MyWebsocket {private static Map<String, Session> map = new HashMap<>();private static CopyOnWriteArraySet<MyWebsocket> clients = new CopyOnWriteArraySet<>();private Session session;private String nickname;@OnOpenpublic void onOpen(Session session, @PathParam("nickname") String nickname){this.session = session;this.nickname = nickname;clients.add(this);log.info("有新用戶加入,當前人數為:", clients.size());this.session.getAsyncRemote().sendText(nickname + "已加入連接,當前人數為:" + clients.size());}@OnClosepublic void onClose(){clients.remove(this);log.info("有用戶斷開連接,當前人數為:{}", clients.size());}@OnMessagepublic void onMessage(String message, Session session, @PathParam("nickname") String nickname){log.info("來自客戶端:{}發來的消息:{}", nickname, message);broadcast(nickname + ":" + message);}@OnErrorpublic void onError(Session session, Throwable error){log.error("出現錯誤");error.printStackTrace();}/*** 自定義群發消息* @param message*/public void broadcast(String message){for (MyWebsocket websocket : clients){//異步發送消息websocket.session.getAsyncRemote().sendText(message);}} }3.5.2. 客戶端代碼
<!DOCTYPE HTML> <html> <head><meta charset="UTF-8"><title>My WebSocket</title><style>#message{margin-top:40px;border:1px solid gray;padding:20px;}</style> </head> <body> 昵稱:<input type="text" id="nickname"/> <button onclick="conectWebSocket()">連接WebSocket</button> <button onclick="closeWebSocket()">斷開連接</button> <hr /> <br /> 消 息:<input id="text" type="text" /><button onclick="send()">發送消息</button> <div id="message"></div> </body> <script type="text/javascript">var websocket = null;function conectWebSocket(){var nickname = document.getElementById("nickname").value;if(nickname == "" || nickname == null){alert("請輸入昵稱");return;}//判斷當前瀏覽器是否支持WebSocketif ('WebSocket'in window) {websocket = new WebSocket("ws://10.4.4.83:20713/websocket/" + nickname);} else {alert('Not support websocket')}//連接發生錯誤的回調方法websocket.onerror = function() {setMessageInnerHTML("error");};//連接成功建立的回調方法websocket.onopen = function(event) {setMessageInnerHTML("Loc MSG: 成功建立連接");}//接收到消息的回調方法websocket.onmessage = function(event) {setMessageInnerHTML(event.data);}//連接關閉的回調方法websocket.onclose = function() {setMessageInnerHTML("Loc MSG:關閉連接");}//監聽窗口關閉事件,當窗口關閉時,主動去關閉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>3.5.3. 測試結果
3.6. websocket實現私聊+群聊
實現內容:A可以在公屏上輸入內容,大家都可以看見。也可以選擇輸入頻道,只和每一個人聊天。
3.6.1. 服務器端代碼
package com.AttackingApe.demo.webSocket.util;import com.AttackingApe.demo.webSocket.Pojo.SocketConfig; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component;import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CopyOnWriteArraySet;/*** @author PengPan* @version 1.0* @date 2020/7/15 18:23*/ @ServerEndpoint(value = "/websocket/{nickname}") @Component @Slf4j public class MyWebsocket {private static Map<String, Session> map = new HashMap<>();private static CopyOnWriteArraySet<MyWebsocket> clients = new CopyOnWriteArraySet<>();private Session session;private String nickname;@OnOpenpublic void onOpen(Session session, @PathParam("nickname") String nickname){this.session = session;this.nickname = nickname;map.put(session.getId(), session);clients.add(this);log.info("有新用戶加入,當前人數為:", clients.size());this.session.getAsyncRemote().sendText(nickname + "已成功連接(其頻道號為:" + session.getId() + "),當前在線人數為:" + clients.size());}@OnClosepublic void onClose(){clients.remove(this);log.info("有用戶斷開連接,當前人數為:{}", clients.size());}@OnMessagepublic void onMessage(String message, Session session, @PathParam("nickname") String nickname){log.info("來自客戶端:{}發來的消息:{}", nickname, message);SocketConfig socketConfig;ObjectMapper objectMapper = new ObjectMapper();try{socketConfig = objectMapper.readValue(message, SocketConfig.class);if(socketConfig.getType() == 1){ //私聊socketConfig.setFromUser(session.getId());Session fromSession = map.get(socketConfig.getFromUser());Session toSession = map.get(socketConfig.getToUser());if(toSession != null){ //接受者存在,發送以下消息給接受者和發送者fromSession.getAsyncRemote().sendText(nickname + ":" + socketConfig.getMsg());toSession.getAsyncRemote().sendText(nickname + ":" + socketConfig.getMsg());}else{ //發送者不存在,發送以下消息給發送者fromSession.getAsyncRemote().sendText("頻道號不存在或對方不在線");}}else{ //群聊broadcast(nickname + ":" + socketConfig.getMsg());}}catch (Exception e){log.error("發送消息出錯");e.printStackTrace();}}@OnErrorpublic void onError(Session session, Throwable error){log.error("出現錯誤");error.printStackTrace();}/*** 自定義群發消息* @param message*/public void broadcast(String message){for (MyWebsocket websocket : clients){//異步發送消息websocket.session.getAsyncRemote().sendText(message);}} }3.6.2. 客戶端代碼
<!DOCTYPE HTML> <html> <head><meta charset="UTF-8"><title>My WebSocket</title><style>#message{margin-top:40px;border:1px solid gray;padding:20px;}</style> </head> <body> 昵稱:<input type="text" id="nickname"/> <button onclick="conectWebSocket()">連接WebSocket</button> <button onclick="closeWebSocket()">斷開連接</button> <hr /> <br /> 消 息:<input id="text" type="text" /> 頻道號:<input id="toUser" type="text"/> <button onclick="send()">發送消息</button> <div id="message"></div> </body> <script type="text/javascript">var websocket = null;function conectWebSocket(){var nickname = document.getElementById("nickname").value;if(nickname == "" || nickname == null){alert("請輸入昵稱");return;}//判斷當前瀏覽器是否支持WebSocketif ('WebSocket'in window) {websocket = new WebSocket("ws://10.4.4.83:20713/websocket/" + nickname);} else {alert('Not support websocket')}//連接發生錯誤的回調方法websocket.onerror = function() {setMessageInnerHTML("error");};//連接成功建立的回調方法websocket.onopen = function(event) {setMessageInnerHTML("Loc MSG: 成功建立連接");}//接收到消息的回調方法websocket.onmessage = function(event) {setMessageInnerHTML(event.data);}//連接關閉的回調方法websocket.onclose = function() {setMessageInnerHTML("Loc MSG:關閉連接");}//監聽窗口關閉事件,當窗口關閉時,主動去關閉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;var toUser = document.getElementById('toUser').value;var socketConfig = {msg:message,toUser:toUser};if(toUser == "" || toUser == null){socketConfig.type = 0;}else{socketConfig.type = 1;}websocket.send(JSON.stringify(socketConfig));} </script> </html>3.6.3. SocketConfig代碼
package com.AttackingApe.demo.webSocket.Pojo;import lombok.Data;/*** @author PengPan* @version 1.0* @date 2020/7/16 15:41*/ @Data public class SocketConfig {//聊天類型 0:群聊 1:私聊private int type;//發送者private String fromUser;//接受者private String toUser;//消息private String msg;//消息類型 1:文本 2:圖片private int code; }3.6.4. 測試結果
3.7. websocket實現聊天圖片發送
實現內容:聊天的時候可以傳入圖片。
3.7.1. 服務端代碼
package com.AttackingApe.demo.webSocket.util;import com.AttackingApe.demo.webSocket.Pojo.SocketConfig; import com.alibaba.fastjson.JSONObject; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component;import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CopyOnWriteArraySet;/*** @author PengPan* @version 1.0* @date 2020/7/15 18:23*/ @ServerEndpoint(value = "/websocket/{nickname}") @Component @Slf4j public class MyWebsocket {private static Map<String, Session> map = new HashMap<>();private static CopyOnWriteArraySet<MyWebsocket> clients = new CopyOnWriteArraySet<>();private Session session;private String nickname;@OnOpenpublic void onOpen(Session session, @PathParam("nickname") String nickname){this.session = session;this.nickname = nickname;map.put(session.getId(), session);clients.add(this);log.info("有新用戶加入,當前人數為:", clients.size());JSONObject jsonObject = new JSONObject();jsonObject.put("msg",nickname + "已成功連接(其頻道號為:" + session.getId() + "),當前在線人數為:" + clients.size());jsonObject.put("code", 1);this.session.getAsyncRemote().sendText(jsonObject.toJSONString());}@OnClosepublic void onClose(){clients.remove(this);log.info("有用戶斷開連接,當前人數為:{}", clients.size());}@OnMessagepublic void onMessage(String message, Session session, @PathParam("nickname") String nickname){log.info("來自客戶端:{}發來的消息:{}", nickname, message);SocketConfig socketConfig;ObjectMapper objectMapper = new ObjectMapper();JSONObject jsonObject = new JSONObject();jsonObject.put("code", JSONObject.parseObject(message).get("code"));try{socketConfig = objectMapper.readValue(message, SocketConfig.class);jsonObject.put("nickname", nickname + ":");if(socketConfig.getType() == 1){ //私聊socketConfig.setFromUser(session.getId());Session fromSession = map.get(socketConfig.getFromUser());Session toSession = map.get(socketConfig.getToUser());if(toSession != null){ //接受者存在,發送以下消息給接受者和發送者jsonObject.put("msg", socketConfig.getMsg());fromSession.getAsyncRemote().sendText(jsonObject.toJSONString());toSession.getAsyncRemote().sendText(jsonObject.toJSONString());}else{ //發送者不存在,發送以下消息給發送者jsonObject.put("msg", "頻道號不存在或對方不在線");fromSession.getAsyncRemote().sendText("頻道號不存在或對方不在線");}}else{ //群聊jsonObject.put("msg", socketConfig.getMsg());broadcast(jsonObject.toJSONString());}}catch (Exception e){log.error("發送消息出錯");e.printStackTrace();}}@OnErrorpublic void onError(Session session, Throwable error){log.error("出現錯誤");error.printStackTrace();}/*** 自定義群發消息* @param message*/public void broadcast(String message){for (MyWebsocket websocket : clients){//異步發送消息websocket.session.getAsyncRemote().sendText(message);}} }3.7.2. 客戶端代碼
<!DOCTYPE HTML> <html> <head><meta charset="UTF-8"><title>My WebSocket</title><style>#message{margin-top:40px;border:1px solid gray;padding:20px;}</style> </head> <body> 昵稱:<input type="text" id="nickname"/> <button onclick="conectWebSocket()">連接WebSocket</button> <button onclick="closeWebSocket()">斷開連接</button> <hr /> <br /> 消 息:<input id="text" type="text" /> 頻道號:<input id="toUser" type="text"/> <button onclick="send()">發送消息</button> <input type="file" id="file" onchange="chooseFile()"/> <div id="message"></div> </body> <script type="text/javascript">var websocket = null;function conectWebSocket(){var nickname = document.getElementById("nickname").value;if(nickname == "" || nickname == null){alert("請輸入昵稱");return;}//判斷當前瀏覽器是否支持WebSocketif ('WebSocket'in window) {websocket = new WebSocket("ws://10.4.4.83:20713/websocket/" + nickname);} else {alert('Not support websocket')}//連接發生錯誤的回調方法websocket.onerror = function() {setMessageInnerHTML("error");};//連接成功建立的回調方法websocket.onopen = function(event) {setMessageInnerHTML("Loc MSG: 成功建立連接");}//接收到消息的回調方法websocket.onmessage = function(event) {var json = JSON.parse(event.data);if(json.code == 1){setMessageInnerHTML(json.nickname + json.msg);}else if(json.code == 2){setMessageInnerHTML(json.nickname);setIconInnerHTML(json.msg);}}//連接關閉的回調方法websocket.onclose = function() {setMessageInnerHTML("Loc MSG:關閉連接");}//監聽窗口關閉事件,當窗口關閉時,主動去關閉websocket連接,防止連接還沒斷開就關閉窗口,server端會拋異常。window.onbeforeunload = function() {websocket.close();}}//將文本消息顯示在網頁上function setMessageInnerHTML(innerHTML) {document.getElementById('message').innerHTML += innerHTML + '<br/>';}//將圖片消息顯示在網頁上function setIconInnerHTML(innerHTML) {document.getElementById('message').innerHTML = document.getElementById('message').innerHTML + '<img width="150px" src='+innerHTML+'>' + '<br/>';}//關閉連接function closeWebSocket() {websocket.close();}//發送文本消息function send() {var message = document.getElementById('text').value;var toUser = document.getElementById('toUser').value;var socketConfig = {code:1,msg:message,toUser:toUser};if(toUser == "" || toUser == null){socketConfig.type = 0;}else{socketConfig.type = 1;}websocket.send(JSON.stringify(socketConfig));}//發送圖片消息function chooseFile() {var fileList = document.getElementById("file").files;var type = fileList[0].type;var toUser = document.getElementById('toUser').value;if(fileList.length > 0){var fileReader = new FileReader();fileReader.readAsDataURL(fileList[0]);fileReader.onload = function (e) {var socketConfig = {msg: e.target.result,toUser: toUser,code: 2};if (toUser == "" || toUser == null) {socketConfig.type = 0;} else {socketConfig.type = 1;}websocket.send(JSON.stringify(socketConfig));}}} </script> </html>3.7.3. SocketConfig代碼
package com.AttackingApe.demo.webSocket.Pojo;import lombok.Data;/*** @author PengPan* @version 1.0* @date 2020/7/16 15:41*/ @Data public class SocketConfig {//聊天類型 0:群聊 1:私聊private int type;//發送者private String fromUser;//接受者private String toUser;//消息private String msg;//消息類型 1:文本 2:圖片private int code; }3.7.4. 測試結果
總結
以上是生活随笔為你收集整理的SpringBoot+websocket实现私聊和群聊(可以发送文字和图片)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 十二月各地中小企业扶持政策汇总
- 下一篇: JavaScript验证 IP/域名格式