SpringBoot整合websocket实现及时通信聊天

🎨领域:Java后端开发



在这里插入图片描述


🔥收录专栏: 系统设计与实战
🐒个人主页:BreezAm
💖Gitee:https://gitee.com/BreezAm
✨个人标签:【后端】【大数据】【前端】【运维】

文章目录

    • 🌿一、技术介绍
      • 🌳1.1 客户端WebSocket
        • 🌴1.1.1 函数
        • 🌴1.1.2 事件
      • 🌳1.2 服务端WebSocket
    • 🌿二、实战
      • 🌳2.1、服务端
        • 🌴2.1.1引入maven依赖
        • 🌴2.1.2 编写配置类
        • 🌴2.1.3 编写WebSocketService服务类
        • 🌴2.1.4 建立连接
        • 🌴2.1.5 关闭连接
        • 🌴2.1.6 发送消息
        • 🌴2.1.7 监听错误
      • 🌳2.2 客户端
        • 🌴2.2.1 主页面
        • 🌴2.2.1 聊天页面
    • 🌿三、开源地址
    • 🌿四、参考文献

🌿一、技术介绍

线上演示地址:http://chat.breez.work
在这里插入图片描述

实时通信(Instant Messaging,简称IM)是一个实时通信系统,允许两人或多人使用网络实时的传递文字消息文件语音视频交流。[4]

场景再现:

  • 🐭微信聊天
  • 🐭QQ聊天
  • 🐭网站在线客服

🌳1.1 客户端WebSocket

WebSocket 对象提供了用于创建和管理 WebSocket 连接,以及可以通过该连接发送接收数据的 API。使用 WebSocket() 构造函数来构造一个 WebSocket。[1]

构造函数如下所示:

const webSocket = WebSocket(url[, protocols])

例子如下:

const webSocket = new WebSocket("ws://42.193.120.86:3688/ws/小明/翠花")

🌴1.1.1 函数

1、 webSocket.send()
该函数用于向服务端发送一条消息,例子如下:

webSocket.send("Hello server!");

2、 webSocket.close()
该函数用于关闭客户端与服务端的连接,例子如下:

webSocket.close();

🌴1.1.2 事件

1、webSocket.onopen
该事件用于监听客户端与服务端的连接状态,如果客户端与服务端连接成功则该事件触发,例子如下:

webSocket.onopen = function(event) {console.log("连接已经建立,可以进行通信");
};

2、webSocket.onclose
如果服务端与客户端连接断开,那么此事件出发,例子如下:

webSocket.onclose = function(event) {console.log("连接已经关闭");
};

3、webSocket: message event
该事件用于监听服务端向客户端发送的消息,例子如下:

webSocket.addEventListener('message', function (event) {console.log('来自服务端的消息:', event.data);
});

4、webSocket:error event
如果客户端与服务端发生错误时,那么此事件将会触发,例子如下:

webSocket.addEventListener('error', function (event) {console.log('连接出现错误', event);
});

🌳1.2 服务端WebSocket

@ServerEndpoint用于声明一个socket服务,例子如下:

@ServerEndpoint(value = "/ws/{userId}/{targetId}")

几个重要的方法注解:

  • @OnOpen 打开连接
  • @OnClose 监听关闭
  • @OnMessage 发送消息
  • @OnError 监听错误

🌿二、实战

🌳2.1、服务端

🌴2.1.1引入maven依赖

 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

🌴2.1.2 编写配置类

@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

🌴2.1.3 编写WebSocketService服务类

下面的userId代表发送者的ID号,target代表发送目标ID号。

@Component
@ServerEndpoint(value = "/ws/{userId}/{target}")
public class WebSocketService {//用于保存连接的用户信息private static ConcurrentHashMap<String, Session> SESSION = new ConcurrentHashMap<>();//原子递增递减,用于统计在线用户数private static AtomicInteger count = new AtomicInteger();//消息队列,用于保存待发送的信息private Queue<String> queue = new LinkedBlockingDeque<>();//onOpen()//onClose()//onMessage()//onError()
}

🌴2.1.4 建立连接

建立连接之前,判断用户是否已经连接,如果没有连接,那么将用户session信息保存到集合,然后计数器递增。

	@OnOpenpublic void onOpen(Session session, @PathParam("userId") String userId) {if (!SESSION.containsKey(userId)) {SESSION.put(userId, session);count.incrementAndGet();}}

🌴2.1.5 关闭连接

关闭连接的时候,将用户session删除和计数器递减。

	 @OnClosepublic void onClose(@PathParam("userId") String userId) {SESSION.remove(userId);count.decrementAndGet();}

🌴2.1.6 发送消息

