实现WebSocket聊天室功能

news2024/12/24 8:48:48

实现WebSocket聊天室功能

    • 什么是WebSocket?
    • WebSocket的工作原理
    • 服务器端实现
    • 客户端实现

在现代Web开发中,实时通信已经变得越来越重要。传统的HTTP协议由于其无状态和单向通信的特点,无法很好地满足实时通信的需求。而WebSocket协议则应运而生,提供了全双工的通信能力,非常适合实现诸如聊天室这样的实时应用。在这篇博客中,我们将深入探讨WebSocket的工作原理,并一步步实现一个简单的聊天室应用。

什么是WebSocket?

WebSocket是HTML5的一部分,它为客户端和服务器之间提供了全双工通信通道。与传统的HTTP协议不同,WebSocket允许服务器主动向客户端推送数据,而不仅仅是客户端请求时服务器响应。这使得WebSocket非常适合需要频繁更新的应用,如实时聊天、在线游戏、股票行情等。

WebSocket的工作原理

握手阶段:WebSocket通信从HTTP协议开始,客户端发起一个HTTP请求,通过特殊的头部字段表明要升级到WebSocket协议。服务器响应这个请求,并同意升级协议。
数据传输阶段:握手成功后,客户端和服务器之间建立了一条全双工的通信通道,双方可以通过这个通道随时发送和接收数据。

连接关闭:任何一方都可以随时关闭连接,关闭时双方都会收到一个关闭帧,告知对方连接已经关闭。
实现一个简单的WebSocket聊天室
接下来,我们将使用Node.js和前端JavaScript来实现一个简单的WebSocket聊天室。我们将分为两个部分:服务器端和客户端。

服务器端实现

springboot整合websocket


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


创建MyWebSocketHandler2

/**
 * MyWebSocketHandler2类继承自TextWebSocketHandler,用于处理WebSocket的文本消息。
 * 该类的主要作用是接收客户端发送的文本消息,并将消息内容回显给客户端。
 */

import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

/**
 * @className MyWebSocketHandler2
 * @描述 RuoYi-Vue-Test
 * @Author ljquan
 * @Date 2024/7/2 上午9:43 星期二
 */
@Component(value = "MyWebSocketHandler2")
public class MyWebSocketHandler2 extends TextWebSocketHandler {

    /*
      处理接收到的文本消息。

      @param session WebSocket会话,用于发送和接收消息。
     * @param message 接收到的文本消息对象。
     * @throws Exception 如果处理消息时发生异常。
     */
    /**
     * 当收到文本消息时,该方法会被调用。
     * 主要功能是打印接收到的消息,并发送一个回显消息给客户端。
     *
     * @param session WebSocket会话,用于发送和接收消息。
     * @param message 接收到的文本消息。
     * @throws Exception 如果处理消息时发生错误。
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 提取文本消息的负载部分。
        // 提取消息负载部分。
        String payload = message.getPayload();
        // 打印接收到的消息,用于调试和日志记录。
        // 打印接收到的消息。
        System.out.println("收到客户端的消息2: " + payload);
        // 构造回显消息,并发送给客户端。
        // 回显接收到的消息给客户端。
        session.sendMessage(new TextMessage("张三的ws: " + payload));
    }
}

创建WebSocketConfig配置类

import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

import javax.annotation.Resource;

/**
 * WebSocket配置类,用于配置WebSocket的相关设置。
 * 通过实现WebSocketConfigurer接口,可以自定义WebSocket的处理逻辑和访问路径。
 */
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    /**
     * 注入名为"MyWebSocketHandler"的WebSocketHandler,用于处理WebSocket连接。
     */
    @Resource(name = "MyWebSocketHandler")
    WebSocketHandler MyWebSocketHandler;

    /**
     * 注入名为"MyWebSocketHandler2"的WebSocketHandler,用于处理另一个WebSocket连接。
     * 这种做法可以支持多个不同的WebSocket处理逻辑。
     */
    @Resource(name = "MyWebSocketHandler2")
    WebSocketHandler MyWebSocketHandler2;

