RSocket vs WebSocket:Spring Boot 3.3 中的两大实时通信利器

news2024/11/28 16:42:48

RSocket vs WebSocket:Spring Boot 3.3 中的两大实时通信利器

随着现代互联网应用的不断发展,实时通信已经成为许多应用程序不可或缺的功能。无论是社交网络、在线游戏还是数据监控系统,实时通信都能提供快速、无缝的信息交换。而实现实时通信的两种主要协议是 RSocket 和 WebSocket。

RSocket 是一种新的、先进的应用层协议,旨在提供高效的网络通信。与传统的请求/响应模式不同,RSocket 支持请求-响应、请求-流、流-流等多种模式,从而在微服务和流式数据传输中表现得更加灵活和高效。RSocket 的优势在于它可以在 TCP、WebSocket 等多种传输协议上运行,支持背压机制和多路复用,从而避免了资源的浪费,并保证了消息传递的可靠性。

WebSocket 是一种标准协议,允许客户端和服务器之间建立持久连接,客户端和服务器都可以主动发送消息。相较于传统的 HTTP 请求-响应模型,WebSocket 是全双工通信,即服务器可以实时向客户端推送数据,而不需要等待客户端发起请求,尤其适合实时数据更新场景。WebSocket 的使用场景广泛,涵盖了即时通讯、实时数据展示和多人在线游戏等。

运行效果:

若想获取项目完整代码以及其他文章的项目源码,且在代码编写时遇到问题需要咨询交流,欢迎加入下方的知识星球。

本文将结合 Spring Boot 3.3,详细讲解如何使用 RSocket 和 WebSocket 实现实时通信。我们将通过一个完整的示例,展示前后端交互、消息传递和双向通信的实际应用。文章还将结合具体的代码示例,演示如何从前端向后端发送消息,并在点击按钮时与服务器进行交互。

项目配置

项目依赖配置(pom.xml)

在 pom.xml 中引入 RSocket、WebSocket 以及其他必要的依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.3.3</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.icoderoad</groupId>
	<artifactId>rsocket-websocket-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>rsocket-websocket-demo</name>
	<description>Demo project for Spring Boot</description>
	
	<properties>
		<java.version>17</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency><!-- Spring Boot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- RSocket 支持 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-rsocket</artifactId>
        </dependency>

        <!-- WebSocket 支持 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

        <!-- Thymeleaf 模板引擎 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!-- Lombok 支持 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

应用配置(application.yml)

server:
  port: 8080

spring:
  rsocket:
    server:
      port: 7000
      transport: websocket
      mapping-path: /rsocket

  websocket:
    enabled: true
    mapping: /ws

app:
  rsocket-message: "这是来自 RSocket 的消息"
  websocket-message: "这是来自 WebSocket 的消息"

读取配置类 (RSocket 和 WebSocket 配置类)

我们使用 @ConfigurationProperties 注解读取配置文件中的 app 节点。这里使用 Lombok 来简化实体类的代码实现。

package com.icoderoad.rwebsocket.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Data
@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {
	
    private String rsocketMessage;
    
    private String websocketMessage;
    
}

RSocket 服务端实现

RSocket 提供了灵活的通信模型,允许服务端和客户端以流的方式交换数据。我们通过 @MessageMapping 来定义接收和处理客户端消息的方法。

package com.icoderoad.rwebsocket.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.stereotype.Controller;

import com.icoderoad.rwebsocket.config.AppProperties;

import reactor.core.publisher.Mono;

@Controller
public class RSocketController {

    @Autowired
    private AppProperties appProperties;

    @MessageMapping("rsocket.message")
    public Mono<String> sendMessage(String input) {
        return Mono.just("RSocket服务端响应: " + input + " | " + appProperties.getRsocketMessage());
    }
}

WebSocket 服务端实现

WebSocket 服务端使用 Spring 提供的 TextWebSocketHandler 来处理消息。我们在收到客户端消息后,通过会话对象将响应发送回客户端。

package com.icoderoad.rwebsocket.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.icoderoad.rwebsocket.config.AppProperties;

@Controller
public class WebSocketController extends TextWebSocketHandler {

    @Autowired
    private AppProperties appProperties;

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String clientMessage = message.getPayload();
        String responseMessage = "WebSocket服务端响应: " + clientMessage + " | " + appProperties.getWebsocketMessage();
        session.sendMessage(new TextMessage(responseMessage));
    }
}

