实时消息推送系统,写得太好了!
websocket 协议是在 http 协议上的一种补充协议,是 html5 的新特性,是一种持久化的协议。其实 websocket 和 http 关系并不是很大,不过都是属于应用层的协议,接下来我们就开始实战。
websocket 定时推送
本教程基于 springboot 为脚手架,没使用过 springboot 同学可以看往期文章,或者直接去 spring 官网拉一个 springboot 基础项目下来。
加入依赖
在 springboot 的项目中添加一下 webSocket 依赖,一般一项新技术的引入在 springboot 中也只是引用一个此技术 starter 的依赖,其他配置基本 springboot 帮我们解决了。
-
<dependency> -
<groupId>org.springframework.boot</groupId> -
<artifactId>spring-boot-starter-websocket</artifactId> -
</dependency>
配置
新建一个 Java 配置类,注入 ServerEndpointExporter 配置,如果是使用 springboot 内置的 tomcat 此配置必须,如果是使用的是外部 tomcat 容器此步骤请忽略。看 spring 源码中这样描述,使用此配置可以关闭 servlet 容器对 websocket 端点的扫描,这个暂时没有深入研究。
-
@Configuration -
public class WebSocketConfig { -
@Bean -
public ServerEndpointExporter serverEndpointExporter() { -
return new ServerEndpointExporter(); -
} -
}
核心代码
接下来最核心的类其实就是提供一个前后端交互的类实现消息的接收推送。
-
@ServerEndpoint(value = "/wsdemo") 前端通过此 URI 和后端交互,建立连接
-
@Component 不用说将此类交给 spring 管理
-
@OnOpen websocket 建立连接的注解,前端触发上面 URI 时会进入此注解标注的方法,和之前关于 DWR 文章中的 onpage 方法类似
-
@OnClose 顾名思义关闭连接,销毁 session
-
@OnMessage 收到前端传来的消息后执行的方法
-
@ServerEndpoint(value = "/wsdemo") -
@Component -
public class MyWebSocket { -
private static int onlineCount = 0; -
private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>(); -
private Session session; -
@OnOpen -
public void onOpen(Session session) { -
this.session = session; -
webSocketSet.add(this); -
addOnlineCount(); -
System.out.println("有新连接加入!当前在线人数为" + getOnlineCount()); -
try { -
sendMessage("连接已建立成功."); -
} catch (Exception e) { -
System.out.println("IO异常"); -
} -
} -
@OnClose -
public void onClose() { -
webSocketSet.remove(this); -
subOnlineCount(); -
System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount()); -
} -
@OnMessage -
public void onMessage(String message, Session session) { -
System.out.println("来自客户端的消息:" + message); -
} -
@OnError -
public void onError(Session session, Throwable error) { -
System.out.println("发生错误"); -
error.printStackTrace(); -
} -
public void sendMessage(String message) throws IOException { -
this.session.getBasicRemote().sendText(message); -
} -
public static synchronized int getOnlineCount() { -
return onlineCount; -
} -
public static synchronized void addOnlineCount() { -
MyWebSocket.onlineCount++; -
} -
public static synchronized void subOnlineCount() { -
MyWebSocket.onlineCount--; -
} -
public Session getSession() { -
return session; -
} -
public void setSession(Session session) { -
this.session = session; -
} -
public static CopyOnWriteArraySet<MyWebSocket> getWebSocketSet() { -
return webSocketSet; -
} -
public static void setWebSocketSet(CopyOnWriteArraySet<MyWebSocket> webSocketSet) { -
MyWebSocket.webSocketSet = webSocketSet; -
} -
}
定时任务
使用 spring 的 Schedule 建立定时任务
-
@EnableScheduling 开启 spring 定时任务功能
-
@Scheduled(cron = "0/10 * * * * ?") 用于标识定时执行的方法,此处主要方法返回值一定是 void,没有入参。对应定时时间配置可以百度 cron 语法,根据自己的业务选择合适的周期
在这类中,我们通过上面 MyWebSocket 提供的静态方法获取其中的 webSocketSet ,来获取所有此业务相关的所有 websocketsession,可以在定时任务中对 session 内容进行验证判断(权限验证等),进行发送消息
-
@Component -
@EnableScheduling -
public class TimeTask -
{ -
private static Logger logger = LoggerFactory.getLogger(TimeTask.class); -
@Scheduled(cron = "0/1 * * * * ?") -
public void test(){ -
System.err.println("********* 定时任务执行 **************"); -
CopyOnWriteArraySet<MyWebSocket> webSocketSet = -
MyWebSocket.getWebSocketSet(); -
int i = 0 ; -
webSocketSet.forEach(c->{ -
try { -
c.sendMessage(" 定时发送 " + new Date().toLocaleString()); -
} catch (IOException e) { -
e.printStackTrace(); -
} -
}); -
System.err.println("/n 定时任务完成......."); -
} -
}
前端页面
前端页面可以参考使用,主要要更改调用的 url 为自己项目 URL
-
<!DOCTYPE HTML> -
<html> -
<head> -
<title>My WebSocket</title> -
</head> -
<body> -
Welcome<br/> -
<input type="text" /><button onclick="send()">Send</button> <button onclick="closeWebSocket()">Close</button> -
<div> -
</div> -
</body> -
<script type="text/javascript"> -
var websocket = null; -
//判断当前浏览器是否支持WebSocket ,主要此处要更换为自己的地址 -
if('WebSocket' in window){ -
websocket = new WebSocket("ws://localhost:8886/wsdemo"); -
} -
else{ -
alert('Not support websocket') -
} -
//连接发生错误的回调方法 -
websocket.onerror = function(){ -
setMessageInnerHTML("error"); -
}; -
//连接成功建立的回调方法 -
websocket.onopen = function(event){ -
setMessageInnerHTML("open"); -
} -
//接收到消息的回调方法 -
websocket.onmessage = function(event){ -
setMessageInnerHTML(event.data); -
} -
//连接关闭的回调方法 -
websocket.onclose = function(){ -
setMessageInnerHTML("close"); -
} -
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 -
window.onbeforeunload = function(){ -
websocket.close(); -
} -
//将消息显示在网页上 -
function setMessageInnerHTML(innerHTML){ -
document.getElementById('message').innerHTML += innerHTML + '<br/>'; -
} -
//关闭连接 -
function closeWebSocket(){ -
websocket.close(); -
} -
//发送消息 -
function send(){ -
var message = document.getElementById('text').value; -
websocket.send(message); -
} -
</script> -
</html>
效果演示