    /**
     * 配置WebSocket处理器,将WebSocketHandler与特定的URL路径关联起来。
     * 此方法允许配置多个WebSocket处理路径,并设置允许的来源。
     *
     * @param registry WebSocketHandlerRegistry,用于注册WebSocket处理器和配置访问路径及允许来源。
     */
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        // 将MyWebSocketHandler与路径"/ws"关联,并允许所有来源访问。
        registry.addHandler(MyWebSocketHandler, "/ws").setAllowedOrigins("*");

        // 同样将MyWebSocketHandler2与路径"/ws2"关联,也允许所有来源访问。
        // 这样可以支持不同的WebSocket服务在同一应用中。
        registry.addHandler(MyWebSocketHandler2, "/ws2").setAllowedOrigins("*");
    }
}

客户端实现

创建test.vue

<template>
  <div id="test">
    <h1>聊天室</h1>
    <div class="chat-window">
      <div
          v-for="(message, index) in messages"
          :key="index"
          :class="['message', message.isSelf ? 'self' : 'other']"
      >
        <div class="user-id">{{ message.userId }}</div>
        <div class="message-text">{{ message.text }}</div>
      </div>
    </div>
    <input v-model="inputMessage" @keyup.enter="sendMessage" placeholder="输入消息" />
    <button @click="sendMessage">发送</button>
  </div>
</template>

<script>
import { connectWebSocket, sendMessage } from "@/util/websocket";

export default {
  name: 'TestChat',
  data() {
    return {
      // 存储聊天消息的数组
      messages: [],
      // 输入框的消息内容
      inputMessage: '',
      // 用户ID,用于区分消息发送者
      userId: null
    };
  },
  methods: {
    /**
     * 发送消息方法
     * 当输入框的消息不为空时,发送消息并清空输入框内容
     */
    sendMessage() {
      if (this.inputMessage.trim()) {
        // 发送消息
        sendMessage(JSON.stringify({ userId: this.userId, text: this.inputMessage }));
        // 清空输入框内容
        this.inputMessage = '';
      }
    }
  },
  created() {
    // 初始化用户ID
    this.userId = new Date().getTime();
    // 连接WebSocket,并处理接收到的消息
    connectWebSocket('ws://localhost:54552/ws', (message) => {
      const parsedMessage = JSON.parse(message);
      // 接收到的消息添加到消息数组中,并标记是否为本人发送
      this.messages.push({
        text: parsedMessage.text,
        userId: parsedMessage.userId,
        isSelf: parsedMessage.userId.toString() === this.userId.toString()
      });
    });
  }
};
</script>

<style>
#test {
  text-align: center;
  margin-top: 50px;
}

.chat-window {
  width: 600px;
  height: 400px;
  border: 1px solid #ccc;
  margin: 0 auto;
  padding: 10px;
  overflow-y: scroll;
}

.message {
  margin-bottom: 10px;
  padding: 10px;
  border-radius: 10px;
  max-width: 50%;
}

.self {
  background-color: #daf1da;
  margin-left: auto;
  text-align: right;
}

.other {
  background-color: #f1dada;
  margin-right: auto;
  text-align: left;
}

.user-id {
  font-weight: bold;
  margin-bottom: 5px;
}

.message-text {
  margin-bottom: 10px;
}

input {
  width: 250px;
  padding: 5px;
}

button {
  padding: 5px 10px;
}
</style>

再创建一个脚本js,websocket.js

let socket;

export function connectWebSocket(url, onMessage) {
    socket = new WebSocket(url);

    socket.onopen = function() {
        console.log("WebSocket连接已建立");
    };

    socket.onmessage = function(event) {
        onMessage(event.data);
    };

    socket.onclose = function() {
        console.log("WebSocket连接已关闭");
    };

    socket.onerror = function(error) {
        console.error("WebSocket发生错误: ", error);
    };
}

export function sendMessage(message) {
    if (socket && socket.readyState === WebSocket.OPEN) {
        socket.send(message);
    }
}

然后配置路由

 {path: '/TestChat', name: 'TestChat',  props: true,component: () => import("../views/webSocket/demo/test.vue")},

最后执行前后端,测试得到以下:
在这里插入图片描述

在这里插入图片描述
一般如果使用WebSocket来实现大屏数据的,需要用到定时任务,然后定时可以更新数据后WebSocket连接到客户端。

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

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

