WebStock会话

avatar
作者
猴君
阅读量:0

其实使用消息队列也可以实现会话,直接前端监听指定的队列,使用rabbitmq的分组还可以实现不同群聊的效果。

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 {     @Autowired     WsService wsService;      @Override     public void afterConnectionEstablished(WebSocketSession session) throws Exception {         log.info("建立ws连接");         WsSessionManager.add(session.getId(), session);     }      @Override     protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {         log.info("发送文本消息");         // 获得客户端传来的消息         String payload = message.getPayload();         //这里也是一样,要取出前端传来的参数,判断发给谁.这里我就是发给了连接客户端自己.         log.info("server 接收到消息 " + payload);         wsService.sendMsg(session, "server 发送给的消息 " + payload + ",发送时间:" + LocalDateTime.now().toString());         String url = session.getUri().toString();         //使用?拼接参数,后端取出判断发给谁         System.out.println("获取到的参数:" + url.substring(url.indexOf('?') + 1));     }      @Override     protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {         log.info("发送二进制消息");     }      @Override     public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {         log.error("异常处理");         WsSessionManager.removeAndClose(session.getId());     }      @Override     public 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) {         // 添加 session         SESSION_POOL.put(key, session);     }      /**      * 删除 session,会返回删除的 session      *      * @param key      * @return      */     public static WebSocketSession remove(String key) {         // 删除 session         return 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: 关闭出现异常处理                 e.printStackTrace();             }         }     }      /**      * 获得 session      *      * @param key      * @return      */     public static WebSocketSession get(String key) {         // 获得 session         return 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 {      @Autowired     private MyWsHandler myWsHandler;      @Override     public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {         registry                 .addHandler(myWsHandler, "myWs")                 //允许跨域                 .setAllowedOrigins("*");     } } 

这里有几个后续逻辑:

(1)、连接时,通过前端的参数或者对其按登陆人信息绑定连接消息。

(2)、收到一个消息,发送给谁就得需要前端传来参数:例如某个群的id,然后通过群绑定人员,因为(1)中通过<key,value>人员id为key,value时连接信息。

直接遍历这个群下面的所有人员id,获取已经连接的信息,发送给他们。这里还要搞一个表存储群消息log。这样其他群员连接时,可以获取到以往的消息。

发送消息工具类

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 {      /**      * 发送消息      * @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 {     @Autowired     WsServiceUtil 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;     //判断当前浏览器是否支持WebSocket     if ('WebSocket' in window) {         ws = new WebSocket("ws://localhost:8080/myWs?2002");     }     else {         alert('当前浏览器 Not support websocket')     }      //连接发生错误的回调方法     ws.onerror = function () {         setMessageInnerHTML("WebSocket连接发生错误");     };      //连接成功建立的回调方法     ws.onopen = function(event) {         console.log("ws调用连接成功回调方法")         //ws.send("")     }     //接收到消息的回调方法     ws.onmessage = function(message) {         console.log("接收消息:" + message.data);         if (typeof(message.data) == 'string') {             setMessageInnerHTML(message.data);         }     }     //ws连接断开的回调方法     ws.onclose = function(e) {         console.log("ws连接断开")         //console.log(e)         setMessageInnerHTML("ws close");     }      //将消息显示在网页上     function setMessageInnerHTML(innerHTML) {         console.log(innerHTML)         document.getElementById('message').innerHTML += '接收的消息:' + innerHTML + '<br/>';     }      //关闭连接     function closeWebSocket() {         ws.close();     }       //发送消息     function send(msg) {         if(!msg){             msg = document.getElementById('text').value;             document.getElementById('message').innerHTML += "发送的消息:" + msg + '<br/>';             ws.send(msg);         }     } </script> </html>  

4、总结

所以最重要的是这个消息发给谁

        后端要做的就是需要根据不同的群、人员标识符去发送消息,

前端需要做的就是

        传入不同的标识符,如果是私聊,就得传人员id,如果是群聊,就需要传入群id。

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!