55、基于 WebFlux 开发 WebSocKet

★ 基于Web Flux开发WebSocket

两步:
(1)实现WebSocketHandler开发WebSocket处理类。

实现该接口时只需要实现Mono handle(WebSocketSession webSocketSession)方法即可。

(2)使用HandlerMapping和WebSocketHandlerAdapter注册WebSocket处理类。

★ 反应式的WebSocket处理类

反应式API模型下,WebSocketSession的receive()方法返回的只是Flux(消息发布者),
它并不会同步获取消息,也不会阻塞。

类似的,WebSocketSession的send()方法发送的也只是Flux(消息发布者)

因此WebSocket处理类receive()消息之后,程序依然使用map()等方法对Flux中的数据项进行处理。

★ 配置基于WebFlux的WebSocket

要配置两个Bean:

  1. HandlerMapping(通常使用SimpleUrlHandlerMapping实现类即可)Bean,它定义URL与WebSocketHandler Bean的映射关系。

  2. WebSocketHandlerAdapter:它负责管理对WebSocketHandler Bean进行适配。
    它会自动对容器中所有的WebSocketHandler Bean进行适配,
    因此,意味着无论容器中有多少个WebSocketHandler ,该WebSocketHandlerAdapter只要配置一个即可。

可直接使用www.websocket.org/echo.html页面来测试WebSocket

代码演示

1、创建项目
在这里插入图片描述

MyWebSocketHandler

实现 WebSocKet 处理类

package cn.ljh.webflux_websocket.websockethandler;import org.springframework.stereotype.Component;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketMessage;
import org.springframework.web.reactive.socket.WebSocketSession;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;//实现 WebSocKet 处理类@Component
public class MyWebSocketHandler implements WebSocketHandler
{//实现这个接口,只需要实现一个方法,这个方法可通过 WebSocketSession 获取 Flux//这个方法并不需要处理具体的数据,它面向的是Flux编程@Overridepublic Mono<Void> handle(WebSocketSession webSocketSession){//接收消息时,得到的并不是具体的消息,而是 Flux , 这个 Flux 负责消息通信,就是个消息通道Flux<WebSocketMessage> sourceFlux = webSocketSession.receive();//map() 方法里的参数,就是 function的apply()方法,通常写成 Lambda 表达式Flux<WebSocketMessage> resultFlux = sourceFlux.map(message ->{//textMessage() 方法负责将 String 转换成 WebSocketMessage//这个 message 是 WebSocketMessage 类型,WebSocketMessage.getPayloadAsText()负责将消息数据转成StringWebSocketMessage webSocketMessage = webSocketSession.textMessage("回复:" + message.getPayloadAsText());return webSocketMessage;});//发送消息Mono<Void> sendMessage = webSocketSession.send(resultFlux);return sendMessage;}
}

WebSocketConfig

配置基于WebFlux的WebSocket

