SpringBoot框架:集成websocket实现即时通讯

一、导入依赖

  分别导入websocket依赖包和处理json格式数据的fastjson依赖包。

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.60</version> </dependency>

二、注解处理

  以下注解可以将配置为@ServerEndpoint标注的类在调用时自动导出为实体,类编写完成后使用@Configuration将config加入配置。

package com.example.demo2.config; 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(); } }

三、websocket类编写

package com.example.demo2.controller; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.fasterxml.jackson.databind.util.JSONPObject; 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; @Component @ServerEndpoint("/websocket/{userId}") public class MessageController { //与某个客户端的连接会话,需要用来发送数据 private Session session; //concurrent线程安全set,存放每个客户端对应的websocket对象 private static CopyOnWriteArraySet<MessageController> messageControllers = new CopyOnWriteArraySet<>(); //存储session池 private static Map<String,Session> sessionPool = new HashMap<String,Session>(); /** * 链接成功调用 */ @OnOpen public void onOpen(Session session, @PathParam(value = "userId")String userId){ try{ //session获取 this.session = session; //静态存储的websocket长链接集合中,添加本次调用成功所创建的这个实体 messageControllers.add(this); //session缓存池添加用户的用户ID和对应的session sessionPool.put(userId,session); //将用户加入链接和当前连接数的消息广播给当前所有已连接的用户 sendAllMessage("【" + userId +"】加入链接,当前连接数:" + messageControllers.size()); }catch (Exception e){ e.printStackTrace(); } } /** * 链接关闭调用 */ @OnClose public void onClose(){ try{ //已连接的对象列表中移除当前调用此关闭方法的对象 messageControllers.remove(this); //将用户断开链接和链接总数信息推送给现在还链接着的用户 System.out.println("用户断开链接,当前链接总数为:" + messageControllers.size()); }catch (Exception e){ } } /** * 收到客户端消息 */ @OnMessage public void onMessage(String message){ //收到客户端消息后可以根据实际需求做一些处理操作,也可以直接返回,到页面进行处理 //广播给群中现在处理已连接状态的所有用户 sendAllMessage(message); } /** * 发送错误处理 */ @OnError public void onError(Session session,Throwable error){ //输出错误信息 System.out.println("【发送错误】:" + error.getMessage()); error.printStackTrace(); } /** * 广播(全体)消息 */ public void sendAllMessage(String message){ //遍历当前所有已连接的用户,循环发送 for(MessageController messageController : messageControllers){ try{ //session处于打开状态,则发送消息 if(messageController.session.isOpen()){ //最好是使用这个getAsyncRemote,另一个(getBasicRemote)在多个线程同时进行时容易报错,这两个是异步和同步的区别 messageController.session.getAsyncRemote().sendText(message); } }catch (Exception e){ e.printStackTrace(); } } } /** * 单点消息 */ public void sendOneMessage(String userId,String message){ //根据userId获取到对应的session Session session = sessionPool.get(userId); //这个session不为空并且还在开放状态 if(session != null && session.isOpen()){ try{ //将消息单独推送到这个userId对应的session里 session.getAsyncRemote().sendText(message); }catch (Exception e){ e.printStackTrace(); } } } /** * 多点消息(多选发给一部分人) */ public void sendManyMessage(String[] userIds,String message){ //遍历参数中的用户id数组,进行多个推送,介于单个和广播(全体)之间的部分发送 for(String userId:userIds){ Session session = sessionPool.get(userId); if(session != null && session.isOpen()){ try{ session.getAsyncRemote().sendText(message); }catch (Exception e){ e.printStackTrace(); } } } } }

  除了在这个类内部调用发送信息的方法之外,其他可以通过类中注入此类后,使用接口进行方法调用。(之前本来想用main方法测试一下发现这种方式不行,还是要在接口中调用)

四、websocket在vue页面里进行应用

<template> <div> <!--填写个人信息 --> <input v-model="userId" /> <input v-model="userName" /> <!-- 绑定后根据个人信息创建websocket连接 --> <button @click="andUser">绑定</button> <br /> <!-- 填写要发送的消息 --> <input v-model="message" /> <!-- 发送信息 --> <button @click="webSocketSend">发送</button> <br /> <!-- 遍历显示所有信息列表 --> <div v-for="item in infoList"> <span>{{ item }}</span> <br /> </div> </div> </template> <script> export default { name: "Index", data(){ return{ //默认用户信息 userId:1, userName:"张三", //预置websocket,设为undefined websock:undefined, //要发送的消息 message:"", //消息列表 infoList:[], } }, mounted() { //如果多地进行测试,可以在这里进行初始化 //一个人开多个窗口的话,可以在填写不同用户信息后,点击绑定时使用不同的userId进行初始化 }, destroyed() { //页面销毁时触发,关闭此用户的websocket连接 this.webSocketOnClose(); }, methods:{ //建立连接 initWebSocket(){ //websocket服务链接的地址 let url = "ws://127.0.0.1:8080/websocket/" + this.userId; //创建连接 this.websock = new WebSocket(url); //将自定义的方法替换websocket自带的方法 this.websock.onopen = this.webSocketOnOpen; // this.websock.send = this.webSocketSend; this.websock.onerror = this.webSocketOnError; this.websock.onmessage = this.webSocketOnMessage; this.websock.onclose = this.webSocketOnClose; }, //连接上之后触发 webSocketOnOpen(){ //将用户连接成功的消息放到列表进行展示 this.infoList.push("" + this.userName + "】连接成功"); }, //发送消息时触发 webSocketSend(){ //将用户信息和要发送的消息包装为json let data = { userId:this.userId, userName:this.userName, message:this.message } //将json格式化为字符串之后发送到服务端 this.websock.send(JSON.stringify(data)); //自己发送的信息添加到列表进行展示 this.infoList.push(this.userName + ":" + this.message); }, //发送错误时触发 webSocketOnError(e){ //将错误信息添加到列表展示在页面 this.infoList.push("【错误】:" + e.toString()); }, //接收消息时触发 webSocketOnMessage(e){ //返回的信息存储在此方法参数的data字段 if(e.data != undefined && e.data != null && e.data != ''){ //信息非空时,通过json格式化为表单 let json = JSON.parse(e.data); //如果返回消息的用户id是本人,则为自己发送的信息,不需要显示 if(json.userId != this.userId){ //判断是别人发送的信息,则拼接字段并添加到列表中用于展示 this.infoList.push(json.userName + ":" + json.message); } } }, //关闭连接时触发 webSocketOnClose(){ //将用户关闭链接的消息写入列表 this.infoList.push("" + this.userName + "】关闭连接"); }, //绑定用户 andUser(){ //初始化websocket this.initWebSocket(); } } } </script> <style scoped> </style>

  


__EOF__

本文作者我命倾尘
本文链接https://www.cnblogs.com/guobin-/p/16670186.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   我命倾尘  阅读(944)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
历史上的今天:
2020-09-08 Vue.js框架:IDEA中vue文件代码自动补全设置
点击右上角即可分享
微信分享提示