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

news2024/11/25 12:29:32

一、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<>();

    /**
     * 与服务器连接成功
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        log.info("客户端成功建立连接:{}", session.getId());
        sessionList.add(session);
    }

    /**
     * 接受客户端的消息
     */
    @Override
    public 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));
            }
        }
    }

    /**
     * 通讯异常
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        log.error("通讯出现异常");
    }

    /**
     * 连接关闭
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        log.info("连接关闭");
    }

    /**
     * 是否允许分段发送
     */
    @Override
    public 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 {

    @Autowired
    private SystemWebSocketHandler handler;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        // 设置WebSocket服务器地址 ws://localhost:8080/SpringBootWebSocket
        registry.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;
            }
            // 判断当前浏览器是否支持WebSocket
            if ('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.coloradmin.cn/o/912807.html

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

相关文章

MyBatis plus 多数据源实现

1. 项目背景 最近写文章发布到【笑小枫】小程序和我的个人网站上&#xff0c;因为个人网站用的是halo框架搭建&#xff0c;两边数据结构不一致&#xff0c;导致我每次维护文章都需要两边维护&#xff0c;这就很烦~ 于是&#xff0c;本文就诞生了。通过项目连接这两个数据库&a…

CQ课堂 | 社区版 2.3.0 新功能操作演示直播快来预约!

CloudQuery 一体化数据库操作管控云平台&#xff0c;社区版 V 2.3.0 已发布&#xff01; 三大核心功能增强 1、 权限管控&#xff1a;新增自动授权、分级授权 2、 动态脱敏&#xff1a;新增脱敏配置导入导出、脱敏扫描 3、 审计中心&#xff1a;新增上卷下钻能力、审计归档 …

【3D激光SLAM】LOAM源代码解析--transformMaintenance.cpp

系列文章目录 【3D激光SLAM】LOAM源代码解析–scanRegistration.cpp 【3D激光SLAM】LOAM源代码解析–laserOdometry.cpp 【3D激光SLAM】LOAM源代码解析–laserMapping.cpp 【3D激光SLAM】LOAM源代码解析–transformMaintenance.cpp 写在前面 本系列文章将对LOAM源代码进行讲解…

微积分入门(3)—— 近似值与微分的定义

例零 微分 言归正传&#xff0c;我们今天先来谈谈近似值 此“近似值”非彼“近似值”&#xff0c;大部分人现在想到的绝对是“四舍五入”。 所以我们今天偏偏就不讲四舍五入&#xff0c;为什么呢&#xff1f; 还记得我们上次说的极小变化量吗&#xff1f;在任意小的变化中&…

AWVS安装~Windows~激活

目录 1.下载安装包 2.双击acunetix_15.1.221109177.exe进行安装 3.配置C:\Windows\System32\drivers\etc\hosts 4.复制wvsc.exe到C:\Program Files (x86)\Acunetix\15.1.221109177下 5.复制license_info.json与wa_data.dat到C:\ProgramData\Acunetix\shared\license下&…

Python爬虫库之urllib使用详解

一、Python urllib库 Python urllib 库用于操作网页 URL&#xff0c;并对网页的内容进行抓取处理。 Python3 的 urllib。 urllib 包 包含以下几个模块&#xff1a; urllib.request - 打开和读取 URL。 urllib.error - 包含 urllib.request 抛出的异常。 urllib.parse - 解…

【云原生微服务九】SpringCloud之Feign实现声明式客户端负载均衡详细案例

文章目录 一、Feign概述1、为什么会使用Feign代替Ribbon2、Feign和OpenFeign的区别&#xff1f; 二、Feign实现负载均衡0、最上层父项目spring-cloud-center的pom.xml文件1、搭建服务注册中心eureka-server1、pom.xml2、修改配置文件application.yml3、修改启动类4、启动eureka…

Java将PDF文件转为Word文档

Java将PDF文件转为Word文档 一、创建Springboot Maven项目 二、导入依赖信息 <repositories><repository><id>com.e-iceblue</id><url>https://repo.e-iceblue.cn/repository/maven-public/</url></repository></repositories&g…

错误代码0x80004005要怎么解决?快速修复的方法分享

错误代码0x80004005是Windows操作系统中常见的错误之一&#xff0c;它经常出现在执行某些操作时或在使用特定的应用程序时。这个错误代码可能有多种原因导致&#xff0c;如文件损坏、访问权限问题、网络连接故障等。本文将介绍几种常见的修复方法来解决错误代码0x80004005&…

arcgis:画一幅自己城市的shp地图

首先打开ArcGis10.6&#xff0c;点击带黄底的小加号&#xff0c;添加底图。 可以选择中国地图彩色版&#xff0c;然后双击&#xff0c;转动鼠标滑轮找到属于自己的城市。 点击-目录&#xff0c;在新建的文件夹里右击-新建-shapefile。 格式选择折线&#xff0c;先把主要河流道路…

Airtest框架(跨平台自动化测试框架)

目录 Airtest与Poco airtest IDE界面 poco窗口 airtest窗口 airtest常用方法 连接设备 安卓命令等操作 安卓按键操作 设备状态获取 录屏 windows设备常用操作 生成airtest报告 Airtest与Poco Airtest是基于Python的跨平台UI自动化测试框架&#xff0c;基于图像识…

14款奔驰R400升级ACC自适应巡航系统,解放双脚缓解驾驶疲劳

有的时候你是否厌倦了不停的刹车、加油&#xff1f;是不是讨厌急刹车&#xff0c;为掌握不好车距而烦恼&#xff1f;如果是这样&#xff0c;那么就升级奔驰原厂ACC自适应式巡航控制系统&#xff0c;带排队自动辅助和行车距离警报功能&#xff0c;感受现代科技带给你的舒适安全和…

【leetcode 力扣刷题】反转链表+递归求解

反转链表递归求解 206. 反转链表解法①&#xff1a;取下一个节点在当前头节点前插入解法②&#xff1a;反转每个节点next的指向解法③&#xff1a;递归 92.反转链表Ⅱ反转left到right间节点的next指向 234.回文链表解法①&#xff1a;将链表元素存在数组中&#xff0c;在数组上…

python接口自动化之如何使用requests库发送http请求

前言 今天笔者想和大家来聊聊python接口自动化如何使用requests库发送http请求&#xff0c;废话呢笔者就不多说了&#xff0c;直接进入正题。 一、requests库 什么是Requests &#xff1f;Requests 是⽤Python语⾔编写&#xff0c;基于urllib&#xff0c;采⽤Apache2 Licens…

大数据 算法

什么是大数据 大数据是指数据量巨大、类型繁多、处理速度快的数据集合。这些数据集合通常包括结构化数据&#xff08;如数据库中的表格数据&#xff09;、半结构化数据&#xff08;如XML文件&#xff09;和非结构化数据&#xff08;如文本、音频和视频文件&#xff09;。大数据…

跨境电商独立站创业路线?怎么做外贸网站?

跨境电商独立站创业需要做哪些准备?创建国际贸易自主网站的流程&#xff1f; 跨境电商独立站创业&#xff0c;正逐渐成为许多创业者的首选。这一领域蕴藏着巨大的商机&#xff0c;同时也需要创业者具备坚定的决心和深入的市场洞察力。下面将为您详细介绍一条成功的跨境电商独…

科技云报道:云计算下半场,公有云市场生变,私有云风景独好

科技云报道原创。 大数据、云计算、人工智能&#xff0c;组成了恢弘的万亿级科技市场。这三个领域&#xff0c;无论远观近观&#xff0c;都如此性感和魅力&#xff0c;让一代又一代创业者为之杀伐攻略。 然而高手过招往往一瞬之间便已胜负知晓&#xff0c;云计算市场的巨幕甫…

网络安全应急管理与技术实践:应对不断演化的网络威胁

&#x1f482; 个人网站:【工具大全】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 当谈论网络安全应急管理…

基于web的服装商城系统java网上购物商店jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 基于web的服装商城系统 系统有1权限&#xff1a;前台…

优化学习体验的在线考试系统

随着互联网的发展&#xff0c;在线教育逐渐成为学习的主要方式之一。在线考试系统作为在线教育的重要组成部分&#xff0c;对于学习者提供了更为便捷和灵活的学习方式。但是&#xff0c;如何优化学习体验&#xff0c;提高学习效果&#xff0c;仍然是在线考试系统需要解决的问题…