发送采用的方法是:session.getBasicRemote().sendText("你好");

 	@OnMessagepublic void onMessage(String message, @PathParam("userId") String userId, @PathParam("target") String target) throws IOException {queue.add(message);Session s = SESSION.get(target);if (s == null) {Session b = SESSION.get(userId);b.getBasicRemote().sendText("对方不在线");} else {for (int i = 0; i < queue.size(); i++) {String msg = queue.poll();Message m = new Message();m.setUserId(userId);s.getBasicRemote().sendText(msg);}}}

🌴2.1.7 监听错误

出现错误,删除用户session信息和计数器递减

	@OnErrorpublic void onError(Throwable error, @PathParam("userId") String userId) {SESSION.remove(userId);count.decrementAndGet();error.printStackTrace();}

🌳2.2 客户端

本案例中客户端采用Nuxt编写,相关代码如下

🌴2.2.1 主页面

运行截图如图所示:
在这里插入图片描述

<template><div style="padding-left: 20%;"><div style="padding-left: 20%;padding-top: 30px;"><div style="font-size: 30px;">欢迎使用喵喵号聊天</div></div><div style="padding-top: 20%;"><el-form :rules="rules" ref="formInline" :inline="true" :model="formInline" class="demo-form-inline"><el-form-item label="我的喵喵号" prop="userId"><el-input v-model="formInline.userId" placeholder="喵喵号"></el-input></el-form-item><el-form-item label="对方喵喵号" prop="targetId"><el-input v-model="formInline.targetId" placeholder="喵喵号"></el-input></el-form-item><el-form-item><el-button type="primary" @click="onSubmit('formInline')">聊一下</el-button></el-form-item></el-form></div></div>
</template><script>export default {name: 'IndexPage',data() {return {formInline: {userId: '',targetId: ''},rules: {userId: [{required: true,message: '请输入你的喵喵号',trigger: 'blur'}],targetId: [{required: true,message: '请输入对方喵喵号',trigger: 'blur'}]}}},methods: {onSubmit(formName) {this.$refs[formName].validate((valid) => {if (valid) {this.$router.push({name: 'chat',params: this.formInline})} else {console.log('error submit!!');return false;}});}},created() {}}
</script>
<style>body {background: url('../static/img/cat.jpg');}
</style>

🌴2.2.1 聊天页面

运行截图如下:
小明
在这里插入图片描述

翠花
在这里插入图片描述

<template><div><el-row :gutter="20" style="padding-top: 20px;"><div style="padding-left: 35%;"><div style="padding-bottom: 15px"><div style="float: left;padding-right: 30px;">我的喵喵号:<el-tag type="warning">{{user.userId}}</el-tag></div><div>对方喵喵号:<el-tag type="success">{{user.targetId}}</el-tag><el-link @click="clearMsg()" :underline="false" style="padding-left: 30px;" type="danger">清空消息</el-link></div></div><div style="border: 1px green solid;width: 400px;height: 400px;border-radius: 10px;"><div v-for="(m,index) in msgList" :key="index++"><el-row :gutter="20"><div v-if="m.type===1" style="padding-left: 10px;"><el-avatar src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"></el-avatar>{{m.msg}}</div><div v-if="m.type===2" style="padding-right: 15px;float: right;">{{m.msg}}<el-avatar src="https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg"></el-avatar></div><div v-if="m.type===3" style="padding-left: 15px;padding-top: 15px;">系统消息:{{m.msg}}</div></el-row></div></div></div></el-row><el-row :gutter="5" style="padding-top: 20px;padding-left: 35%;"><el-col :span="9" :xs="9" :sm="9" :md="9" :lg="9" :xl="9"><el-input :disabled="msg_status" v-model="msg" placeholder="消息"></el-input></el-col><el-col :span="2"><el-button @click="sendMessage()" type="primary">发送</el-button></el-col></el-row></div></template><script>export default {name: 'ChatPage',data() {return {url: 'localhost:3688/ws/1001/1002',msg: '',socket: {},msg_status: true,msgList: [],initList: [],count: 0,user: {userId: '',targetId: ''}}},created() {const userId = this.$route.params.userIdconst targetId = this.$route.params.targetIdif (userId !== undefined && targetId !== undefined) {this.user.userId = userIdthis.user.targetId = targetIdthis.connect()} else {this.$router.push("/")}},methods: {//创建socket客户端connect() {var that = thisthis.socket = new WebSocket("ws://42.193.120.86:3688/ws/" + this.user.userId + "/" + this.user.targetId);this.socket.onclose = function(event) {that.$message('连接关闭');};this.socket.addEventListener('error', function(event) {that.$message.error('出现错误');});// 监听消息this.socket.addEventListener('message', function(event) {that.msgList.push({type: 2,msg: event.data})console.log(event.data);console.log({type: 2,msg: event.data});});this.socket.onopen = function(event) {that.msg_status = falsethat.msgList.push({type: 3,msg: '连接成功'})};},clearMsg() {this.$confirm('确认清空?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {this.msgList = []})},//发送消息sendMessage() {this.socket.send(this.msg)this.msgList.push({type: 1,msg: this.msg})this.msg = ''}}}
</script><style>
</style>