最后说一句(求关注!别白嫖!)
如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、转发、在看。
关注公众号:woniuxgg,在公众号中回复:笔记 就可以获得蜗牛为你精心准备的java实战语雀笔记,回复面试、开发手册、有超赞的粉丝福利!
相关文章:
实时消息推送系统,写得太好了!
websocket 协议是在 http 协议上的一种补充协议,是 html5 的新特性,是一种持久化的协议。其实 websocket 和 http 关系并不是很大,不过都是属于应用层的协议,接下来我们就开始实战。 websocket 定时推送 本教程基于 springboot …...
泛微E9开发 控制日期浏览按钮的可选日期范围
控制日期浏览按钮的可选日期范围 1、需求说明2、实现方法3、扩展知识点控制日期浏览按钮的可选日期范围格式参数说明演示 1、需求说明 控制日期浏览按钮的可选日期范围为2024/07/01~2024/07/31,如下图所示 2. 控制日期浏览按钮的可选日期范围在当前时间的前一周~当…...
ppt接单渠道大公开‼️
PPT 接单主要分两种:PPT 模板投稿和PPT 定制接单,我们先从简单的 PPT 模板投稿说起。 PPT 模板投稿 利用业余时间,做一些 PPT 模板上传到平台,只要有人下载你的模板,你就有收入。如果模板质量高,简直就是一…...
从零开始搭建vite开发环境
准备 nodejs 18 pnpm https://vitejs.cn/ 开始 pnpm init pnpm add -D vite新建index.html <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width…...
FastAPI本身是一个高性能的Web框架
FastAPI本身是一个高性能的Web框架,它并不直接支持数据库操作,但可以通过集成各种数据库库来与各种数据库进行交互。FastAPI支持几乎所有的关系型数据库和非关系型数据库,这主要取决于你选择的数据库库(如ORM库)以及相…...
yolov7:训练自己的数据集和测试
1、源代码:DataXujing/YOLOv7: :fire::fire::fire: Official YOLOv7训练自己的数据集并实现端到端的TensorRT模型加速推断 (github.com)2、参考的文献:⭐YOLOv7训练自己的数据集(全网最详细 亲测有效)⭐_python_Sunny&Meng-开…...
Redis 集群模式
文章目录 前言1. Redis Cluster 搭建1.1 准备节点1.2 准备配置文件1.3 查看集群状态 2. 客户端访问3. Python 连接集群4. Redis 集群维护4.1 新增节点4.2 手动分配 slot4.3 节点移除 5. 集群运维5.1 集群倾斜5.2 手动切换 前言 Redis 3.0 提供了 Redis Cluster 架构࿰…...
如何快速实现一个无缝轮播效果
🧑💻 写在开头 点赞 收藏 学会🤣🤣🤣 需求简介 轮播图是我们前端开发中的一个常见需求,在项目开发中,我们可以使用element、ant等UI库实现。某些场景,为了一个简单的功能安装一…...
kubernetes集群证书过期问题解决
kubernetes集群证书过期问题解决 问题描述检查证书是否过期更新证书master节点操作node节点操作 问题描述 K8S 各个组件需要与 api-server 进行通信,通信使用的证书都存放在 /etc/kubernetes/pki 路径下,kubeadm 生成的证书大部分默认有效期为 1 年&…...
PHP框架详解-symfony框架
Symfony是一个使用PHP语言编写的开源Web应用框架,旨在加快开发进程,替代重复编码工作,并帮助构建可维护和可扩展的应用程序。以下是对Symfony框架的详细解析: 一、框架概述 Symfony提供了一组可重用的组件和一个标准化、可扩展的…...
Linux--线程的控制
目录 0.前言 1.pthread库 2.关于控制线程的接口 2.1.创建线程(pthread_create) 2.2.线程等待(pthread_join) 代码示例1: 编辑 ***一些问题*** 2. 3.创建多线程 3.线程的终止 (pthread_exit /…...
大数据------JavaWeb------会话跟踪技术(Cookie、Session)(完整知识点汇总)
会话跟踪技术(Cookie&Session) 注意: HTTP协议是无状态 的,即每次浏览器向服务器请求时,服务器都会将该请求视为新的请求,因此我们需要会话跟踪技术来实现会话内的数据共享 会话 当用户打开浏览器&am…...
crossJoin笛卡尔积
crossJoin笛卡尔积 在Spark中,crossJoin方法用于执行两个数据集之间的笛卡尔积操作。具体来说,如果有两个数据集(DataFrame或Dataset),调用crossJoin方法将会生成一个新的数据集,其中包含两个原始数据集中所…...
Java客户端调用SOAP方式的WebService服务实现方式分析
简介 在多系统交互中,有时候需要以Java作为客户端来调用SOAP方式的WebService服务,本文通过分析不同的调用方式,以Demo的形式,帮助读者在生产实践中选择合适的调用方式。 本文JDK环境为JDK17。 结论 推荐使用Axis2或者Jaxws&#…...
华为机试真题--字符串序列判定
题目描述: 输入两个字符串S和L,都只包含英文小写字母,其中S长度<=100,L长度<=500000,请判定S是否是L的有效字串。 判定规则: S中的每个字符在L中都能找到(可以不连续),且S在L中字符的前后顺序与S中顺序要保持一致。(例如,S="ace"是L="abcd…...
Linux内核 -- 虚拟化之virtqueue结构
Linux Kernel中的Virtqueue Virtqueue是Linux Kernel中用于实现Virtio设备的一个关键数据结构。Virtio是一种虚拟I/O设备标准,旨在简化虚拟化环境中虚拟设备与虚拟机之间的通信。Virtqueue则是实现这种通信的核心机制。以下是Virtqueue的一些关键点: V…...
【pytorch18】Logistic Regression
回忆线性回归 for continuous:y xwbfor probability output:yσ(xwb) σ:sigmoid or logistic 线性回归是简单的线性模型,输入是x,网络参数是w和b,输出是连续的y的值 如何把它转化为分类问题?加了sigmoid函数,输出的值不再是…...
PostgreSQL的使用
PostgreSQL的使用 1.首先,使用docker进行安装pgvector数据库,具体的安装步骤可以查看我之前发的博文。 2.docker exec -it pgvector /bin/bash 进入docker容器内部,操作数据库,上述命令是以交互式命令进入了容器的内部…...
python 高级技巧 0706
python 33个高级用法技巧 列表推导式 简化了基于现有列表创建新列表的过程。 squares [x**2 for x in range(10)] print(squares)[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]字典推导式 用简洁的方式创建字典。 square_dict {x: x**2 for x in range(10)} print(square_dict){0…...
面试经典 106. 从中序与后序遍历序列构造二叉树
最近小胖开始找工作了,又来刷苦逼的算法了 555 废话不多说,看这一题,上链接:https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/description/?envTypestudy-plan-v2&envIdtop-inte…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
