Java - WebSocket配置及使用
引入依赖
Spring Boot 默认支持 WebSocket,但需要引入 spring-boot-starter-websocket 依赖,然后重新构建项目
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
搭建 WebSocket 服务
创建 WebSocketServer.java
package com.project.module.webSocket;import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Service;import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;@Service
@ServerEndpoint("/ws/{userId}") // WebSocket 连接端点
public class WebSocketServer {// 存储所有用户的 WebSocket 连接private static final Map<String, WebSocketServer> clients = new ConcurrentHashMap<>();private Session session;private String userId; // 当前连接的用户ID@OnOpenpublic void onOpen(Session session, @PathParam("userId") String userId) {this.session = session;this.userId = userId;clients.put(userId, this);System.out.println("新客户端连接,当前在线用户:" + clients);}@OnMessagepublic void onMessage(String message) {System.out.println("收到消息:" + message);// 假设消息格式是 "userId:message"String[] parts = message.split(":", 2);if (parts.length == 2) {String targetUserId = parts[0];String msg = parts[1];sendToUser(targetUserId, "私信:" + msg);} else {System.out.println("无效的消息格式:" + message);}}// @OnMessage
// public void onMessage(String message, @PathParam("userId") String userId) {
// System.out.println("收到消息:" + message);
// sendToUser(userId, "私信:" + message);
// }// 给指定用户发送消息public void sendToUser(String userId, Object messageObject) {WebSocketServer client = clients.get(userId);System.out.println("当前用户:" + userId);if (client != null) {try {// 使用 Jackson 转换对象为 JSONObjectMapper objectMapper = new ObjectMapper();String jsonMessage = objectMapper.writeValueAsString(messageObject);client.session.getBasicRemote().sendText(jsonMessage);} catch (IOException e) {e.printStackTrace();}} else {System.out.println("用户 " + userId + " 不在线,消息未发送");}}@OnClosepublic void onClose() {for (Map.Entry<String, WebSocketServer> entry : clients.entrySet()) {if (entry.getValue().session.getId().equals(session.getId())) {clients.remove(entry.getKey());System.out.println("客户端断开连接,当前在线人数:" + clients.size());break;}}}@OnErrorpublic void onError(Session session, Throwable error) {error.printStackTrace();}public void sendToAll(Object messageObject) {for (Map.Entry<String, WebSocketServer> entry : clients.entrySet()) {WebSocketServer client = entry.getValue();try {// 使用 Jackson 转换对象为 JSONObjectMapper objectMapper = new ObjectMapper();String jsonMessage = objectMapper.writeValueAsString(messageObject);client.session.getBasicRemote().sendText(jsonMessage);} catch (IOException e) {e.printStackTrace();}}}public Map<String, WebSocketServer> getClients() {return clients;}
}
手动注册 WebSocket
@ServerEndpoint 不能直接用 @Autowired 注入 Spring Bean,所以需要 手动注册
在 WebSocketConfig 里添加 Bean
创建 WebSocketConfig.java:
package com.project.module.webSocket;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.websocket.server.ServerEndpointConfig;
import javax.websocket.server.ServerEndpointExporter;@Configuration
public class WebSocketConfig {// 启动 WebSocket 服务器@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}
发送Websocket服务
package com.project.module.webSocket;import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;@Component
public class WebSocketTask {private final WebSocketServer webSocketServer;public WebSocketTask(WebSocketServer webSocketServer) {this.webSocketServer = webSocketServer;}// 每一分钟推送一次消息@Scheduled(fixedRate = 1000*60)public void pushMessage() {webSocketServer.sendToUser("userId","定时任务推送消息:" + System.currentTimeMillis());}
}
前端链接 WebSocket
创建 webSocket.js
注:此处的 import {host} from './base.js'为引入的全局服务地址,例如 host 为 localhost ,开发者可自行更换为自己的 WebSocket 地址
import {host} from './base.js'
const WebSocketService = {ws: null,connect(userId, callback) {this.ws = new WebSocket(`ws://${host}:8980/ws/` + userId);this.ws.onopen = () => {console.log("WebSocket 连接成功");};this.ws.onmessage = (event) => {callback(JSON.parse(event.data));};this.ws.onclose = () => {console.log("WebSocket 连接已关闭");};},sendMessage(message) {if (this.ws && this.ws.readyState === WebSocket.OPEN) {this.ws.send(message);}},disconnect() {if (this.ws) {this.ws.close();}},
};export default WebSocketService;
在Vue组将中使用
<template><div class="container"></div>
</template><script setup>
import { onMounted, ref } from "vue";
import WebSocketService from "@/utils/websocket";const CURRENT_CHART_NAME = 'safety'
const safetyRef = ref()
let safetyChart = nullconst { setChart } = useSetChart()onMounted(() => {websocketConn()
})function websocketConn() {const userId = `userId`WebSocketService.connect(userId, (msg) => {console.log(msg)});
}
</script>
注:此处的userId对应后端 webSocketServer.sendToUser("userId ","定时任务推送消息:" + System.currentTimeMillis()); 中的 userId,代表前端订阅WebSocket消息的用户以及WebSocket要发送的用户
相关文章:
Java - WebSocket配置及使用
引入依赖 Spring Boot 默认支持 WebSocket,但需要引入 spring-boot-starter-websocket 依赖,然后重新构建项目 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</arti…...
厦门未来之音:科技与自然共舞的奇幻篇章
故事背景 故事发生在中国福建厦门,描绘未来城市中科技与传统文化深度融合的奇景。通过六大创新场景展现人与自然、历史与未来的和谐共生,市民在智能设施中感受文化传承的力量。 故事内容 从鼓浪屿的声波音乐栈道到BRT天桥上的空中茶园,从修复…...
React 列表与 Keys 的深入探讨
React 列表与 Keys 的深入探讨 在 React 中,列表渲染是一个常见的操作,而 Keys 是在列表渲染中一个非常重要的概念。本文将深入探讨 React 列表与 Keys 的关系,帮助开发者更好地理解并运用它们。 引言 React 是一个用于构建用户界面的 JavaScript 库,它的虚拟 DOM 和组件…...
【Python】Python 100题 分类入门练习题 - 新手友好
Python 100题 分类入门练习题 - 新手友好篇 - 整合篇 一、数学问题题目1:组合数字题目2:利润计算题目3:完全平方数题目4:日期天数计算题目11:兔子繁殖问题题目18:数列求和题目19:完数判断题目21…...
2025年Python的主要应用场景
李升伟 编译 Python在2025年仍是最受欢迎和强大的编程语言之一。其简洁易读的语法以及庞大的库生态系统,使其成为各行业开发者的首选。无论是构建复杂的数据管道,还是自动化重复性任务,Python都能提供广泛的应用场景,以实现快速、…...
PyTorch中的Flatten
在 PyTorch 中,Flatten 操作是将多维张量转换为一维向量的重要操作,常用于卷积神经网络(CNN)的全连接层之前。以下是 PyTorch 中实现 Flatten 的各种方法及其应用场景。 一、基本 Flatten 方法 1. 使用 torch.flatten() 函数 import torch# 创建一个4…...
深入浅出动态规划:从基础到蓝桥杯实战(Java版)
引言:为什么你需要掌握动态规划? 动态规划(DP)是算法竞赛和面试中的常客,不仅能大幅提升解题效率(时间复杂度通常为O(n)或O(n))[4],更是解决复杂优化问题的利器。统计显示ÿ…...
VS Code-i18n Ally国际化插件
前言 本文借鉴:i18n Ally 插件帮你轻松搞定国际化需求-按模块划分i18n Ally 是一款 VS Code 插件,它能通过可视 - 掘金本来是没有准备将I18n Ally插件单独写一个博客的,但是了解过后,功能强大,使用方便,解决…...
YOLO中mode.predict()参数详解
Inference arguments: ArgumentTypeDefaultDescriptionsourcestr‘ultralytics/assets’指定推理的数据源。可以是图像路径、视频文件、目录、URL 或实时源的设备 ID。支持多种格式和数据源,可在不同类型的输入中灵活应用。conffloat0.25设置检测的最小置信度阈值。…...
收敛算法有多少?
收敛算法是指在迭代计算过程中,能够使序列或函数逐渐逼近某个极限值或最优解的算法。常见的收敛算法有以下几种: 梯度下降法(Gradient Descent) 原理:通过沿着目标函数的负梯度方向更新参数,使得目标函数…...
在亚马逊云科技上使用n8n快速构建个人AI NEWS助理
前言: N8n 是一个强大的工作流自动化工具,它允许您连接不同的应用程序、服务和系统,以创建自动化工作流程,并且采用了开源MIT协议,可以放心使用,他的官方网站也提供了很多的工作流,大家有兴趣的…...
STM32单片机入门学习——第27节: [9-3] USART串口发送串口发送+接收
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做! 本文写于:2025.04.08 STM32开发板学习——第27节: [9-3] USART串口发送&串口发送接收 前言开发板说…...
python 3.9 随机生成 以UTF-8 编码 的随机中文
理论实践 因为python3的默认编码为UTF-8,我们将‘浪’的utf8\u6d6a进行打印测试 print(\u6d6a) >>浪 中文匹配范围有两种 [\u4e00-\u9fa5]和[\u2E80-\u9FFF],后者包括了日韩地区的汉字 由于utf采用16进制,则需要进行一个进制的变换&a…...
数字电子技术基础(四十)——使用Digital软件和Multisim软件模拟显示译码器
目录 1 使用Digital软件模拟显示译码器 1.1 原理介绍 1.2 器件选择 1.3 电路运行 1.4 结果分析 2 使用Multisim软件模拟显示译码器 2.1 器件选择 2.2 电路运行 1 使用Digital软件模拟显示译码器 1.1 原理介绍 7448常用于驱动7段显示译码器。如下所示为7448驱动BS201A…...
第十四届蓝桥杯大赛软件赛国赛C/C++研究生组
研究生C国赛软件大赛 题一:混乘数字题二:钉板上的正方形题三:整数变换题四:躲炮弹题五:最大区间 题一:混乘数字 有一点像哈希表: 首先定义两个数组,拆分ab和n 然后令n a*b 查看两个…...
innodb如何实现mvcc的
InnoDB 实现 MVCC(多版本并发控制)的机制主要依赖于 Undo Log(回滚日志)、Read View(读视图) 和 隐藏的事务字段。以下是具体实现步骤和原理: 1. 核心数据结构 InnoDB 的每一行数据(…...
多模态大语言模型arxiv论文略读(四)
A Survey on Multimodal Large Language Models ➡️ 论文标题:A Survey on Multimodal Large Language Models ➡️ 论文作者:Shukang Yin, Chaoyou Fu, Sirui Zhao, Ke Li, Xing Sun, Tong Xu, Enhong Chen ➡️ 研究机构: 中国科学技术大学、腾讯优图…...
空对象模式(Null Object Pattern)在C#中的实现详解
一 、什么是空对象模式 空对象模模是靠”空对孔象式是书丯一种引施丼文行为,行凌,凌万成,个默疤"空象象象象来飞䛿引用用用用电从延盈盈甘仙丿引用用用职从延务在仅代砷易行行 」这种燕式亲如要目的片片 也说媚平父如如 核心思烟 定义一个人 派一个 � 创建…...
在kotlin的安卓项目中使用dagger
在 Kotlin 的 Android 项目中使用 Dagger(特别是 Dagger Hilt,官方推荐的简化版)进行依赖注入(DI)可以大幅提升代码的可测试性和模块化程度。 1. 配置 Dagger Hilt 1.1 添加依赖 在 bu…...
(三)链式工作流构建——打造智能对话的强大引擎
上一篇:(二)输入输出处理——打造智能对话的灵魂 在前两个阶段,我们已经搭建了一个基础的智能对话,并深入探讨了输入输出处理的细节。今天,我们将进入智能对话的高级阶段——链式工作流构建。这一阶段的目…...
python三大库之---pandas(二)
python三大库之—pandas(二) 文章目录 python三大库之---pandas(二)六,函数6.1、常用的统计学函数6.2重置索引6.3 遍历6.3.1DataFrame 遍历6.3.2 itertuples()6.3.3 使用属性遍历 6.4 排序6.4.1 sort_index6.4.2 sort_…...
php7.4.3连接MSsql server方法
需要下载安装Microsoft Drivers for PHP for SQL Server驱动, https://download.csdn.net/download/tjsoft/90568178 实操Win2008IISphp7.4.3连接SqlServer2008数据库所有安装包资源-CSDN文库 适用于 SQL Server 的 PHP 的 Microsoft 驱动程序支持与 SQL Server …...
Flask返回文件方法详解
在 Flask 中返回文件可以通过 send_file 或 send_from_directory 方法实现。以下是详细方法和示例: 1. 使用 send_file 返回文件 这是最直接的方法,适用于返回任意路径的文件。 from flask import Flask, send_fileapp = Flask(__name__)@app.route("/download")…...
JS中的Promise对象
基本概念 Promise 是 JavaScript 中用于处理异步操作的对象。它代表一个异步操作的最终完成及其结果值。Promise 提供了一种更优雅的方式来处理异步代码,避免了传统的回调地狱。 Promise 有三种状态 Pending(等待中):初始状态&…...
macOS设置定时播放眼保健操
文章目录 1. ✅方法一:直接基于日历2. 方法二:基于脚本2.1 音乐文件获取(ncm转mp3)2.2 创建播放音乐任务2.3 脚本实现定时播放 1. ✅方法一:直接基于日历 左侧新建一个日历,不然会和其他日历混淆,看起来会有点乱 然后…...
Python 小练习系列 | Vol.14:掌握偏函数 partial,用函数更丝滑!
🧩 Python 小练习系列 | Vol.14:掌握偏函数 partial,用函数更丝滑! 本节的 Python 小练习系列我们将聚焦一个 冷门但高能 的工具 —— functools.partial。它的作用类似于“函数的预设模板”,能帮你写出更加灵活、优雅…...
记录学习的第二十三天
老样子,每日一题开胃。 我一开始还想着暴力解一下试试呢,结果不太行😂 接着两道动态规划。 这道题我本来是想用最长递增子序列来做的,不过实在是太麻烦了,实在做不下去了。 然后看了题解,发现可以倒着数。 …...
Web品质 - 重要的HTML元素
Web品质 - 重要的HTML元素 在构建一个优秀的Web页面时,HTML元素的选择和运用至关重要。这些元素不仅影响页面的结构,还直接关系到页面的可用性、可访问性和SEO表现。本文将深入探讨一些关键的HTML元素,并解释它们在提升Web品质方面的重要性。 1. <html> 根元素 HTM…...
SpringBoot整合sa-token,Redis:解决重启项目丢失登录态问题
SpringBoot整合sa-token,Redis:解决重启项目丢失登录态问题 🔥1. 痛点直击:为什么登录状态会消失?2.实现方案2.1.导入依赖2.2.新增yml配置文件 3.效果图4.结语 😀大家好!我是向阳🌞&…...
Python 字典和集合(子类化UserDict)
本章内容的大纲如下: 常见的字典方法 如何处理查找不到的键 标准库中 dict 类型的变种set 和 frozenset 类型 散列表的工作原理 散列表带来的潜在影响(什么样的数据类型可作为键、不可预知的 顺序,等等) 子类化UserDict 就创造自…...
