实时消息推送系统,写得太好了!
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…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
Vue ③-生命周期 || 脚手架
生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...
Android写一个捕获全局异常的工具类
项目开发和实际运行过程中难免会遇到异常发生,系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler,它是Thread的子类(就是package java.lang;里线程的Thread)。本文将利用它将设备信息、报错信息以及错误的发生时间都…...
