WebSocket简易聊天室实现(有详细解释)

 完整代码

Arata08/online-chat-demo

服务端:

1.编写配置类,扫描有 @ServerEndpoint 注解的 Bean

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}

解释:
@Configuration 注解表示该类是一个配置类,用于定义Spring容器中的bean。配置类可以替代传统的XML配置文件,通过Java代码来声明和管理bean。
@ServerEndpointExporter 是Spring WebSocket提供的一个类,用于自动注册使用 @ServerEndpoint 注解标注的WebSocket端点。它会扫描应用程序中的所有 @ServerEndpoint 注解的类,并将它们注册为WebSocket端点。

2.编写配置类,用于获取 HttpSession 对象

import jakarta.servlet.http.HttpSession;
import jakarta.websocket.HandshakeResponse;
import jakarta.websocket.server.HandshakeRequest;
import jakarta.websocket.server.ServerEndpointConfig;
/*** 获取HttpSession,这样的话,ChatEndpoint类就能操作HttpSession*/
public class GetHttpSessionConfig extends ServerEndpointConfig.Configurator {@Overridepublic void modifyHandshake(ServerEndpointConfig serverEndpointConfig, HandshakeRequest request, HandshakeResponse response) {// 获取 HttpSession 对象HttpSession httpSession = (HttpSession) request.getHttpSession();// 将 httpSession 对象保存起来,存到 ServerEndpointConfig 对象中// 在 ChatEndpoint 类的 onOpen 方法就能通过 EndpointConfig 对象获取在这里存入的数据serverEndpointConfig.getUserProperties().put(HttpSession.class.getName(), httpSession);}
}

解释:

EndpointConfig端点配置类使用-CSDN博客文章浏览阅读2次。接口位于包中,它是Java WebSocket API(JSR 356)的一部分。Spring WebSocket框架也提供了对这个接口的支持。https://blog.csdn.net/m0_61160520/article/details/143819154?fromshare=blogdetail&sharetype=blogdetail&sharerId=143819154&sharerefer=PC&sharesource=m0_61160520&sharefrom=from_link

modifyHandshake 方法在WebSocket握手过程中被调用。它允许你在握手阶段修改 ServerEndpointConfig 对象,并访问HTTP请求和响应对象。这个方法的签名如下:

public void modifyHandshake(ServerEndpointConfig serverEndpointConfig, HandshakeRequest request, HandshakeResponse response)
  • serverEndpointConfig:当前WebSocket端点的配置对象。
  • request:握手请求对象,包含客户端发起握手请求的信息。
  • response:握手响应对象,包含服务器对握手请求的响应信息。

3.注册一个WebSocket端点类

解释:https://blog.csdn.net/m0_61160520/article/details/143818152?fromshare=blogdetail&sharetype=blogdetail&sharerId=143818152&sharerefer=PC&sharesource=m0_61160520&sharefrom=from_linkicon-default.png?t=O83Ahttps://blog.csdn.net/m0_61160520/article/details/143818152?fromshare=blogdetail&sharetype=blogdetail&sharerId=143818152&sharerefer=PC&sharesource=m0_61160520&sharefrom=from_link

import cn.edu.scau.config.GetHttpSessionConfig;
import cn.edu.scau.utils.MessageUtils;
import cn.edu.scau.websocket.pojo.Message;
import com.alibaba.fastjson2.JSON;
import jakarta.servlet.http.HttpSession;
import jakarta.websocket.*;
import jakarta.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;@ServerEndpoint(value = "/chat", configurator = GetHttpSessionConfig.class)
@Component
public class ChatEndpoint {// 保存在线的用户,key为用户名,value为 Session 对象private static final Map<String, Session> onlineUsers = new ConcurrentHashMap<>();private HttpSession httpSession;/*** 建立websocket连接后,被调用** @param session Session*/@OnOpenpublic void onOpen(Session session, EndpointConfig config) {this.httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());String user = (String) this.httpSession.getAttribute("currentUser");if (user != null) {onlineUsers.put(user, session);}// 通知所有用户,当前用户上线了String message = MessageUtils.getMessage(true, null, getFriends());broadcastAllUsers(message);}private Set<String> getFriends() {return onlineUsers.keySet();}private void broadcastAllUsers(String message) {try {Set<Map.Entry<String, Session>> entries = onlineUsers.entrySet();for (Map.Entry<String, Session> entry : entries) {// 获取到所有用户对应的 session 对象Session session = entry.getValue();// 使用 getBasicRemote() 方法发送同步消息session.getBasicRemote().sendText(message);}} catch (Exception exception) {exception.printStackTrace();}}/*** 浏览器发送消息到服务端时该方法会被调用,也就是私聊* 张三  -->  李四** @param message String*/@OnMessagepublic void onMessage(String message) {try {// 将消息推送给指定的用户Message msg = JSON.parseObject(message, Message.class);// 获取消息接收方的用户名String toName = msg.getToName();String tempMessage = msg.getMessage();// 获取消息接收方用户对象的 session 对象Session session = onlineUsers.get(toName);String currentUser = (String) this.httpSession.getAttribute("currentUser");String messageToSend = MessageUtils.getMessage(false, currentUser, tempMessage);session.getBasicRemote().sendText(messageToSend);} catch (Exception exception) {exception.printStackTrace();}}/*** 断开 websocket 连接时被调用** @param session Session*/@OnClosepublic void onClose(Session session) throws IOException {// 1.从 onlineUsers 中删除当前用户的 session 对象,表示当前用户已下线String user = (String) this.httpSession.getAttribute("currentUser");if (user != null) {Session remove = onlineUsers.remove(user);if (remove != null) {remove.close();}session.close();}// 2.通知其他用户,当前用户已下线// 注意:不是发送类似于 xxx 已下线的消息,而是向在线用户重新发送一次当前在线的所有用户String message = MessageUtils.getMessage(true, null, getFriends());broadcastAllUsers(message);}}

客户端

1.创建一个 axios 实例

向后端发送登录请求需要使用这个 axios 实例

import axios from 'axios'const request = axios.create({baseURL: '/api',timeout: 60000,headers: {'Content-Type': 'application/json;charset=UTF-8'}
})request.interceptors.request.use()request.interceptors.response.use(response => {if (response.data) {return response.data}return response
}, (error) => {return Promise.reject(error)
})export default request

2.编写代理规则

vite.config.js

import {fileURLToPath, URL} from 'node:url'import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'// https://vitejs.dev/config/
export default defineConfig({plugins: [vue()],resolve: {alias: {'@': fileURLToPath(new URL('./src', import.meta.url))}},server: {proxy: {'/api': {target: 'http://localhost:7024',changeOrigin: true,rewrite: (path) => {return path.replace('/api', '')}}}}
})

3.创建 WebSocket 对象

webSocket.value = new WebSocket('ws://localhost:7024/chat')

4.为 WebSocket 对象绑定事件

webSocket.value.onopen = onOpen// 接收到服务端推送的消息后触发
webSocket.value.onmessage = onMessagewebSocket.value.onclose = onClose

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

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

相关文章

Excel超级处理器:高效实现2种批量生成二维码方式

在Excel数据处理中&#xff0c;二维码的批量生成是一个常见且重要的需求。借助Excel超级处理器这一强大的插件&#xff0c;用户可以轻松实现二维码的两种主要批量生成方式&#xff1a;直接在单元格中显示二维码图片&#xff0c;以及直接生成二维码图片并保存在文件夹中。超级处…

Linux Android 正点原子RK3568替换开机Logo完整教程

0.这CSDN是有BUG吗?大家注意:表示路径的2个点号全都变成3个点号啦! 接下来的后文中,应该是2个点都被CSDN变成了3个点: 1.将这两个 bmp 图片文件720x1280_8bit拷贝到内核源码目录下,替换内核源码中默认的 logo 图片。注意:此时还缺少电量显示图片 2.编译内核 make d…

性能高于Transformer模型1.7-2倍,彩云科技发布基于DCFormer架构通用大模型云锦天章

2017年&#xff0c;谷歌发布《Attention Is All You Need》论文&#xff0c;首次提出Transformer架构&#xff0c;掀开了人工智能自然语言处理&#xff08;NLP&#xff09;领域发展的全新篇章。Transformer架构作为神经网络学习中最重要的架构&#xff0c;成为后来席卷全球的一…

函数指针示例

目录&#xff1a; 代码&#xff1a; main.c #include <stdio.h> #include <stdlib.h>int Max(int x, int y); int Min(int x, int y);int main(int argc, char**argv) {int x,y;scanf("%d",&x);scanf("%d",&y);int select;printf(&q…

【书生大模型实战营 闯关材料】入门岛:第4关 玩转HF/魔搭/魔乐社区

2.1.2-2.1.3 InternLM 模型下载 模型下载 使用Hugging Face平台、魔搭社区平台&#xff08;可选&#xff09;和魔乐社区平台&#xff08;可选&#xff09;下载文档中提到的模型&#xff08;至少需要下载config.json文件、model.safetensors.index.json文件&#xff09;&#x…

Android - Pixel 6a 手机OS 由 Android 15 降级到 Android 14 操作记录

Pixel 6a 手机由 Android 14 升级到 Android 15了&#xff0c;但是由于一些原因又想降级回 Android 14&#xff0c; 能降吗&#xff1f;该怎么降级呢&#xff1f;本篇文章来记述实际操作过程&#xff0c;希望能给想做相同操作的人一些帮助。 答案当然是能降&#xff0c;而且我…

python-文件内容操作

文章目录 文件的介绍文件的理解文件操作基本知识文件对象属性与常用方法文件的读取文件的写入**上下文管理语句 with****读CSV文件**二维数据的存储从CSV格式的文件中读取数据将数据写入CSV格式的文件 读取Excel格式数据文件(pandas库)读取Excel格式数据文件(pandas库) 文件的介…

《操作系统 - 清华大学》3 -3:连续内存分配:内存碎片与分区的动态分配

文章目录 0. 概述1. 内存碎片问题2. 动态分配3. 首次适配算法4. 最优适配算法5. 最差适配算法 0. 概述 内存分配是操作系统管理过程中很重要的环节&#xff0c;首先需要考虑的是一块连续区域分配的过程&#xff0c;这个过程中会有很多问题&#xff0c;首先比较关注的一个问题是…

7.高可用集群架构Keepalived双主热备原理

一. 高可用集群架构Keepalived双主热备原理 (1)主机+备机keepalived配置(192.168.1.171) ! Configuration File for keepalivedglobal_defs {# 路由id:当前安装keepalived节点主机的标识符,全局唯一router_id keep_101 } #计算机节点(主机配置) vrrp_instance VI_1 {</

Notepad++的完美替代

由于Notepad的作者曾发表过可能在开发者代码中植入恶意软件的言论&#xff0c;他备受指责。在此&#xff0c;我向大家推荐一个Notepad的完美替代品——NotepadNext和Notepad--。 1、NotepadNext NotepadNext的特点&#xff1a; 1、跨平台兼容性 NotepadNext基于Electron或Qt…

【Chapter 3】Machine Learning Classification Case_Prediction of diabetes-XGBoost

文章目录 1、XGBoost Algorithm2、Comparison of algorithm implementation between Python code and Sentosa_DSML community edition(1) Data reading and statistical analysis(2)Data preprocessing(3)Model Training and Evaluation(4)Model visualization 3、summarize 1…

Linux(CentOS)安装达梦数据库 dm8

CentOS版本&#xff1a;CentOS 7&#xff0c;查看操作系统版本信息&#xff0c;请查阅 查看Linux内核版本信息 达梦数据库版本&#xff1a;dm8 一、获取 dm8 安装文件 1、下载安装文件 打开达梦官网&#xff1a;https://www.dameng.com/ 下载的文件 解压后的文件 2、上传安…

ReactPress与WordPress:两大开源发布平台的对比与选择

ReactPress与WordPress&#xff1a;两大开源发布平台的对比与选择 在当今数字化时代&#xff0c;内容管理系统&#xff08;CMS&#xff09;已成为各类网站和应用的核心组成部分。两款备受欢迎的开源发布平台——ReactPress和WordPress&#xff0c;各自拥有独特的优势和特点&am…

前后端请求响应

引入 在之前的例子中&#xff0c;我们编写了一个简单的web类&#xff0c;我们运行启动类&#xff0c;启动内嵌的tomcat后就可以在浏览器通过特定的路径访问tomcat中的应用程序。 但之前编写的程序仅仅是个简单的java类&#xff0c;其并未实现某个接口或继承某个类&…

Ubuntu24 上安装搜狗输入法

link 首先在终端中依次输入以下代码 sudo apt update sudo apt install fcitx 找到语言支持 在终端中依次输入 sudo cp /usr/share/applications/fcitx.desktop /etc/xdg/autostart/ sudo apt purge ibus 进入网页 搜狗输入法linux-首页​ shurufa.sogou.com/linux 找到刚才下…

Linux从0——1之shell编程4

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&a…

嵌入式硬件杂谈(二)-芯片输入接入0.1uf电容的本质(退耦电容)

引言&#xff1a;对于嵌入式硬件这个庞大的知识体系而言&#xff0c;太多离散的知识点很容易疏漏&#xff0c;因此对于这些容易忘记甚至不明白的知识点做成一个梳理&#xff0c;供大家参考以及学习&#xff0c;本文主要针对芯片输入接入0.1uf电容的本质的知识点的进行学习。 目…

树莓派4B Qt+FFMPEG 多线程录制USB相机mjpeg数据流“h264_omx“硬件编码的MP4文件

文章目录 1 前言2 一些问题说明2.0 树莓派4b系统版本2.1 Qt2.2 FFMPEG2.3 图像格式 3 核心代码3.0 代码逻辑3.1 pro文件3.2 avframequeue.cpp3.3 decodethread.cpp 4 资源下载 1 前言 本项目为在树莓派4B开发板上&#xff0c;通过QtFFMPEG以多线程分别解码、编码USB摄像头视频数…

Cartographer激光雷达slam -20241116

Cartographer Cartographer代码结构 cartographer&#xff1a;负责处理来自雷达、IMU和里程计的数据并基于这些数据进行地图的构建&#xff0c;是cartographer理论的底层实现cartographer_ros&#xff1a;基于ros的通信机制获取传感器的数据并将它们转换成cartographer中定义…

Scratch 014生日贺卡(上)

知识回顾&#xff1a; 1、“面向鼠标指针”积木块 2、“重复执行直到”积木块 本次分享制作生日贺卡引入广播模块 案列效果&#xff1a; 生日贺卡上案例效果-CSDN直播 步骤拆解&#xff1a; 1、添加背景和角色 2、编辑贺卡造型添加名字 3、流程图的组成和画法 4、…