WebSocket 配置类

使用 WebSocketConfigurer 来注册 WebSocket 的处理器,并允许跨域访问。

package com.icoderoad.rwebsocket.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

import com.icoderoad.rwebsocket.controller.WebSocketController;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    private final WebSocketController webSocketController;

    public WebSocketConfig(WebSocketController webSocketController) {
        this.webSocketController = webSocketController;
    }

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(webSocketController, "/ws")
                .setAllowedOrigins("*");
    }
}

前端实现

前端使用 Thymeleaf 渲染,并通过 jQuery 与后端的 RSocket 和 WebSocket 进行交互。用户可以输入消息,通过点击按钮发送到后端,并接收后端的响应。

在 src/main/resources/templates 目录下创建 index.html 文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>RSocket & WebSocket Demo</title>
    
    <!-- 引入 Bootstrap 样式 -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    
    <!-- 引入 jQuery 和 Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>

    <!-- 引入 RSocket 库 -->
    <script src="/js/rsocket-core.min.js"></script>
    <script src="/js/rsocket-websocket-client.min.js"></script>

    <style>
        .message-box {
            max-height: 300px;
            overflow-y: auto;
            border: 1px solid #dee2e6;
            padding: 10px;
            border-radius: 0.25rem;
            background-color: #f8f9fa;
        }
        .message-box p {
            margin-bottom: 0.5rem;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1 class="mt-5">RSocket & WebSocket Demo</h1>

        <!-- WebSocket 区域 -->
        <div class="mt-5">
            <h3>WebSocket 消息</h3>
            <div class="input-group mb-3">
                <input type="text" id="websocket-input" class="form-control" placeholder="输入 WebSocket 消息">
                <button id="send-websocket" class="btn btn-primary">发送 WebSocket 消息</button>
            </div>
            <div id="websocket-messages" class="message-box"></div>
        </div>

        <!-- RSocket 区域 -->
        <div class="mt-5">
            <h3>RSocket 消息</h3>
            <div class="input-group mb-3">
                <input type="text" id="rsocket-input" class="form-control" placeholder="输入 RSocket 消息">
                <button id="send-rsocket" class="btn btn-success">发送 RSocket 消息</button>
            </div>
            <div id="rsocket-messages" class="message-box"></div>
        </div>
    </div>

    <script>
        $(document).ready(function () {
            // WebSocket 连接
            const ws = new WebSocket("ws://localhost:8080/ws");

            ws.onmessage = function (event) {
                $("#websocket-messages").append(`<p>${event.data}</p>`);
            };

            // 发送 WebSocket 消息
            $("#send-websocket").click(function () {
                const message = $("#websocket-input").val();
                if (message.trim()) {
                    ws.send(message);
                    $("#websocket-input").val('');
                }
            });
            const { RSocketClient } = window['rsocket-core'];
            const { default: RSocketWebSocketClient } = window['rsocket-websocket-client'];

            // RSocket 客户端创建和连接
            async function createRSocketClient() {
                const transportOptions = {
                    url: 'ws://localhost:7001/rsocket',
                };
                const setupOptions = {
                    keepAlive: 60000,
                    lifetime: 180000,
                    dataMimeType: 'application/json',
                    metadataMimeType: 'message/x.rsocket.routing.v0',
                };
                const transport = new RSocketWebSocketClient(transportOptions);
                const client = new RSocketClient({
                    setup: setupOptions,
                    transport
                });
                try {
                    return await client.connect();
                } catch (error) {
                    console.error("RSocket 连接错误: ", error);
                    throw error;
                }
            }

            // 处理 RSocket 消息
            async function setupRSocket() {
                try {
                    const socket = await createRSocketClient();

                    $("#send-rsocket").click(function () {
                        const message = $("#rsocket-input").val();
                        if (message.trim()) {
                            socket.requestResponse({
                                data: message,
                                metadata: String.fromCharCode('rsocket.message'.length) + 'rsocket.message'
                            }).subscribe({
                                onComplete: (response) => {
                                    $("#rsocket-messages").append(`<p>${response.data}</p>`);
                                    $("#rsocket-input").val('');
                                },
                                onError: (error) => {
                                    console.error("RSocket 错误: ", error);
                                }
                            });
                        }
                    });
                } catch (error) {
                    console.error("启动 RSocket 客户端失败: ", error);
                }
            }

            setupRSocket();
        });
    </script>
</body>
</html>

总结

通过结合 RSocket 和 WebSocket,我们可以在 Spring Boot 3.3 中轻松实现高效的实时通信。RSocket 通过其多种通信模型和背压机制,为流式数据传输提供了强大的支持;WebSocket 则在全双工实时通信方面表现出色,适合需要即时数据更新的场景。通过本文的实例,读者可以在项目中灵活应用这两种技术,实现高效的消息交互。在前端,我们使用简单的输入框和按钮,演示了如何与服务器进行消息通信。这种方式不仅提升了用户体验,还能大幅提高系统的响应速度和处理效率。

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

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

相关文章

“主升筹码”,底部建仓信号+主升加仓位置,不错过任何行情

使用技巧 指标分为主图和副图 其中&#xff0c;主图主升筹码信号较多&#xff0c;副图的信号较少。这里&#xff0c;我说一个选股思路&#xff0c;就是底部主升筹码共振进场&#xff0c;上升过程中主图信号当作加仓信号。 选股&#xff0c;提供一个主升筹码共振选股&#xff0…

Redis 5.0 安装配置(Windows)

Redis 5.0之后支持Redis Stream等功能 下载地址&#xff1a;Releases tporadowski/redis GitHub 点击运行redis-server.exe 此外&#xff1a;Redis 6.0及以后版本目前都没有Windows版

【越狱插件】内网穿透 frpc、frps插件

内网穿透、frp、frpc、frps https://zhaoboy9692.github.io/repo 越狱源 https://zhaoboy9692.github.io/repo 苦于在ios越狱下没有frp穿透使用 特地开发了的越狱插件 基于最新frp0.48编译 ios14.6测试没问题 有问题及时反馈

ubuntu中使用cmake编译报错No CMAKE_CXX_COMPILER could be found.的解决方法

ubuntu中使用cmake编译报错No CMAKE_CXX_COMPILER could be found.的解决方法 No CMAKE_CXX_COMPILER could be found.Could NOT find CUDA (missing: CUDA_NVCC_EXECUTABLE CUDA_CUDART_LIBRARY)Could not find a package configuration file provided by "OpenCV" …

【SQL|大数据|数据清洗|过滤】where条件中 “ != “ 和 “ NOT IN() ” 对NULL的处理

对数据进行清洗过滤的时候&#xff0c;NULL往往是一个很特殊的存在&#xff0c;对NULL值的存在通常有以下三种方式 1、保留NULL 2、过滤掉NULL 3、将NULL替换为其他符合业务需求的默认常量 下面是一些常用处理NULL的方式&#xff1a; 如下图所示数据源&#xff1a; car_vin&…

android openGL ES详解——缓冲区VBO/VAO/EBO/FBO

目录 一、缓冲区对象概念 二、分类 三、顶点缓冲区对象VBO 1、概念 2、为什么使用VBO 3、如何使用VBO 生成缓冲区对象 绑定缓冲区对象 输入缓冲区数据 更新缓冲区中的数据 删除缓冲区 4、VBO应用 四、顶点数组对象VAO 1、概念 2、为什么使用VAO 3、如何使用VAO…

ai修复照片工具哪个好?在线将模糊图像变清晰就用它

最近想尝试学习一下复古照片的拍摄风格&#xff0c;一波翻箱倒柜的操作翻出了以前家里拍的照片&#xff0c;却发现有些照片出现了氧化褪色&#xff0c;看不清原本图像的情况。 想看清晰一点的照片却找不到原本的底片&#xff0c;没办法再次冲洗新的相纸出来&#xff0c;该怎么…

Generative AI project lifecycle 生成式人工智能项目的全生命周期

这篇文章&#xff0c;你将学习到开发和部署一个由LLM驱动的应用程序所需的技术。在你将了解一个生成式AI项目的全生命周期&#xff0c;这可以帮助指导你完成这项工作。这个框架映射出了从概念到发布所需的任务。这里有一个整体生命周期的图表。我们将逐个阶段地讨论它。 在任何…

一文说明MySQL索引

最近研究了一下关于MySQL索引方面的面试题&#xff0c;以及可能拓展的问题&#xff0c;与大家分享 索引 在MySQL中&#xff0c;常见的索引类型包括以下几种&#xff1a; 普通索引&#xff08;INDEX&#xff09; &#xff1a;这是最基本的索引类型&#xff0c;可以包含一个或多…

基于springboot+vue实现的助学兼职系统(源码+L文+ppt)4-092

基于springbootvue实现的助学兼职系统&#xff08;源码L文ppt&#xff09;4-092 第4章 系统设计 4.1 总体功能设计 一般学生、招聘公司和管理者都需要登录才能进入助学兼职系统&#xff0c;使用者登录时会在后台判断使用的权限类型&#xff0c;包括一般使用者和管理者,一般使…

探索 Python 中的 XML 转换利器:xml2dict

文章目录 **探索 Python 中的 XML 转换利器&#xff1a;xml2dict**一、背景介绍二、xml2dict 是什么&#xff1f;三、如何安装 xml2dict&#xff1f;四、基本用法五、实际应用场景六、常见问题及解决方案七、总结 探索 Python 中的 XML 转换利器&#xff1a;xml2dict 一、背景…

构建智能暖箱监控系统:基于C#和WPF的完整指南

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

鸿蒙前端-1. 层叠效果

代码Stack&#xff08;{alignContent&#xff1a;Alignment.Center}&#xff09;{ Item1&#xff08;&#xff09; Item2&#xff08;&#xff09; Item3&#xff08;&#xff09;} 默认是居中对齐&#xff0c;后面的Item的优先级比前面的要高。 特点&#xff1a;代码简洁&…

stm32实现esp8266连接到TCP服务器(二)

1.2 连接到TCP Server 1.2.1 使用网络助手&#xff0c;设立TCP服务器 ​ 编辑 1.2.2 连接服务器 ATCIPSTART"TCP","192.168.1.18",8080 //指令&#xff0c;注意双引号逗号都要半角(英文)输入 CONNECT //结果&#xff1a;成功 OK //结果&#xff1a;成功 …

08 实战:色彩空间展示(本程序以视频为主)

程序效果如下: 我在这里讲解RGB和YCbCr的原理: 一、RGB颜色空间 1.1 基本概念 RGB颜色空间是一种最基础和常用的颜色表示方式,它基于人眼感知色彩的三原色原理。RGB分别代表: R(Red):红色G(Green):绿色B(Blue):蓝色通过这三种基本颜色的不同组合,可以产生人眼…

c#编写的各类应用程序、类库的引用(黑白盒)

001 课程简介&#xff0c;C# 语言简介&#xff0c;开发环境准备 (yuque.com)https://www.yuque.com/yuejiangliu/dotnet/timothy-csharp-001 一个Solution里包含多个Project 一、见识 C# 编写的各类应用程序 二、类库的引用&#xff08;黑/白盒引用&#xff09; 1、黑盒引用&a…

杨辉三角算法

给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: numRows 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]示例 2: 输入: numRows 1 输出: [[1]]提示: 1 <…

