Spring Boot + Netty + WebSocket 实现消息推送
1、关于Netty
Netty 是一个利用 Java 的高级网络的能力,隐藏其背后的复杂性而提供一个易于使用的 API 的客户端/服务器框架。
2、Maven依赖
<dependencies><!-- https://mvnrepository.com/artifact/io.netty/netty-all --><dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.36.Final</version></dependency>
</dependencies>
3、SpringBootApplication
启动器中需要new一个NettyServer,并显式调用启动netty。
@SpringBootApplication
public class SpringCloudStudyDemoApplication {public static void main(String[] args) {SpringApplication.run(SpringCloudStudyDemoApplication.class,args);try {new NettyServer(12345).start();System.out.println("https://blog.csdn.net/moshowgame");System.out.println("http://127.0.0.1:6688/netty-websocket/index");}catch(Exception e) {System.out.println("NettyServerError:"+e.getMessage());}}
}
4、NettyServer
启动的NettyServer,这里进行配置
/*** NettyServer Netty服务器配置*/
public class NettyServer {private final int port;public NettyServer(int port) {this.port = port;}public void start() throws Exception {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup group = new NioEventLoopGroup();try {ServerBootstrap sb = new ServerBootstrap();sb.option(ChannelOption.SO_BACKLOG, 1024);sb.group(group, bossGroup) // 绑定线程池.channel(NioServerSocketChannel.class) // 指定使用的channel.localAddress(this.port)// 绑定监听端口.childHandler(new ChannelInitializer<SocketChannel>() { // 绑定客户端连接时候触发操作@Overrideprotected void initChannel(SocketChannel ch) throws Exception {System.out.println("收到新连接");//websocket协议本身是基于http协议的,所以这边也要使用http解编码器ch.pipeline().addLast(new HttpServerCodec());//以块的方式来写的处理器ch.pipeline().addLast(new ChunkedWriteHandler());ch.pipeline().addLast(new HttpObjectAggregator(8192));ch.pipeline().addLast(new WebSocketServerProtocolHandler("/ws", null, true, 65536 * 10));ch.pipeline().addLast(new MyWebSocketHandler());}});ChannelFuture cf = sb.bind().sync(); // 服务器异步创建绑定System.out.println(NettyServer.class + " 启动正在监听:" + cf.channel().localAddress());cf.channel().closeFuture().sync(); // 关闭服务器通道} finally {group.shutdownGracefully().sync(); // 释放线程池资源bossGroup.shutdownGracefully().sync();}}
}
5、MyChannelHandlerPool
通道组池,管理所有websocket连接
/*** MyChannelHandlerPool* 通道组池,管理所有websocket连接*/
public class MyChannelHandlerPool {public MyChannelHandlerPool(){}public static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
}
6、MyWebSocketHandler
处理ws一下几种情况:
channelActive与客户端建立连接
channelInactive与客户端断开连接
channelRead0客户端发送消息处理
/*** NettyServer Netty服务器配置*/
public class NettyServer {private final int port;public NettyServer(int port) {this.port = port;}public void start() throws Exception {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup group = new NioEventLoopGroup();try {ServerBootstrap sb = new ServerBootstrap();sb.option(ChannelOption.SO_BACKLOG, 1024);sb.group(group, bossGroup) // 绑定线程池.channel(NioServerSocketChannel.class) // 指定使用的channel.localAddress(this.port)// 绑定监听端口.childHandler(new ChannelInitializer<SocketChannel>() { // 绑定客户端连接时候触发操作@Overrideprotected void initChannel(SocketChannel ch) throws Exception {System.out.println("收到新连接");//websocket协议本身是基于http协议的,所以这边也要使用http解编码器ch.pipeline().addLast(new HttpServerCodec());//以块的方式来写的处理器ch.pipeline().addLast(new ChunkedWriteHandler());ch.pipeline().addLast(new HttpObjectAggregator(8192));ch.pipeline().addLast(new WebSocketServerProtocolHandler("/ws", "WebSocket", true, 65536 * 10));ch.pipeline().addLast(new MyWebSocketHandler());}});ChannelFuture cf = sb.bind().sync(); // 服务器异步创建绑定System.out.println(NettyServer.class + " 启动正在监听:" + cf.channel().localAddress());cf.channel().closeFuture().sync(); // 关闭服务器通道} finally {group.shutdownGracefully().sync(); // 释放线程池资源bossGroup.shutdownGracefully().sync();}}
}
7、socket.html
主要是连接ws,发送消息,以及消息反馈
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>Netty-Websocket</title><script type="text/javascript">// by zhengkai.blog.csdn.netvar socket;if(!window.WebSocket){window.WebSocket = window.MozWebSocket;}if(window.WebSocket){socket = new WebSocket("ws://127.0.0.1:12345/ws");socket.onmessage = function(event){var ta = document.getElementById('responseText');ta.value += event.data+"\r\n";};socket.onopen = function(event){var ta = document.getElementById('responseText');ta.value = "Netty-WebSocket服务器。。。。。。连接 \r\n";};socket.onclose = function(event){var ta = document.getElementById('responseText');ta.value = "Netty-WebSocket服务器。。。。。。关闭 \r\n";};}else{alert("您的浏览器不支持WebSocket协议!");}function send(message){if(!window.WebSocket){return;}if(socket.readyState == WebSocket.OPEN){socket.send(message);}else{alert("WebSocket 连接没有建立成功!");}}</script>
</head>
<body>
<form onSubmit="return false;"><label>ID</label><input type="text" name="uid" value="${uid!!}" /> <br /><label>TEXT</label><input type="text" name="message" value="这里输入消息" /> <br /><br /> <input type="button" value="发送ws消息"onClick="send(this.form.uid.value+':'+this.form.message.value)" /><hr color="black" /><h3>服务端返回的应答消息</h3><textarea id="responseText" style="width: 1024px;height: 300px;"></textarea>
</form>
</body>
</html>
8、Controller
写好了html当然还需要一个controller来引导页面。
@RestController
public class IndexController {@GetMapping("/index")public ModelAndView index(){ModelAndView mav=new ModelAndView("socket");mav.addObject("uid", RandomUtil.randomNumbers(6));return mav;}
}
9、改造netty支持url参数
1.首先,调整一下加载handler的顺序,优先MyWebSocketHandler在WebSocketServerProtocolHandler之上。
ch.pipeline().addLast(new MyWebSocketHandler());
ch.pipeline().addLast(new WebSocketServerProtocolHandler("/ws", null, true, 65536 * 10));
2.其次,改造MyWebSocketHandler 的channelRead方法,首次连接会是一个FullHttpRequest类型,可以通过FullHttpRequest.uri()获取完整ws的URL地址,之后接受信息的话,会是一个TextWebSocketFrame类型。
public class MyWebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("与客户端建立连接,通道开启!");//添加到channelGroup通道组MyChannelHandlerPool.channelGroup.add(ctx.channel());}@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {System.out.println("与客户端断开连接,通道关闭!");//添加到channelGroup 通道组MyChannelHandlerPool.channelGroup.remove(ctx.channel());}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {//首次连接是FullHttpRequest,处理参数 by zhengkai.blog.csdn.netif (null != msg && msg instanceof FullHttpRequest) {FullHttpRequest request = (FullHttpRequest) msg;String uri = request.uri();Map paramMap=getUrlParams(uri);System.out.println("接收到的参数是:"+JSON.toJSONString(paramMap));//如果url包含参数,需要处理if(uri.contains("?")){String newUri=uri.substring(0,uri.indexOf("?"));System.out.println(newUri);request.setUri(newUri);}}else if(msg instanceof TextWebSocketFrame){//正常的TEXT消息类型TextWebSocketFrame frame=(TextWebSocketFrame)msg;System.out.println("客户端收到服务器数据:" +frame.text());sendAllMessage(frame.text());}super.channelRead(ctx, msg);}@Overrideprotected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {}private void sendAllMessage(String message){//收到信息后,群发给所有channelMyChannelHandlerPool.channelGroup.writeAndFlush( new TextWebSocketFrame(message));}private static Map getUrlParams(String url){Map<String,String> map = new HashMap<>();url = url.replace("?",";");if (!url.contains(";")){return map;}if (url.split(";").length > 0){String[] arr = url.split(";")[1].split("&");for (String s : arr){String key = s.split("=")[0];String value = s.split("=")[1];map.put(key,value);}return map;}else{return map;}}
}
3.html中的ws地址也进行改造
socket = new WebSocket("ws://127.0.0.1:12345/ws?uid=666&gid=777");
4.改造后控制台输出情况
收到新连接
与客户端建立连接,通道开启!
接收到的参数是:{"uid":"666","gid":"777"}
/ws
客户端收到服务器数据:142531:这里输入消息
客户端收到服务器数据:142531:这里输入消息
客户端收到服务器数据:142531:这里输入消息
failed: WebSocket opening handshake timed out
相关文章:

Spring Boot + Netty + WebSocket 实现消息推送
1、关于Netty Netty 是一个利用 Java 的高级网络的能力,隐藏其背后的复杂性而提供一个易于使用的 API 的客户端/服务器框架。 2、Maven依赖 <dependencies><!-- https://mvnrepository.com/artifact/io.netty/netty-all --><dependency><gr…...

Python3 【字符串】:方法和函数使用示例手册
Python3 【字符串】:方法和函数使用示例手册 Python 提供了丰富的字符串处理方法和函数,以下是一些常用的方法和函数分类整理,并提供详细使用示例,简单易懂,值得收藏。 1. 字符串大小写转换 str.upper():…...

数据结构与算法整理复习(一):数据结构概念与线性表
目录 第一章:绪论 1.1 数据结构的基本概念 1.2 算法与算法评价 第二章:线性表 2.1 线性表的定义和基本操作 2.2 线性表的顺序表示(顺序表) 应用题 2.3 线性表的链式表达(链表) 2.3.1 单链表 2.3.2…...

【Block总结】PConv风车卷积,更大的感受野,提高特征提取能力|即插即用
论文信息 论文标题:《Pinwheel-shaped Convolution and Scale-based Dynamic Loss for Infrared Small Target Detection》 论文链接:https://arxiv.org/pdf/2412.16986 GitHub链接:https://github.com/JN-Yang/PConv-SDloss-Data 创新点 …...

Python新春烟花
目录 系列文章 写在前面 技术需求 完整代码 下载代码 代码分析 1. 程序初始化与显示设置 2. 烟花类 (Firework) 3. 粒子类 (Particle) 4. 痕迹类 (Trail) 5. 烟花更新与显示 6. 主函数 (fire) 7. 游戏循环 8. 总结 注意事项 写在后面 系列文章 序号直达链接爱…...

VirtualBox can‘t enable the AMD-V extension
个人博客地址:VirtualBox cant enable the AMD-V extension | 一张假钞的真实世界 最近一次完成Deepin的系统更新后,进入VirtualBox创建的虚拟机(Widows10)时,出现以下错误: 根据网址“https://askubuntu.…...

掘金--创意标题匹配问题
问题描述 在广告平台中,为了给广告主一定的自由性和效率,允许广告主在创造标题的时候以通配符的方式进行创意提交。线上服务的时候,会根据用户的搜索词触发的 bidword 对创意中的通配符(通配符是用成对 {} 括起来的字符串&#x…...

OBU和T-Box
OBU(On-Board Unit,车载单元)和T-Box(Telematics Box,远程信息处理控制单元)都是用于车联网和智能交通系统的车载设备,但它们的功能、应用场景和技术特点存在显著差异。以下是两者的详细对比&am…...

【PVE】Proxmox VE8.0+创建LXC容器安装docker
为了不影响PVE宿主机,通常使用套娃的形式安装Docker容器,再安装相关docker应用。首先在CT模板中创建 Linux 容器,推荐使用Debian。开启ssh登录,修改debian配置,安装docker 一、创建 LXC 容器 1、CT模板下载 点击“模…...

一文大白话讲清楚webpack基本使用——11——chunkIds和runtimeChunk
文章目录 一文大白话讲清楚webpack基本使用——11——chunkIds和runtimeChunk1. 建议按文章顺序从头看,一看到底,豁然开朗2. 啥是chunkIds3.怎么使用chunkIds4. 啥是runtimeChunk5. 怎么使用runtimeChunk 一文大白话讲清楚webpack基本使用——11——chun…...

Java 中的设计模式:经典与现代实践
Java 中的设计模式:经典与现代实践 1. 设计模式简介 设计模式是一种软件开发中的思想,它为我们提供了一些经过验证的、能够应对常见问题的解决方案。学习和掌握设计模式能够让开发者在面对复杂的需求时,能够设计出更加灵活、可维护的代码。…...

DRG_DIP 2.0时代医院程序结构转型与数据结构优化研究
一、引言 1.1 DRG_DIP 2.0 改革背景与意义 医保支付方式改革在医疗保障制度改革中占据着极为关键的地位,是推动医疗领域变革的核心力量。它犹如一把精准的手术刀,对医疗资源的合理分配、医疗服务质量的稳步提升以及医疗费用的有效控制起着决定性作用。…...

一部手机如何配置内网电脑同时访问内外网
做过运维的朋友都知道,最麻烦的是运维电脑不能远程,每次都得现场进行维护,明明客户那边有可以访问内网的电脑,怎么操作能将这台电脑能访问跟到外网呢,这样不就能通过远程软件远程了吗?嘿嘿。按以下步骤试试…...

国产低功耗带LCD驱动和触摸按键功能的MCU
以下是国产低功耗、集成LCD驱动和触摸按键功能的MCU精选型号及其核心特性,结合性能、功耗和适用场景进行综合推荐: 1.灵动微MM32L0130系列 257 核心特性:低功耗:待机模式功耗低至100nA,支持多种低功耗模式。 LCD驱动&a…...

XCP 协议基础
文章目录 一、XCP 简介二、XCP的主要功能三、什么是标定四、什么时候进行标定五、标定的意义六、标定的三层架构XCP协议 和 CCP协议的区别参考 一、XCP 简介 XCP 协议的全称为 eXtended Calibration Protocol,即扩展标定协议。 另有其他定义,XCP 协议全…...

Swift 中 Codable 和 Hashable 的理解
最近初学Swift,碰到下面的代码脑袋里冒出疑问:Codable 和 Hashable是啥?怎么理解? struct Landmark: Hashable, Codable {var id: Intvar name: Stringvar park: Stringvar state: Stringvar description: String }针对上面的疑问…...

基于 WPF 平台实现成语游戏
一、引言 在软件开发领域,利用各种框架开发有趣的应用程序是提升技术能力和增加开发乐趣的有效方式。WPF(Windows Presentation Foundation)作为微软强大的桌面应用开发框架,提供了丰富的图形和交互功能。本文将带领大家基于 WPF…...

2024“博客之星”——我的博客成长与技术洞察
🌟欢迎来到 我的博客 —— 探索技术的无限可能! 🌟博客的简介(文章目录) 目录 一、引言二、个人成长与突破盘点(一)技能提升与知识拓展(二)创作风格与影响力提升…...

HTTPS协议简述
HTTPS 协议简介 HTTPS 是 HTTP Security 的组合,即在 HTTP 的基础上加入了安全性机制,主要通过加密传输、身份认证和数据完整性保护来确保通信的安全性。 为了实现这一目标,HTTPS 引入了 加密技术,包括对称加密、非对称加密和数…...

前沿技术趋势洞察:2024年技术的崭新篇章与未来走向!
引言 时光飞逝,2024年已经来临,回顾过去一年,科技的迅猛进步简直让人目不暇接。 在人工智能(AI)越来越强大的今天,我们不再停留在幻想阶段,量子计算的雏形开始展示它的无穷潜力,Web …...

HTML常用属性
HTML标签的常见属性包括许多不同的功能,可以为元素提供附加信息或控制元素的行为。以下是一些常见的属性及其解释: 1. src 描述:src(source)属性指定一个资源的路径,通常用于图像、音频、视频等标签。常见…...

电子应用设计方案100:智能家庭AI电风扇系统设计
智能家庭 AI 电风扇系统设计 一、引言 智能家庭 AI 电风扇系统旨在为用户提供更加舒适、便捷和个性化的吹风体验,通过融合人工智能技术和先进的控制算法,实现智能化的风速调节、风向控制和场景适应。 二、系统概述 1. 系统目标 - 实现精准的风速调节&a…...

ThinkPHP 8请求处理-获取请求对象与请求上下文
【图书介绍】《ThinkPHP 8高效构建Web应用》-CSDN博客 《2025新书 ThinkPHP 8高效构建Web应用 编程与应用开发丛书 夏磊 清华大学出版社教材书籍 9787302678236 ThinkPHP 8高效构建Web应用》【摘要 书评 试读】- 京东图书 使用Composer初始化ThinkPHP 8应用_thinkphp8 compos…...

工厂模式 - 工厂方法模式、抽象工厂模式
引言 工厂模式(Factory Pattern)是设计模式中创建型模式的一种,它提供了一种创建对象的最佳方式。工厂模式的核心思想是将对象的创建与使用分离,使得代码更加灵活、可扩展。工厂模式主要分为两种:工厂方法模式和抽象工…...

2025年已过6%
前些阵子,注意到一个网站的年度进度条显示今年已完成4%的进度,而今天是1月22日,再一看已过去6%。如果1个月按30天来计算,1个月也就占一年1/12,差不多在8%-9%左右。 也许你会感觉这6%过得很快,也许你会感觉这…...

C#,入门教程(04)——Visual Studio 2022 数据编程实例:随机数与组合
上一篇: C#,入门教程(03)——Visual Studio 2022编写彩色Hello World与动画效果https://blog.csdn.net/beijinghorn/article/details/123478581 C#,入门教程(01)—— Visual Studio 2022 免费安装的详细图文与动画教程https://blog.csdn.net…...

UWB高精度定位技术在智能仓储中的应用
在智能化和数字化转型的浪潮中,UWB高精度定位系统逐渐成为企业优化仓储管理和生产调度的关键技术。结合RFID标签打印机和服装生产型ERP软件,这一技术为企业带来了全新的管理方式和效率提升。 UWB高精度定位系统的核心优势 UWB(超宽带&…...

计算机毕业设计hadoop+spark视频推荐系统 短视频推荐系统 视频流量预测系统 短视频爬虫 视频数据分析 视频可视化 视频大数据 大数据
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...

【AI编辑器】字节跳动推出AI IDE——Trae,专为中文开发者深度定制
目录 一、背景 二、核心特性 2.1 AI驱动的代码自动生成 2.2 智能问答与代码补全 2.3 多语言支持 2.4 插件与扩展 三、架构 四、下载使用 4.1 下载与安装 4.2 界面与配置 五、应用实践 5.1 快速生成代码 5.2 智能问答与调试 5.3 团队协作与代码审查 六、与Cursor…...

CSDN 博客之星 2024:默语的技术进阶与社区耕耘之旅
CSDN 博客之星 2024:默语的技术进阶与社区耕耘之旅 🌟 默语,是一位在技术分享与社区建设中坚持深耕的博客作者。今年,我有幸再次入围成为 CSDN 博客之星TOP300 的一员,这既是对过往努力的肯定,也是对未来探…...