springboot集成websocket实现聊天室(极简版)

news2024/9/27 7:17:57

文章目录

  • 前情描述
  • websocket优势
  • 效果展示
  • spring-boot后端
  • html前端代码
  • 资源地址
  • 结语

前情描述

最近想了解websocket的相关原理,于是写了一个极简版的程序,后端使用springboot集成websocket模块,前端手敲了一个html页面(页面很丑很丑很丑,勿喷勿喷),整个程序仅支持简单的websocket通信。

websocket优势

百度百科对websocket的定义是:WebSocket是一种在单个TCP连接上进行全双工通信的协议。
websocket的优势:
1:数据包更小,创建连接后数据包头部较小,减少网络传输的开销,提高了传输效率;
2:实时性更强,webwocket是全双工协议,服务器和客户端可以同时相互发送数据;
3:保持连接状态,websocket创建连接之后,会保持服务器和客户端的联系状态,之后通信可以省略部分状态信息。

效果展示

下面是use_one和user_two的聊天记录:
两个相互发送消息,消息内容会显示在聊天框
在这里插入图片描述

spring-boot后端

一: 依赖
在springboot的基础上引入websocket相关依赖

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

二: 重要代码
1:向springboot容器注入ServerEnpointExporter实例
该实例是spring集成websocket的重要内容,它可以将标注有@ServerEndpoint的类注册到websocket服务器中,从而让客户端可以正常访问到websocket服务器。

@Configuration
public class WebSocketConfig {

    /**
     * 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

2:创建websocket服务器
在类上标注@ServerEnpoint(“/url”),需要注意的是不同的url会由不同的实例来维护,然后需要我们实现@OnOpen【开始链接】,@OnClose【结束链接】,@OnMessage【客户端向服务器发送消息】,@OnError【链接发生错误】注解的方法,这些方法参数会带有一个Session,我们可以将session保存起来,当需要向客户端发送信信息可以调用session.getBasicRemote().sendText(message);

@ServerEndpoint("/person/{userId}")
@Component
@Slf4j
public class WebSocketServer {

    private static Map<String, WebSocketServer> SOCKET_MAP = new ConcurrentHashMap<>();

    @Getter
    private Session session;


    @OnOpen
    public void open(Session session, @PathParam("userId") String userId) {
        this.session = session;
        SOCKET_MAP.put(userId, this);
        log.info("用户{}连接成功,当前链接总人数{}", userId, SOCKET_MAP.size());
    }

    @OnClose
    public void close(Session session, @PathParam("userId") String userId) {
        SOCKET_MAP.remove(userId);
        log.info("用户{}断开连接,当前链接总人数{}", userId, SOCKET_MAP.size());
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("收到用户{}的消息:{}", session.getId(), message);
        ChatEntityStr chatEntity = JSONObject.parseObject(message, ChatEntityStr.class);
        WebSocketServer socketServer = SOCKET_MAP.get(chatEntity.getTo());
        if (null == socketServer) {
            //用户不在线
            log.info("用户{}不在线", chatEntity.getTo());
            return;
        }
        SendHelper.sendToPersonStr(message, socketServer.getSession());
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误:{}", session.getId());
        error.printStackTrace();
    }

}

html前端代码

这里写了两个html,one.html【代表user_one】,two.html【代表user_two】,下面仅展示了one.html,前端代码在项目目录下,one.html和two.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>简易聊天框</title>
    <style type="text/css">
    </style>
</head>
<body>
<div style="flex-direction: column">
    <div>
        <label>
            <textarea rows="3" id="chatMsg" style="height: 500px;width: 500px;resize: none;"></textarea>
        </label>
    </div>
    <div>
        <label>
            <input type="text" style="width: 400px" name="inputMsg" id="inputMsg" onkeyup="inputChange(this.value)">
            <button type="button" onclick="sendMsg()">发送</button>
        </label>
    </div>
</div>
</body>
<script type="application/javascript">
    /**
     * 一般情况下,只需要改动self,other,websocket服务器地址即可使用
     */
    const self = "user_one";
    const other = "user_two";

    const message = {attr: ""};
    const input = document.getElementById("inputMsg");
    const chatMsg = document.getElementById("chatMsg");

    let websocket = {
        send: function (str) {
        }
    };
    window.onload = function () {
        if (!'WebSocket' in window) return;
        webSocketInit();
    };
    //初始化websocket
    function webSocketInit() {
        websocket = new WebSocket("ws://127.0.0.1:7777/person/" + self);
        //成功建立连接
        websocket.onopen = function () {
            linkSuccess(self, self, "链接成功");
        };
        //接收到消息
        websocket.onmessage = function (event) {
            const data = JSON.parse(event.data);
            chatMsg.value = chatMsg.value + data.from + " >>> " + data.message + "\n";
        };
        //连接发生错误
        websocket.onerror = function () {
            alert("WebSocket连接发生错误");
        };
        //连接关闭
        websocket.onclose = function () {
            alert("WebSocket连接关闭");
        };
        //监听窗口关闭事件,当窗口关闭时,主动关闭websocket连接
        window.onbeforeunload = function () {
            websocket.close()
        };
    }