2024ideaUI切换和svn与git的切换,svn的安装和配置,idea集成svn ,2024-10-18日

2024-10-18日 2024的UI实在很不舒服&#xff0c;隐藏了很多按键&#xff1b; 第一步&#xff1a; 视图 -》 外观 -》 工具栏选出来&#xff1b; 结果出来&#xff1a; 运行的按键和设置的按钮 第二步 点击设置的按钮&#xff0c;选择最后一个&#xff0c;重启就行 结果 舒服&…

LabVIEW提高开发效率技巧----用户权限控制

在LabVIEW开发中&#xff0c;用户权限控制是一个重要的设计模块&#xff0c;尤其在多用户系统中&#xff0c;它可以确保数据安全并控制不同用户的操作权限。为了实现用户权限控制&#xff0c;可以通过角色与权限管理模块来进行设计和实施。以下将从多个角度详细说明如何在LabVI…

Quarto ppt模板制作与Rstudio git连接

本篇记录下当前ppt演示中比较流行的quarto document使用情况以及Rstudio与git相连接的一些实操。 1 Quarto ppt模板制作 1.1 Quarto简介&#xff08;来自Kimi&#xff09; Quarto 是一个由 RStudio 的母公司 Posit 团队开发的开源科学和技术出版系统&#xff0c;它建立在 Pan…