SpringBoot+WebSocket搭建多人在线聊天环境

一、WebSocket是什么?

WebSocket是在单个TCP连接上进行全双工通信的协议,可以在服务器和客户端之间建立双向通信通道。

WebSocket 首先与服务器建立常规 HTTP 连接,然后通过发送Upgrade标头将其升级为双向 WebSocket 连接。

WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

二、WebSocket的优点

1.较少的控制开销。在连接创建后,服务器和客户端之间交换数据时,用于控制协议的数据包头部较小。在不包含扩展的情况下,对于服务器到客户端的内容,此头部大小只有2至10字节(和数据包长度有关);对于客户端到服务器的内容,此头部还需要加上额外的4字节的掩码。相对于HTTP请求每次都要携带完整的头部,此项开销显著减少了。

2.更强的实时性。由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于HTTP请求需要等待客户端发起请求服务端才能响应,延迟明显更少;即使是和Comet等类似的长轮询比较,其也能在短时间内更多次地传递数据。

3.保持连接状态。与HTTP不同的是,WebSocket需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息,而HTTP请求可能需要在每个请求都携带状态信息,比如身份认证等。

4.更好的二进制支持。Websocket定义了二进制帧,相对HTTP,可以更轻松地处理二进制内容。

5.可以支持扩展。Websocket定义了扩展,用户可以扩展协议、实现部分自定义的子协议。如部分浏览器支持压缩等。

6.更好的压缩效果。相对于HTTP压缩,Websocket在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以显著地提高压缩率。

三、项目实战

1.引入依赖

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

完整的pom文件如下所示:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.14</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>WebSocketChatDemo</artifactId><version>0.0.1-SNAPSHOT</version><name>WebSocketChatDemo</name><description>WebSocketChatDemo</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--websocket--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><!--lombok插件依赖--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

2.创建SystemWebSocketHandler类

package com.example.websocketchatdemo.websocket;import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;/*** @author qx* @date 2023/8/22* @des WebSocket处理类*/
@Slf4j
@Component
public class SystemWebSocketHandler implements WebSocketHandler {// 存储所有客户端会话private static final List<WebSocketSession> sessionList = new ArrayList<>();/*** 与服务器连接成功*/@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {log.info("客户端成功建立连接:{}", session.getId());sessionList.add(session);}/*** 接受客户端的消息*/@Overridepublic void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {// 获取客户端的消息String msg = message.getPayload().toString();log.info("接收到客户端的消息:{}", msg);sendMsg(msg);}/*** 给所有客户端发送消息** @param msg 消息内容* @throws IOException*/private void sendMsg(String msg) throws IOException {for (WebSocketSession session : sessionList) {if (session.isOpen()) {session.sendMessage(new TextMessage(msg));}}}/*** 通讯异常*/@Overridepublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {log.error("通讯出现异常");}/*** 连接关闭*/@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {log.info("连接关闭");}/*** 是否允许分段发送*/@Overridepublic boolean supportsPartialMessages() {// 一次性发送消息return false;}
}

3.创建WebSocket配置类

这个配置类主要进行跨域的配置。