package cn.ljh.webflux_websocket.config;import cn.ljh.webflux_websocket.websockethandler.MyWebSocketHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter;import java.util.HashMap;
import java.util.Map;//配置基于WebFlux的WebSocket@Configuration
public class WebSocketConfig
{//这个bean负责对容器中所有的 WebSocketHandler Bean 进行适配@Beanpublic WebSocketHandlerAdapter webSocketHandlerAdapter(){return new WebSocketHandlerAdapter();}//MyWebSocketHandler 会接受容器中的依赖注入@Beanpublic HandlerMapping handlerMapping(MyWebSocketHandler myWebSocketHandler){//定义 URL 与 WebSocketHandler Bean 之间的映射关系//就是向这个 /myWebSocket 地址发送请求的时候,就将这个请求交给这个 myWebSocketHandler 处理类进行处理Map map = Map.of("/myWebSocket",myWebSocketHandler);//参数1:指定 URL 和 Handler 之间的映射关系  ,  参数2:就是优先级SimpleUrlHandlerMapping simpleUrlHandlerMapping = new SimpleUrlHandlerMapping(map,-1);return simpleUrlHandlerMapping;}}

前端没有写,www.websocket.org/echo.html页面已经没法测试WebSocket了。
现在简单的websocket 就完成了

在这里插入图片描述

通过 webFlux 弄一个webSocket 的聊天室。

完整代码:

client.html

这个客户端页面,先放在static 静态路径下面,就可以直接访问

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title> 基于WebSocket的多人聊天 </title><script type="text/javascript">// 定义Web Socket对象var webSocket = null;let sendMsg = function(){if (webSocket == null || webSocket.readyState != 1){document.getElementById('show').innerHTML+= "还未连接服务器,请先连接WebSocket服务器<br>";return;}let inputElement = document.getElementById('msg');// 发送消息webSocket.send(inputElement.value);// 清空单行文本框inputElement.value = "";}let connect = function(){let name = document.getElementById('name').value.trim();if (name == null || name == ""){document.getElementById('show').innerHTML+= "用户名不能为空<br>";return;}if (webSocket && webSocket.readyState == 1){webSocket.close();}webSocket = new WebSocket("ws://127.0.0.1:8080/myWebSocket/" + name);webSocket.onopen = function(){document.getElementById('show').innerHTML+= "恭喜您,连接服务器成功!<br>";document.getElementById('name').value = "";// 为onmessage事件绑定监听器,接收消息webSocket.onmessage= function(event){// 接收、并显示消息document.getElementById('show').innerHTML+= event.data + "<br>";}};}</script>
</head>
<body>
<input type="text" size="20" id="name" name="name"/>
<input type="button" value="连接" onclick="connect();"/>
<div style="width:600px;height:240px;overflow-y:auto;border:1px solid #333;" id="show"></div>
<input type="text" size="80" id="msg" name="msg"/>
<input type="button" value="发送" onclick="sendMsg();"/>
</body>
</html>

MyWebSocketHandler

实现 WebSocKet 处理类

package cn.ljh.webflux_websocket.websockethandler;import org.springframework.stereotype.Component;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketMessage;
import org.springframework.web.reactive.socket.WebSocketSession;
import reactor.core.publisher.Flux;
import reactor.core.publisher.FluxSink;
import reactor.core.publisher.Mono;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;//实现 WebSocKet 处理类@Component
public class MyWebSocketHandler implements WebSocketHandler
{//创建一个线程安全的map来存聊天信息,  FluxSink 代表了发送消息的通道public static final Map<WebSocketSession, FluxSink<WebSocketMessage>> myClients = new ConcurrentHashMap<>();//实现这个接口,只需要实现一个方法,这个方法可通过 WebSocketSession 获取 Flux//这个方法并不需要处理具体的数据,它面向的是Flux编程@Overridepublic Mono<Void> handle(WebSocketSession webSocketSession){//1、获取连接路径:   得到 WenSocket 的连接路径String path = webSocketSession.getHandshakeInfo().getUri().getPath();//2、获取用户名:     获取path路径字符串最后一个斜杠之后的内容,也就是获取聊天的用户名String name = path.substring(path.lastIndexOf("/") + 1);//3、接收消息:     接收消息时,得到的并不是具体的消息,而是 Flux , 这个 Flux 负责消息通信,就是个消息通道Flux<WebSocketMessage> sourceFlux = webSocketSession.receive();//map() 方法里的参数,就是 function的apply()方法,通常写成 Lambda 表达式Mono<Void> mono1 = sourceFlux.map(message ->{//这个 message 是 WebSocketMessage 类型,WebSocketMessage.getPayloadAsText()负责将消息数据转成String//获取用户发送的消息String payloadAsText = message.getPayloadAsText();//返回 用户名+消息String nameAndMessage = name + " : " + payloadAsText;return nameAndMessage;})//4、实现消息广播:   把消息发给每一个用户//此时的 message 已经是转换之后的 message 了,这时候是 String 类型.doOnNext(message ->{//此处做消息广播,      keySet()用于遍历map中的所有key,存在一个set集合中for (WebSocketSession session : myClients.keySet()){//通过session这个key , 获取消息通道FluxSinkFluxSink<WebSocketMessage> fluxSink = myClients.get(session);//调用 fluxSink 的 next() 方法向 Flux 发送消息//textMessage() 方法负责将 String 转换成 WebSocketMessage,把string类型的消息转回 WebSocketMessagefluxSink.next(session.textMessage(message));}//.then() 方法 讲解的时候说是合并上面的消息操作,百度说是异步执行}).then();//创建要发送消息的 outFluxFlux<WebSocketMessage> outFlux = Flux.create(fluxSink ->{//Flux 真正发布消息用的是Flux 底层的 fluxSinkmyClients.put(webSocketSession, fluxSink);});//发送消息Mono<Void> mono2 = webSocketSession.send(outFlux);//把两个mono 的消息汇总起来 再返回Mono<Void> allMono = Mono.zip(mono1, mono2).then();return allMono;}
}

WebSocketConfig

配置基于WebFlux的WebSocket

package cn.ljh.webflux_websocket.config;import cn.ljh.webflux_websocket.websockethandler.MyWebSocketHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter;import java.util.HashMap;
import java.util.Map;//配置基于WebFlux的WebSocket@Configuration
public class WebSocketConfig
{//这个bean负责对容器中所有的 WebSocketHandler Bean 进行适配@Beanpublic WebSocketHandlerAdapter webSocketHandlerAdapter(){return new WebSocketHandlerAdapter();}//MyWebSocketHandler 会接受容器中的依赖注入@Beanpublic HandlerMapping handlerMapping(MyWebSocketHandler myWebSocketHandler){//定义 URL 与 WebSocketHandler Bean 之间的映射关系//就是向这个 /myWebSocket 地址发送请求的时候,就将这个请求交给这个 myWebSocketHandler 处理类进行处理Map map = Map.of("/myWebSocket/{name}",myWebSocketHandler);//参数1:指定 URL 和 Handler 之间的映射关系  ,  参数2:就是优先级SimpleUrlHandlerMapping simpleUrlHandlerMapping = new SimpleUrlHandlerMapping(map,-1);return simpleUrlHandlerMapping;}}

测试结果

成功

在这里插入图片描述

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

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

相关文章

【Arduino27】DHT11温湿度传感器模拟值实验

硬件准备 DHT11温湿度&#xff1a;1个 面包板&#xff1a;1个 杜邦线&#xff1a;3根 硬件连线 VDD引脚接 5V 电源 DATE引脚接 4号 接口 GND引脚接 GND 接口 软件程序 #include<DHT.h>#define DHT11_pin 4 //温湿度传感器引脚DHT dht(DHT11_pin,DHT11);float tem…

常用echart图总结

柱状图 - category-work,grid直角坐标,legend,series-bar柱状图,tooltip提示框 - makeapie echarts社区图表可视化案例

华为OD机试 - 最多颜色的车辆 - 数据结构map(Java 2022Q4 100分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路1、核心思想2、题做多了&#xff0c;你就会发现&#xff0c;这道题属于送分题&#xff0c;为什么这样说&#xff1f;3、具体解题思路&#xff1a; 五、Java算法源码六、效果展示1、输入2、输出 华为OD机试 2023B…

C++ 模板

模板&#xff1a; 模板&#xff0c;即数据是灵魂&#xff0c;其余为肉身&#xff0c;正所谓有趣的灵魂万里挑一&#xff0c;所以想要模板变得完美&#xff0c;关键在于数据&#xff1b;其余不过是抄作业的框架。 模板函数&#xff1a; 模板函数可以自动推导出你传给他的数据类型…

便捷高效的电能管理:利用PLC远程控制网关实时监控配电箱

配电箱是工业生产过程中必不可少的设备&#xff0c;其中的PLC&#xff08;可编程逻辑控制器&#xff09;是实现自动化控制的重要组成部分。为了实时监控配电箱的数据&#xff0c;并进行远程调试上下载与管理控制&#xff0c;我们可以使用PLC数据采集与远程控制网关。 PLC数据采…

2023年全国大学生数学建模B题

多波束测线问题 1.问题提出 单波束测深是利用声波在水中的传播特性来测量水体深度的技术。声波在均匀介质中作匀 速直线传播&#xff0c;在不同界面上产生反射&#xff0c;利用这一原理&#xff0c;从测量船换能器垂直向海底发射声波信号&#xff0c;并记录从声波发射到信号接…

CVE-2023-3836:大华智慧园区综合管理平台任意文件上传漏洞复现

文章目录 CVE-2023-3836&#xff1a;大华智慧园区综合管理平台任意文件上传漏洞复现0x01 前言0x02 漏洞描述0x03 影响范围0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 CVE-2023-3836&#xff1a;大华智慧园区综合管理平台任意文件上传漏洞复现 0x01 前言 免责声…

0012Java程序设计-springboot基于微信小程序的校园智慧帮系统的设计与实现

摘要目录相关技术2.1 MySQL数据库2.2 SpringBoot框架2.3 uniapp框架2.4 B/S架构 系统设计系统实现开发环境 摘要 随着移动互联网高速发展&#xff0c;手机、移动智能终端设备在生活中有着越来越重要的地位。在高校推崇以人为本的今天&#xff0c;也逐渐重视“移动互联网”技术…

Java“牵手”1688商品详情数据,1688商品详情API接口,1688API接口申请指南

1688平台商品详情接口是开放平台提供的一种API接口&#xff0c;通过调用API接口&#xff0c;开发者可以获取1688商品的标题、价格、库存、月销量、总销量、库存、详情描述、图片等详细信息 。 获取商品详情接口API是一种用于获取电商平台上商品详情数据的接口&#xff0c;通过…

一套成熟的实验室信息管理系统(云LIS源码)ASP.NET CORE

一套成熟的实验室信息管理系统&#xff0c;集前处理、检验、报告、质控、统计分析、两癌等模块为一体的网络管理系统。它的开发和应用将加快检验科管理的统一化、网络化、标准化的进程。 LIS把检验、检疫、放免、细菌微生物及科研使用的各类分析仪器&#xff0c;通过计算机联…

CSS中如何实现文字渐变色效果(Text Gradient Color)?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 文字渐变色效果&#xff08;Text Gradient Color&#xff09;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这…

2023国赛数学建模C题思路模型 - 蔬菜类商品的自动定价与补货决策

# 1 赛题 在生鲜商超中&#xff0c;一般蔬菜类商品的保鲜期都比较短&#xff0c;且品相随销售时间的增加而变差&#xff0c; 大部分品种如当日未售出&#xff0c;隔日就无法再售。因此&#xff0c; 商超通常会根据各商品的历史销售和需 求情况每天进行补货。 由于商超销售的蔬菜…

前端面试的话术集锦第 8 篇:高频考点(JS性能优化 性能优化琐碎事)

这是记录前端面试的话术集锦第八篇博文——高频考点(JS性能优化 & 性能优化琐碎事),我会不断更新该博文。❗❗❗ 1. 从V8中看JS性能优化 注意:该知识点属于性能优化领域。 1.1 测试性能⼯具 Chrome已经提供了⼀个⼤⽽全的性能测试⼯具Audits。 点我们点击Audits后,可…

【Git】01-Git基础

文章目录 Git基础1. 简述1.1 版本管理演变1.2 Git的特点 2. Git安装2.1 安装文档2.1 配置user信息 3. 创建仓库3.1 场景3.2 暂存区和工作区 4. 重命名5. 常用git log版本历史5.1 查看当前分支日志5.2 简洁查看日志5.3 查看最近指定条数的日志 6. 通过图形界面工具查看版本7. 探…

数据库-DQL

DQL&#xff1a;用来查询数据库表中的记录 关键字&#xff1a;SELECT 语法&#xff1a; select&#xff1a;字段列表 from&#xff1a;表名列表 where&#xff1a;条件列表 group by&#xff1a;分组列表 having&#xff1a;分组后条件列表 order by&#xff1a;排序字段列表…

UWB学习——day1

UWB定义 UWB&#xff1a;Ultra Wideband&#xff08;超宽频&#xff09; UWB所谓的超宽频区别于其它近场通信技术可总结为时域上跳跃&#xff0c;频域上矮胖 从图中可以看出&#xff0c;时域上通过短且强的脉冲信号&#xff0c;频域上主要是超宽的频谱&#xff08;Spectrum&a…

VsCode备忘

上次简单学习了一下vscode的使用&#xff0c;结果好长时间没用&#xff0c;今天打开又全忘了。。。再记录一下吧 快捷键 CtrlShiftP 命令面板&#xff0c;查找命令&#xff0c;设置等等 Ctrl 打开集成终端&#xff0c;监视生成输出 Ctrl, 打开设置 CtrlP 转到文件,使用转到符…

CSAPP的Lab学习——Archlab(Architecture Lab)

文章目录 前言一、A部分sum .ys&#xff1a;迭代求和链表元素写一个Y86-64的程序和。rsum .递归求和链表元素copy.ys 复制将源块复制到目标块 二、B部分三、C部分实现iaddq指令 总结 前言 一个本硕双非的小菜鸡&#xff0c;备战24年秋招。刚刚看完CSAPP&#xff0c;真是一本神…

ansible搭建

一&#xff0c;ansible是一种由Python开发的自动化运维工具&#xff0c;集合了众多运维工具&#xff08;puppet、cfengine、chef、func、fabric&#xff09;的优点&#xff0c;实现了批量系统配置、批量程序部署、批量运行命令等功能 二&#xff0c;特点 * 部署简单 * **默认…

【网络通信 -- WebRTC】Open WebRTC Toolkit 环境搭建指南

【网络通信 -- WebRTC】Open WebRTC Toolkit -- OWT-Server 编译安装指南 【1】OWT Server 与 Web Demo 视频会议环境搭建 【1.1】编译 OWT Server 安装依赖 ./scripts/installDepsUnattended.sh编译 scripts/build.js -t all --check 注意若不支持硬件加速则采用如下命令 s…