專門做干果批發(fā)的網(wǎng)站國際新聞頭條今日國際大事
其實使用消息隊列也可以實現(xiàn)會話,直接前端監(jiān)聽指定的隊列,使用rabbitmq的分組還可以實現(xiàn)不同群聊的效果。
1、依賴搭建:
<?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>org.example</groupId><artifactId>WebStock</artifactId><version>1.0-SNAPSHOT</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.8</version><relativePath/></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-websocket</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties></project>
SpringBoot都已集成完畢了,不用使用原生的WebStock。
2、配置運行
如果是工作中,要單獨起一個服務來操作這個比較好,反正是微服務,多一個少一個沒啥的
WebStock連接配置、
package com.quxiao.config;import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.socket.BinaryMessage; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.AbstractWebSocketHandler;import java.time.LocalDateTime;/*** ws消息處理類*/ @Component @Slf4j public class MyWsHandler extends AbstractWebSocketHandler {@AutowiredWsService wsService;@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {log.info("建立ws連接");WsSessionManager.add(session.getId(), session);}@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {log.info("發(fā)送文本消息");// 獲得客戶端傳來的消息String payload = message.getPayload();//這里也是一樣,要取出前端傳來的參數(shù),判斷發(fā)給誰.這里我就是發(fā)給了連接客戶端自己.log.info("server 接收到消息 " + payload);wsService.sendMsg(session, "server 發(fā)送給的消息 " + payload + ",發(fā)送時間:" + LocalDateTime.now().toString());String url = session.getUri().toString();//使用?拼接參數(shù),后端取出判斷發(fā)給誰System.out.println("獲取到的參數(shù):" + url.substring(url.indexOf('?') + 1));}@Overrideprotected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {log.info("發(fā)送二進制消息");}@Overridepublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {log.error("異常處理");WsSessionManager.removeAndClose(session.getId());}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {log.info("關閉ws連接");WsSessionManager.removeAndClose(session.getId());} }
package com.quxiao.config;import lombok.extern.slf4j.Slf4j; import org.springframework.web.socket.WebSocketSession;import java.io.IOException; import java.util.concurrent.ConcurrentHashMap;@Slf4j public class WsSessionManager {/*** 保存連接 session 的地方*/public static ConcurrentHashMap<String, WebSocketSession> SESSION_POOL = new ConcurrentHashMap<>();/*** 添加 session** @param key*/public static void add(String key, WebSocketSession session) {// 添加 sessionSESSION_POOL.put(key, session);}/*** 刪除 session,會返回刪除的 session** @param key* @return*/public static WebSocketSession remove(String key) {// 刪除 sessionreturn SESSION_POOL.remove(key);}/*** 刪除并同步關閉連接** @param key*/public static void removeAndClose(String key) {WebSocketSession session = remove(key);if (session != null) {try {// 關閉連接session.close();} catch (IOException e) {// todo: 關閉出現(xiàn)異常處理e.printStackTrace();}}}/*** 獲得 session** @param key* @return*/public static WebSocketSession get(String key) {// 獲得 sessionreturn SESSION_POOL.get(key);} }
package com.quxiao.config;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;@Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer {@Autowiredprivate MyWsHandler myWsHandler;@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(myWsHandler, "myWs")//允許跨域.setAllowedOrigins("*");} }
這里有幾個后續(xù)邏輯:
(1)、連接時,通過前端的參數(shù)或者對其按登陸人信息綁定連接消息。
(2)、收到一個消息,發(fā)送給誰就得需要前端傳來參數(shù):例如某個群的id,然后通過群綁定人員,因為(1)中通過<key,value>人員id為key,value時連接信息。
直接遍歷這個群下面的所有人員id,獲取已經(jīng)連接的信息,發(fā)送給他們。這里還要搞一個表存儲群消息log。這樣其他群員連接時,可以獲取到以往的消息。
發(fā)送消息工具類
package com.quxiao.config;import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession;import java.io.IOException;/*** ws操作相關服務*/ @Service @Slf4j public class WsServiceUtil {/*** 發(fā)送消息* @param session* @param text* @return* @throws IOException*/public void sendMsg(WebSocketSession session, String text) throws IOException {session.sendMessage(new TextMessage(text));}/*** 廣播消息* @param text* @return* @throws IOException*/public void broadcastMsg(String text) throws IOException {for (WebSocketSession session: WsSessionManager.SESSION_POOL.values()) {session.sendMessage(new TextMessage(text));}}}
? ?這里廣播我就是遍歷了儲存連接消息的map容器。
package com.quxiao.controller;import com.quxiao.config.WsServiceUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletRequest;@RestController @RequestMapping("/put") public class MessageHandler {@AutowiredWsServiceUtil wsServiceUtil;@PostMapping("/t1/{test}")public void t1(@PathVariable("test") String text) {try {wsServiceUtil.broadcastMsg(Thread.currentThread().getName() + ": " + text);} catch (Exception e) {throw new RuntimeException(e);}}}
3、?前端測試頁面:
<!DOCTYPE HTML> <html> <head><title>My WebSocket</title> </head><body> <input id="text" type="text" /> <button onclick="send()">Send</button> <button onclick="closeWebSocket()">Close</button> <div id="message"></div></body><script type="text/javascript">let ws = null;//判斷當前瀏覽器是否支持WebSocketif ('WebSocket' in window) {ws = new WebSocket("ws://localhost:8080/myWs?2002");}else {alert('當前瀏覽器 Not support websocket')}//連接發(fā)生錯誤的回調(diào)方法ws.onerror = function () {setMessageInnerHTML("WebSocket連接發(fā)生錯誤");};//連接成功建立的回調(diào)方法ws.onopen = function(event) {console.log("ws調(diào)用連接成功回調(diào)方法")//ws.send("")}//接收到消息的回調(diào)方法ws.onmessage = function(message) {console.log("接收消息:" + message.data);if (typeof(message.data) == 'string') {setMessageInnerHTML(message.data);}}//ws連接斷開的回調(diào)方法ws.onclose = function(e) {console.log("ws連接斷開")//console.log(e)setMessageInnerHTML("ws close");}//將消息顯示在網(wǎng)頁上function setMessageInnerHTML(innerHTML) {console.log(innerHTML)document.getElementById('message').innerHTML += '接收的消息:' + innerHTML + '<br/>';}//關閉連接function closeWebSocket() {ws.close();}//發(fā)送消息function send(msg) {if(!msg){msg = document.getElementById('text').value;document.getElementById('message').innerHTML += "發(fā)送的消息:" + msg + '<br/>';ws.send(msg);}} </script> </html>
4、總結(jié)
所以最重要的是這個消息發(fā)給誰
????????后端要做的就是需要根據(jù)不同的群、人員標識符去發(fā)送消息,
前端需要做的就是
? ? ? ? 傳入不同的標識符,如果是私聊,就得傳人員id,如果是群聊,就需要傳入群id。