相关文章

【java计算机毕设】仓库管理系统 MySQL springboot vue3 Maven 项目源码代码

目录 1项目功能 2项目介绍 3项目地址 1项目功能 【java计算机毕设】仓库管理系统MySQL springboot vue3 Maven小组项目设计源代码 2项目介绍 系统功能&#xff1a; vue3仓库管理系统&#xff0c;主要功能包含&#xff1a;个人信息管理&#xff0c;仓库管理&#xff0c;员工…

【你也能从零基础学会网站开发】理解DBMS数据库管理系统架构,从用户到数据到底经历了什么

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;程序猿、设计师、技术分享 &#x1f40b; 希望大家多多支持, 我们一起学习和进步&#xff01; &#x1f3c5; 欢迎评论 ❤️点赞&#x1f4ac;评论 &#x1f4c2;收藏 &#x1f4c2;加关注 其实前面我们也…

300关卡成语释义典故题库ACCESS\EXCEL数据库

成语典故指关于成语产生、形成、流传的故事传说。成语有很大一部分是从古代相承沿用下来的&#xff0c;它既代表了一个故事典故&#xff0c;又是一种现成的话&#xff0c;很多又有比喻引申意义而被广泛引用。 今天又获得了一个成语游戏的数据&#xff0c;即根据成语典故或者释…

CID引流电商:助力传统电商突破重围实现持续增长

摘要&#xff1a;面临流量成本攀升和市场份额被挤压的挑战&#xff0c;传统电商急需突破重围。CID引流电商通过跨平台引流和精准定位&#xff0c;助力商家实现持续增长&#xff0c;丰富营销手段&#xff0c;创新商业模式。CID引流电商为传统电商的长远发展注入新动力。 在电商…

TFD那智机器人仿真离线程序文本转换为现场机器人程序

TFD式样那智机器人离线程序通过Process Simulation、DELMIA等仿真软件为载体给机器人出离线&#xff0c;下载下来的文本程序&#xff0c;现场机器人一般是无法导入及识别出来的。那么就需要TFD on Desk TFD控制器来进行转换&#xff0c;才能导入现场机器人读取程序。 导入的文…

Lesson 45 The boss‘s letter

Lesson 45 The boss’s letter 词汇 can 能够 n. 罐&#xff0c;听 用法&#xff1a;1. 情态动词&#xff1a;can 动词原形    例句&#xff1a;我能跑。       I can run.    2. a can of … 一罐……    例句&#xff1a;我要一罐可乐。       I wan…

全平台7合一自定义小程序源码系统功能强大 前后端分离 带完整的安装代码包以及搭建教程

系统概述 这款全平台 7 合一自定义小程序源码系统是专为满足各种业务需求而设计的。它整合了多种功能&#xff0c;能够在不同平台上运行&#xff0c;为用户提供了全方位的体验。无论你是企业主、开发者还是创业者&#xff0c;这款系统都能为你提供强大的支持。 代码示例 系统…

手写一个类似@RequestParam的注解(用来接收请求体的参数)

一、本文解决的痛点 按照大众认为的开发规范&#xff0c;一般post类型的请求参数应该传在请求body里面。但是我们有些post接口只需要传入一个字段&#xff0c;我们接受这种参数就得像下面这样单独创建一个类&#xff0c;类中再添加要传入的基本类型字段&#xff0c;配合Reques…

在卷积神经网络(CNN)中为什么可以使用多个较小的卷积核替代一个较大的卷积核,以达到相同的感受野

在卷积神经网络&#xff08;CNN&#xff09;中为什么可以使用多个较小的卷积核替代一个较大的卷积核&#xff0c;以达到相同的感受野 flyfish 在卷积神经网络&#xff08;CNN&#xff09;中&#xff0c;可以使用多个较小的卷积核替代一个较大的卷积核&#xff0c;以达到相同的…

git命令含有中文,终端输出中文乱码的问题

目录 1、[当前代码页] 的936 (ANSI/OEM - 简体中文 GBK) 是导致中文乱码的原因 2、这样会导致什么问题呢&#xff1f; (1) 问题一: 【属性】选项的【字体】无法识别自定义文字样式&#xff0c;【默认值】选项可选自定义字体样式&#xff0c;却无法覆盖【属性】选项 (2) 问题…