    //对message.attr进行绑定
    Object.defineProperty(message, "attr", {
        configurable: true,
        enumerable: true,
        set: function (newValue) {
            attr = newValue;
            input.value = newValue
        },
        get: function () {
            return attr;
        },
    });
    function inputChange(newValue) {
        message.attr = newValue
        if (event.keyCode === 13 &&
            message.attr !== undefined && message.attr !== null && message.attr.length > 0) {
            sendMsg();
        }
    }

    //发送消息
    function sendMsg() {
        if (message.attr.length <= 0) {
            return
        }
        const msg = {
            from: self,
            to: other,
            createTime: new Date(),
            message: message.attr
        };
        chatMsg.value = chatMsg.value + msg.from + " >>> " + msg.message + "\n";
        websocket.send(JSON.stringify(msg))
        message.attr = ""
    }

    //链接成功
    function linkSuccess(from, to, msg) {
        const successMsg = {
            from: from,
            to: to,
            createTime: new Date(),
            message: msg
        };
        websocket.send(JSON.stringify(successMsg))
    }
</script>
</html>

资源地址

项目地址:https://gitee.com/ryfz-git/springboot-websocket.git

结语

共同学习,共同进步,欢迎交流。

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

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

相关文章

多屏显卡调试

本文依照2017年11月8日一般工作日志改写。 目录 一、显卡选用 二、安装过程 &#xff08;1&#xff09;操作系统&#xff1a; &#xff08;2&#xff09;开机安装驱动 &#xff08;3&#xff09;调整连接线缆 &#xff08;4&#xff09;显卡设置 这是一个LED大屏幕系统&…

秒懂C++之List

目录 前言 一.常用接口展示 二.模拟常用接口 1.1 准备阶段 1.2 push_back 尾插 1.3 insert 插入 1.4 头插 1.5 erase 删除 1.6 clear 清理 析构 1.7 拷贝构造 1.8 赋值拷贝 1.9 反向迭代器 1.10 ->运算符重载 三.全部代码 前言 List其实就是我们前面数据结构学…

AUTOSAR之AUTOSAR OS(上)

1、OSEK OS 1.1 OSEK OS介绍 AUTOSAR OS是基于 OSEK OS发展而来&#xff0c;向下兼容OSEK OS&#xff0c;所以了解AUTOSAR OS之前我们了解一下OSEK OS。 OSEK操作系统&#xff08;OS&#xff09;是一个为分布式嵌入式系统所定义的单核操作系统。为适应汽车电子可靠性、实时性、…

【视觉SLAM】 十四讲ch7习题

简介 本文主要内容是《视觉SLAM十四讲》&#xff08;第二版&#xff09;第7章的习题解答&#xff0c;并介绍了在解答习题中的一下思考和总结的经验。本文代码部分参考了&#xff1a;HW-of-SLAMBOOK2 1、除了本书介绍的ORB特征点&#xff0c;你还能找到哪些特征点&#xff1f;…

Java聚合快递对接云洋系统小程序源码

&#x1f680;【物流新纪元】聚合快递如何无缝对接云洋系统&#xff0c;效率飙升秘籍大公开&#xff01;✨ &#x1f50d; 开篇揭秘&#xff1a;聚合快递的魅力所在 Hey小伙伴们&#xff0c;你是否还在为多家快递公司账号管理繁琐、订单处理效率低下而头疼&#xff1f;&#…

做不好PPT的原因

新手制作PPT长犯的10个错误 1.Word搬家 为了节约时间&#xff0c;直接把Word素材复制粘贴到PPT上&#xff0c;没有提炼 2.堆积图表 每个页面上堆积了大量的图表&#xff0c;却没有说明数据反映了什么趋势 3.图表业余 想用图表达自己的逻辑&#xff0c;但没有专业的模板&a…

【海洋生态环境】十大数据集合集,速看!

本文将为您介绍10个经典、热门的数据集&#xff0c;希望对您在选择适合的数据集时有所帮助。 1 MAI (Multi-scene Aerial Image) 发布方&#xff1a; 不列颠哥伦比亚大学德国航空航天中心慕尼黑大学 发布时间&#xff1a; 2021 简介&#xff1a; MAI 是用于在单个航拍图像中…

【原创】下载RealEstate10K数据集原始视频的方法

前言&#xff1a;目前互联网上能搜到下载RealEstate10K数据集原始视频的方法都已经不能用了&#xff0c;这篇博客介绍一种目前可用的下载RealEstate10K数据集原始视频的方法&#xff0c;并给出自动化的脚本代码。 目录 RealEstate10K简介 RealEstate10K标注文本下载 RealEst…

WhatsApp接不到验证码?快来看这个新功能,绑定邮箱

很多外贸朋友经常会因为WhatsApp接不到验证码来加我问这个解决方案&#xff0c;基本上我会的我都会帮一下忙。最近WhatsApp更新了一个非常实用的功能&#xff0c;绑定电子邮箱的功能&#xff0c;这个功能可以协助进行WhatsApp验证码的接收&#xff0c;下面来看下如何进行绑定吧…

【Linux-Platform】

目录 1. Linux驱动的分离与分层1.1 为什么要进行Linux驱动的分离与分层1.2 Linux驱动的分层 2. 驱动-总线-设备2.1 总线2.2 驱动2.3 设备 3. platform平台设备总线3.1 platform总线注册3.2 platform驱动3.3 platform设备 1. Linux驱动的分离与分层 1.1 为什么要进行Linux驱动的…

【人工智能专栏】基于人类反馈对语言模型进行强化学习 (RLHF)

Reinforcement Learning from Human Feedback (RLHF) 技术分解 字面上说,RLHF就是基于人类反馈(Human Feedback)对语言模型进行强化学习(Reinforcement Learning),和一般的fine-tune过程乃至prompt tuning自然也不同。RLHF 是一项涉及多个模型和不同训练阶段的复杂概念…

C++ 基础入门篇

文章目录 命名空间输入与输出缺省参数函数重载引用和const引用inline&#xff08;内联函数&#xff09; 命名空间 定义&#xff1a;命名空间需要用到namespace关键字&#xff0c;其后跟着命名空间的名字&#xff08;自定义&#xff09;&#xff0c;再接着就是一对花括号&#x…

气膜建筑在工业仓储厂房中的应用优势—轻空间

随着工业生产的快速发展&#xff0c;对仓储厂房的需求日益增长。气膜建筑作为一种新型的建筑形式&#xff0c;因其独特的优势在工业仓储领域逐渐受到青睐。以下是气膜建筑在工业仓储厂房中的主要应用优势。 快速建设与灵活布局 气膜建筑的一个显著优势是其建设速度快&#xff0…

免费分享:2021-2100中国多情景逐年干燥度模拟数据(附下载方法)

AI是表征一个地区干湿程度的指标&#xff0c;一般来说&#xff0c;根据AI分类可以概括地把区域分为湿润&#xff08;AI<1&#xff0c;相当于森林&#xff09;、半湿润&#xff08;AI在1-1.5&#xff0c;相当于森林草原&#xff09;、半干旱&#xff08;AI在1.5-4&#xff0c…

听,LLM在“说话“:智慧农场开启农业知识传播新范式

&#xff08; 于景鑫 国家农业信息化工程技术研究中心&#xff09;设施农业是现代农业的旗舰,集成了环境调控、水肥管理、植保防疫等多项先进技术。据统计,目前全国现代设施种植面积达到4000万亩&#xff0c;效率高、产出高、效益高的特点明显。北方地区每亩蔬菜日光温室年均纯…

十大免费录屏软件推荐:轻松录制高清视频教程

现在视频教程已经成为知识分享、教学演示以及内容创作的重要形式&#xff0c;无论是在线教育、游戏直播还是软件操作指导&#xff0c;高清、流畅的录屏软件都是我们不可获取的工具之一。 但目前市面上有很多录屏软件&#xff0c;哪款才是适合我们的呢&#xff1f;今天就给大家…

前端(vue3)和后端(django)的交互

vue3中&#xff1a; <template><div><h2>注册页面</h2><form submit.prevent"submitForm"><label for"username">用户名&#xff1a;</label><input type"text" id"username" v-model…

C++威力强大的助手 --- const

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; C之旅 const是个奇妙且非比寻常的东西&#xff0c;博主从《Effective C》一书中认识到关于const更深层次的理解&#xff0c;写此博客进行巩固。 &#x…

无人机之运输的优势

无人机在进行运输任务时使用的是电力驱动&#xff0c;从而可以减少对环境的污染和碳排放&#xff0c;对于改善大气质量和减少碳足迹具有积极的意义。 无人机运输可以避免人为错误和事故的发生&#xff0c;通过预先设定的飞行路线&#xff0c;进行精确点投放。此外&#xff0c;还…

零基础小白备考PMP需要多长时间?

PMP考试在中国大陆&#xff0c;平均每三个月安排一次考试。报名缴费一般在考试前两个月&#xff0c;报完名后开始进入备考&#xff0c;所以基本上是2-3个月的时间。 PMP考试备考不是越久越好&#xff0c;把备考战线拉得太长 &#xff0c;我们的精力都是有限的&#xff0c;后期…