package com.example.websocketchatdemo.websocket;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;/*** @author qx* @date 2023/8/22* @des WebSocket配置类*/
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebMvcConfigurer, WebSocketConfigurer {@Autowiredprivate SystemWebSocketHandler handler;@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {// 设置WebSocket服务器地址 ws://localhost:8080/SpringBootWebSocketregistry.addHandler(handler, "/SpringBootWebSocket").setAllowedOrigins("*");}
}

4.前台页面编写

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>聊天室</title></head>
<body>
聊天消息内容:
<br/>
<textarea id="chat_content" readonly style="height: 400px;width: 600px"></textarea>
<br/>输入框:
<br/>
<div><textarea id="in_content" placeholder="请输入内容" style="height: 100px;width: 500px"></textarea>
</div>
<button type="button" id="btn_send">发送消息</button>
<br/><br/>
<label>用户:</label>
<div><input type="text" id="in_name" placeholder="请输入姓名"/>
</div>
<br/>
<button type="button" id="btn_join">进入聊天室</button>
<button type="button" id="btn_quit">离开聊天室</button>
<script src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script>
<script>$(function () {var socketUrl = "ws://localhost:8080/SpringBootWebSocket";var ws = null;$("#btn_join").click(function () {if (ws != null) {alert("用户[" + $("#in_name").val() + "]已加入连接");return;}// 判断当前浏览器是否支持WebSocketif ('WebSocket' in window) {ws = new WebSocket(socketUrl)} else {alert("当前浏览器不支持WebSocket");}// 建立连接ws.onopen = function (event) {console.log('与服务器建立连接');ws.send("您的好友[" + $("#in_name").val() + "]上线了");}// 接收服务端返回给前端的消息ws.onmessage = function (event) {$("#chat_content").append(event.data + "\n");}// 连接关闭ws.onclose = function () {console.log("与服务器断开连接")$("#chat_content").append("用户[" + $("#in_name").val() + "]离开聊天室" + "\n");$("#in_name").val("");}});//发送消息$("#btn_send").click(function () {if (ws == null) {alert("该用户不在线");return;}var msg = $("#in_content").val();ws.send("用户[" + $("#in_name").val() + "]:" + msg);})// 离开聊天室$("#btn_quit").click(function () {ws.send("用户[" + $("#in_name").val() + "]离开聊天室!");$("#in_content").val("");ws.close();})})
</script>
</body>
</html>

5.控制器编写

主要编写一个跳转到聊天室的请求

package com.example.websocketchatdemo.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;/*** @author qx* @date 2023/8/22* @des 测试*/
@Controller
@RequestMapping("/chat")
public class IndexController {/*** 跳转到聊天室*/@GetMapping("/index")public String toChat() {return "index";}
}

6.测试

我们启动项目,打开两个聊天页面。

方便设置两个用户加入聊天室

 

 

然后在一个用户中发送消息,我们可以看到两个聊天窗口的消息同步了。

 

 

当一个用户退出聊天室时,会提示用户退出聊天室。

 这个时候另一个用户发送消息只能自己看到了。

 

 如果想测试多个用户,再从新打开一个页面,进入聊天室就可以了。

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

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

相关文章

设计模式(3)抽象工厂模式

一、概述&#xff1a; 1、提供一个创建一系列相关或相互依赖对象的接口&#xff0c;而无须指定它们具体的类。 2、结构图&#xff1a; 3、举例代码&#xff1a; &#xff08;1&#xff09; 实体&#xff1a; public interface IUser {public void insert(User user);public…

亚马逊云科技 云技能孵化营 初识机器学习

目录 前言 一、课程介绍 二、什么是机器学习 三、机器学习算法进阶过程 四、亚马逊云科技能给我们什么 总结 前言 近期参加了“亚马逊云科技 云技能孵化营”&#xff0c;该孵化营的亚马逊云科技培训与认证团队为开发者准备了云从业者的精要知识及入门课程&#xff0c;帮助…

typora的样式的修改

typora首先是一个浏览器&#xff0c; 当我们在typora的设置里面勾选开启调试模式之后&#xff0c; 我们在typora里面右键就会有“检查元素” 这个选项 首先右键 ----》检查元素 将普通字体变颜色 关于Typora修改样式 破解版的typora样式太单调&#xff1f;想让笔记可读性更高…

会计资料基础

会计资料 1.会计要素及确认与计量 1.1 会计基础 1.2 六项会计要素小结 1.3 利润的确认条件 1.3.1 利润的定义和确认条件 1.4 会计要素及确认条件 2.六项会计要素 2.1 资产的特征及其确认条件 这部分资产可以给企业带来经济收益&#xff0c;但是如果不能带来经济利益&#xff…

【jsthreeJS】入门three,并实现3D汽车展示厅,附带全码

首先放个最终效果图&#xff1a; 三维&#xff08;3D&#xff09;概念&#xff1a; 三维&#xff08;3D&#xff09;是一个描述物体在三个空间坐标轴上的位置和形态的概念。相比于二维&#xff08;2D&#xff09;只有长度和宽度的平面&#xff0c;三维增加了高度或深度这一维度…

09 数据库开发-MySQL

文章目录 1 数据库概述2 MySQL概述2.1 MySQL安装2.1.1 解压&添加环境变量2.1.2 初始化MySQL2.1.3 注册MySQL服务2.1.4 启动MySQL服务2.1.5 修改默认账户密码2.1.6 登录MySQL 2.2 卸载MySQL2.3 连接服务器上部署的数据库2.4 数据模型2.5 SQL简介2.5.1 SQL通用语法2.3.2 分类…

excel文本函数篇2

本期主要介绍LEN、FIND、SEARCH以及后面加B的情况&#xff1a; &#xff08;1&#xff09;后缀没有B&#xff1a;一个字节代表一个中文字符 &#xff08;2&#xff09;后缀有B&#xff1a;两个字节代表一个中文字符 1、LEN(text)&#xff1a;返回文本字符串中的字符个数 2、…

vue3——递归组件的使用

该文章是在学习 小满vue3 课程的随堂记录示例均采用 <script setup>&#xff0c;且包含 typescript 的基础用法 一、使用场景 递归组件 的使用场景&#xff0c;如 无限级的菜单 &#xff0c;接下来就用菜单的例子来学习 二、具体使用 先把菜单的基础内容写出来再说 父…

【中危】 Apache NiFi 连接 URL 验证绕过漏洞 (CVE-2023-40037)

漏洞描述 Apache NiFi 是一个开源的数据流处理和自动化工具。 在受影响版本中&#xff0c;由于多个Processors和Controller Services在配置JDBC和JNDI JMS连接时对URL参数过滤不完全。使用startsWith方法过滤用户输入URL&#xff0c;导致过滤可以被绕过。攻击者可以通过构造特…

亚信科技AntDB数据库连年入选《中国DBMS市场指南》代表厂商

近日&#xff0c;全球权威ICT研究与顾问咨询公司Gartner发布了2023年《Market Guide for DBMS, China》&#xff08;即“中国DBMS市场指南”&#xff09;&#xff0c;该指南从市场份额、技术创新、研发投入等维度对DBMS供应商进行了调研。亚信科技是领先的数智化全栈能力提供商…

学习平台助力职场发展与提升

近年来&#xff0c;随着互联网技术的发展&#xff0c;学习平台逐渐成为了职场发展和提升的必备工具。学习平台通过提供丰富的课程内容、灵活的学习时间和个性化的学习路径&#xff0c;帮助职场人士更好地提升自己的技能和知识储备&#xff0c;为职场发展打下坚实的基础。 学习…

redis基本介绍以及在node中使用

文章目录 引言一、什么是redis1. redis简介2. redis的特点3. redis的应用场景 二、redis在windows下安装1. 下载安装2.验证是否安装成功3. 配置环境变量 三、redis-cli常用命令介绍1. redis-cli2. keys *3. set key value4. get key5. exists key6. del key7. info8. flushdb9.…

数据结构与算法:通往编程高地的必修课(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

电商平台按关键字搜索商品淘宝京东拼多多api接口PHP示例

关键词搜索商品接口的作用是通过调用接口来实现在电商平台中进行商品搜索。具体而言&#xff0c;该接口可以提供以下功能和作用&#xff1a; 商品搜索&#xff1a;用户可以通过输入关键词&#xff0c;在电商平台上进行商品搜索。接口可以根据关键词对商品的名称、描述、标签等…

解决OpenFOAM颗粒计算输出文件Paraview无法打开问题(二)

第二个方案的源是在CFD中文网上看到的一篇帖子&#xff0c;其具体链接忘了。这个帖子给了一个github的链接&#xff0c;就是将OpenFOAM输出的颗粒位置信息转变为真实的位置信息的脚本。其链接在此。 1. 背景 我们知道&#xff0c;paraview之所以打不开OF输出的颗粒文件&#…

Python 有趣的模块之pynupt——通过pynput控制鼠标和键盘

写在前面 Python中有许多有趣和强大的模块&#xff0c;其中一个非常有趣的模块就是pynupt。pynupt是基于pynput模块的一个封装&#xff0c;用于控制鼠标和键盘。它可以实现自动化操作和游戏外挂等功能。 本文将详细介绍pynupt模块的使用方法和常见的功能。 1. 安装pynput模块…

Android 14新增复制粘贴方式,解析工作原理

安卓14为用户提供了一种更简单的方式来在应用程序之间复制和粘贴内容&#xff0c;这肯定是你现在想在安卓14测试版或未来几个月该软件在你的安卓手机上推出时尝试的。 一旦更新在你的手机上&#xff08;无论是测试版还是其他版本&#xff09;&#xff0c;你只需点击并按住你想…

【Python机器学习】实验14 手写体卷积神经网络

文章目录 LeNet-5网络结构&#xff08;1&#xff09;卷积层C1&#xff08;2&#xff09;池化层S1&#xff08;3&#xff09;卷积层C2&#xff08;4&#xff09;池化层S2&#xff08;5&#xff09;卷积层C3&#xff08;6&#xff09;线性层F1&#xff08;7&#xff09;线性层F2 …

小程序中的全局配置以及常用的配置项(window,tabBar)

全局配置文件和常用的配置项 app.json: pages:是一个数组&#xff0c;用于记录当前小程序所有页面的存放路径&#xff0c;可以通过它来创建页面 window:全局设置小程序窗口的外观(导航栏&#xff0c;背景&#xff0c;页面的主体) tabBar:设置小程序底部的 tabBar效果 style:是否…

MySQL不停重启问题

MySQL不停的自动杀掉自动重启 看一下log日志 my.cnf 里配置的 log_error /var/log/mysqld.log vim /var/log/mysqld.log 报的错误只是 [ERROR] Cant start server: Bind on TCP/IP port: Address already in use [ERROR] Do you already have another mysqld server …