还用老气的Excel做报表?试试这款“免费”可视化工具,快速制作3D智慧社区!

随着科技的飞速发展&#xff0c;智慧社区已经成为现代城市管理的重要组成部分。作为这一领域的核心工具&#xff0c;3D智慧社区可视化大屏凭借其先进的技术和强大的功能&#xff0c;正在逐步改变我们的生活方式。今天给大家分享一个 基于山海鲸可视化开发的3D可视化大屏的案例—…

【Flutter】列表流畅性优化

前言 在日常APP的开发中&#xff0c;列表是使用频率最高的&#xff0c;这里讲述在Flutter中优化列表的滑动速度与流畅度&#xff0c;以来提高用户的体验。 方案 1、使用ListView.builder代替ListView ListView.builder在创建列表的时候要比ListView更高效&#xff0c;因为L…

Python题解Leetcode Hot100之二叉树

1. 二叉树的中序遍历 题目描述 给定一个二叉树&#xff0c;返回它的中序遍历。解题思路 使用递归的方法对左子树进行中序遍历&#xff0c;然后访问根节点&#xff0c;最后对右子树进行中序遍历。也可以使用栈来模拟递归的过程&#xff0c;迭代地进行中序遍历。代码class Solut…

机器人控制系列教程之Delta机器人运动学分析(1)

并联机构运动学 对于并联机构的位置正解、位置逆解和对应于位置解的速度、加速度进行分析是并联机构运动学分析主要内容。与串联机构不同&#xff0c;一般并联机构的位置逆解相对要简单&#xff0c;而位置正解则求解比较复杂些。并联机构的位置正解的求解过程中&#xff0c;大…

云徙电商OMS如何赋能品牌电商业务精细化运营

「6.18」、「双十一」、「双十二「、「年货节」等等&#xff0c;如火如荼的「造节」&#xff0c;将电商不断推向高地。 关于电商业务&#xff0c;一个业内共识是&#xff0c;2003 年是线上线下业务切换的关键节点。而消费者需求的变迁是引发这场业务模式革新的核心推手。 盘点…

Crossover和PD虚拟机谁更强大?pd虚拟机一年多少钱

在当前的虚拟化技术和应用程序兼容性解决方案中&#xff0c;Crossover和PD虚拟机&#xff08;Parallels Desktop&#xff09;都是备受用户喜爱的选择。对于需要在非原生系统上运行应用程序的用户而言&#xff0c;选择合适的工具尤为重要。那么&#xff0c;Crossover和PD虚拟机谁…

d3dx9_43.dll丢失怎么解决?d3dx9_43.dll怎么安装详细教程

在使用计算机中&#xff0c;如果遇到d3dx9_43.dll丢失或许找不到d3dx9_43.dll无法运行打开软件怎么办&#xff1f;这个是非常常见问题&#xff0c;下面我详细介绍一下d3dx9_43.dll是什么文件与d3dx9_43.dll的各种问题以及d3dx9_43.dll丢失的多个解决方法&#xff01; 一、d3dx9…

vue3+ts 写echarts 中国地图

需要引入二次封装的echarts和在ts文件写的option <template><div class"contentPage"><myEcharts :options"chartOptions" class"myEcharts" id"myEchartsMapId" ref"mapEcharts" /></di…

vscode语言模式

1.背景 写vue3ts项目的时候&#xff0c;用到了volar插件&#xff0c;在单文件使用的时候&#xff0c;鼠标悬浮在代码上面会有智能提示&#xff1b; 但是最近volar插件提示被弃用了&#xff0c;然后我按照它的官方提示&#xff0c;安装了Vue-official扩展插件&#xff0c;但是…

【开发篇】明明配置跨域声明,为什么却仍可以发送HTTP请求

一、问题 在SpringBoot项目中&#xff0c;明确指定仅允许指定网站跨域访问&#xff1a; 为什么开发人员却仍旧可以通过HTTP工具调用接口&#xff1f; 二、为什么 在回答这个问题之前&#xff0c;我们首先要了解一下什么是CORS&#xff01; 1、什么是CORS CORS的全称为跨域资源…