🌿三、开源地址

  • 💖Gitee:https://gitee.com/BreezAm/websocket
  • 演示地址:http://chat.breez.work

🌿四、参考文献

  • [1]MDN:WebSocket
  • [2]Nuxt:https://nuxtjs.org
  • [3]Vue:https://cn.vuejs.org
  • [4]百度百科:及时通信

🔥收录专栏:系统设计与实战
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/517377.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2019双11,支付宝有哪些“秘密武器”?

2019双11&#xff0c;支付宝参战的第十一年。 与十一年前相比&#xff0c;双11的许多东西都改变了。比如金额——2684亿&#xff0c;差不多是十一年前的5000倍&#xff1b;比如流量——订单峰值54.4万笔/秒&#xff0c;曾经是想都不敢想的数字&#xff1b;再比如层出不穷的新技…

一文看懂 K8s 日志系统设计和实践

导读&#xff1a;上一篇文章《6 个 K8s 日志系统建设中的典型问题&#xff0c;你遇到过几个&#xff1f;》中我们介绍了为什么需要一个日志系统、为什么云原生下的日志系统如此重要以及云原生背景下日志系统的建设难点&#xff0c;相信 DevOps、SRE、运维等同学看了之后深有体会…

如何在 Kubernetes 上配置 Jenkins?

作者 | Sudip Sengupta译者 | 火火酱&#xff0c;责编 | Carol封图 | CSDN 下载自视觉中国在本文中&#xff0c;我们将一起完成在Kubernetes上配置Jenkins的工作。作为一款被广泛使用的开源CI服务器&#xff0c;Jenkins提供了数百个插件&#xff0c;能够为我们项目的构建、部署…

MySQL做数据统计SQL语句整理大全(原理+实战)

&#x1f3a8;领域&#xff1a;Java后端开发&#x1f525;收录专栏&#xff1a; MySQL原理与实战 &#x1f412;个人主页&#xff1a;BreezAm &#x1f496;Gitee&#xff1a;https://gitee.com/BreezAm ✨个人标签&#xff1a;【后端】【大数据】【前端】【运维】 文章目录&a…

如何在一周内上线50个用户增长策略

在闲鱼用户增长业务上的实验 我们最先落地的业务是在用户增长上&#xff0c;闲鱼的用户增长业务有如下描述&#xff1a; 闲鱼的卖家都是普通小卖家&#xff0c;而非专业的B类商家。因此无法统一组织起来参加营销活动带来买家活跃。我们目前DAU已经突破到2000W&#xff0c;如何…

jstat gc各参数含义

参数说明S0C第一个幸存区的大小S1C第二个幸存区的大小S0U第一个幸存区的使用大小S1U第二个幸存区的使用大小EC伊甸园区的大小EU伊甸园区的使用大小OC老年代大小OU老年代使用大小MC方法区大小MU方法区使用大小CCSC压缩类空间大小CCSU压缩类空间使用大小YGC年轻代垃圾回收次数YGC…

MySQL用户如何构建实时数仓

依托数据库生态&#xff0c;AnalyticDB for MySQL可以给用户提供分析场景下的标准解决方案&#xff0c;尤其是在大数据和性能要求较高的情况下AnalyticDB for MySQL的价值可以更好的体现。 MySQL用户为什么要单独构建数据仓库 为什么要单独构建数据仓库&#xff0c;而不是直接…

138 张图带你 MySQL 入门!

作者 | cxuan来源 | Java建设者SQL 基础使用MySQL 是一种关系型数据库&#xff0c;说到关系&#xff0c;那么就离不开表与表之间的关系&#xff0c;而最能体现这种关系的其实就是我们接下来需要介绍的主角 SQL&#xff0c;SQL 的全称是 Structure Query Language &#xff0c;…

Centos/Red Hat6.8 安装、配置、启动Gitlab (内网环境)

文章目录一、软件和源准备1. Gitlab下载2. epel源下载二、环境配置2.1. 安装依赖项2.2. 安装epel源2.3. 安装Gitlab三、Gitlab和防火墙配置3.1. 设置external_url3.2. 重新加载配置3.3. 防火墙配置四、测试验证4.1. 浏览器访问Gitlab4.2. 重新设置密码4.3. Gitlab常用命令一、软…

Promise封装Ajax实现POST和GET请求

&#x1f3a8;领域&#xff1a;Java后端开发&#x1f525;收录专栏&#xff1a; 前端技术 &#x1f412;个人主页&#xff1a;BreezAm &#x1f496;Gitee&#xff1a;https://gitee.com/BreezAm ✨个人标签&#xff1a;【后端】【大数据】【前端】【运维】 文章目录介绍一、相…

轻松构建基于 Serverless 架构的弹性高可用视频处理系统

前言 随着计算机技术和 Internet 的日新月异&#xff0c;视频点播技术因其良好的人机交互性和流媒体传输技术倍受教育、娱乐等行业青睐&#xff0c;而在当前&#xff0c; 云计算平台厂商的产品线不断成熟完善&#xff0c; 如果想要搭建视频点播类应用&#xff0c;告别刀耕火种…

Centos/Red Hat6.8 安装、配置、启动Gitlab (内网环境)心得分享

文章目录一、Gitlab下载1. Gitlab官网下载二、分析思路2.1. 分析2.2. 代码托管平台2.3. 镜像站二、Gitlab 重新加载配置异常2.1. 异常现象2.2. 分析定位三、百度解决问题3.1. 百度类似异常3.2. 参考博文3.3. 解决方案3.4. 执行测试3.5. 结论四、官网issues 014.1. 找官网issues…

祝贺我的同事王坚当选院士!

刚刚&#xff0c; 收到一个激动人心的消息&#xff1a; 原文链接 本文为云栖社区原创内容&#xff0c;未经允许不得转载。

带你从零入门 Serverless | 一文详解 Serverless 架构模式

作者 | Hongqi 阿里云高级技术专家责编 | Carol来源 | Serverless本文整理自《Serverless 技术公开课》什么是 Serverless 架构&#xff1f;按照 CNCF 对 Serverless 计算的定义&#xff0c;Serverless 架构应该是采用 FaaS&#xff08;函数即服务&#xff09;和 BaaS&#xf…

端智能揭秘|促使双十一GMV大幅提升,手淘用了什么秘密武器?

作者|莫凌、桑杨、明依 出品|阿里巴巴新零售淘系技术部 导读&#xff1a;信息流作为手淘的一大流量入口&#xff0c;对手淘的浏览效率转化和流量分发起到至关重要的作用。在探索如何给用户推荐其喜欢的商品这条路上&#xff0c;我们首次将端计算大规模应用在手淘客户端&#xf…

bug:The selected directory is not a valid home for Go SDK

问题描述&#xff1a; 使用IDEA插件配置go开发环境无法选择已经安装配置好的SDK 当选择local中的SDK时&#xff0c;出现如下错误&#xff1a; The selected directory is not a valid home for Go SDK解决方案&#xff1a; 在自己的SDK目录C:\Program Files\Go\src\runtime\…

Dataphin的代码自动化能力如何助力商业决策

前言 随着大数据趋势的迅速增长&#xff0c;数据的重要性与日俱增&#xff0c;企业内看数据、用数据的诉求越来越强烈&#xff0c;其中最常见的就是各种经营报表数据&#xff1a; 老板每日早晨9点准时需要看到企业核心的经营数据&#xff0c;以便进行企业战略及方向决策 业务负…

Gitlab14.x 安装、配置、启动 (Centos/Red Hat7/8.x)

文章目录一、下载、安装、配置依赖1. 安装配置需要的依赖2. Gitlab下载3. 安装Gitlab4. 配置external_url5. 重新加载配置文件6. 查看服务状态7. 配置防火墙8. 浏览器验证9. 寻找密码信息10. 查看密码11. 重新登陆12. 修改密码13. 重新登陆14. Gitlab常用命令声明&#xff1a;C…

如何通过Dataphin构建数据中台新增100万用户?

欢迎来到数据中台小讲堂&#xff01;这一期我们来看看&#xff0c;作为阿里巴巴数据中台(OneData - OneModel、OneID、OneService)方法论的产品载体&#xff0c;Dataphin如何帮助传统零售企业实现数字化转型&#xff0c;并在短时间内新增100万用户&#xff1f; 传统营销的痛点…

真香!3个月0基础转型大厂数据分析师,他做对了什么?

年初的黑天鹅打乱了我的求职阵脚&#xff0c;专业不对口&#xff0c;无实习经验&#xff0c;在求职路上的竞争优势几乎为0&#xff0c;然而&#xff0c;开启自救模式后&#xff0c;我顺利成为了头条数据分析师&#xff0c;下面我就讲讲人生是怎么开挂的。随着人工智能普及&…