(七)springboot实战——springboot3集成R2DBC实现webflux响应式编程服务案例

前言

本节主要内容是关于使用新版springboot3集成响应式数据库R2DBC,完成响应式web服务案例。需要注意的是,此次项目使用的JDK版本是JDK17,springboot版本使用3.2.2版本,数据库使用关系型数据库mysql。WebFlux 是一个基于响应式编程模型的框架,适用于构建异步、非阻塞的高性能 Web 应用程序。它具有高并发能力、函数式编程风格、与其他 Spring 框架的集成能力等优势,可以满足对性能要求高或需要处理大量并发请求的场景。

WebFlux 使用响应式编程模型,基于 Reactor 库实现。它利用异步和非阻塞的方式处理请求,能够处理大量的并发请求,提高应用程序的性能和可扩展性。由于采用了非阻塞的 I/O 操作,WebFlux 能够更有效地利用服务器资源,处理更多的并发请求,提供更高的吞吐量。WebFlux 鼓励使用函数式和声明式的编程风格,通过组合一系列操作来处理请求和响应。这种编程方式更具可读性和可维护性。WebFlux 使用 Flux 和 Mono 这两个反应式类型来处理异步数据流。Flux 用于表示包含零个或多个元素的异步序列,而 Mono 用于表示包含零个或一个元素的异步结果。WebFlux 可以与其他 Spring 框架和库进行无缝集成,例如 Spring Boot、Spring Data、Spring Security 等。这使得开发者可以充分利用 Spring 生态系统的优势。WebFlux 不依赖于特定的服务器,可以在各种服务器上运行,包括 Netty、Undertow 和 Tomcat 等。这为开发者提供了更多的灵活性和选择性。

正文

①使用idea创建一个springboot3项目

②引入r2dbc的mysql驱动和响应式Spring Data R2dbc启动器以及接口文档springdoc

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>
</dependency><!-- https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-starter-webflux-ui -->
<dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webflux-ui</artifactId><version>2.3.0</version>
</dependency><!--        响应式 Spring Data R2dbc-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency><!-- https://mvnrepository.com/artifact/io.asyncer/r2dbc-mysql -->
<dependency><groupId>io.asyncer</groupId><artifactId>r2dbc-mysql</artifactId><version>1.0.6</version>
</dependency>

 ③在resource目录下创建配置文件application.yaml,配置mysql的连接配置信息和接口文档

spring:r2dbc:url: r2dbc:mysql://192.168.110.88:3306/ht-atpusername: rootpassword: root
server:port: 8080
springdoc:api-docs:enabled: truepath: /api-docsswagger-ui:enabled: truepath: /swagger-ui/index.htmlshow-actuator: true

 ④启动项目,验证项目是否可以正常启动,以及接口文档是否可以正常使用

⑤创建用户实体类User

package com.yundi.atp.entity;import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;@Schema(name = "User", description = "用户类")
@Table(name = "user")
@Data
public class User {@Id@Schema(name = "id", description = "用户ID")private Integer id;@Schema(name = "name", description = "用户名称")private String name;@Schema(name = "age", description = "用户年龄")private Integer age;
}

⑥创建统一接口响应对象ApiResponse

package com.yundi.atp.common;import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;@Data
@Builder
public class ApiResponse<T> {@Schema(name = "code", description = "状态码")private Integer code;@Schema(name = "msg", description = "消息结果")private String msg;@Schema(name = "data", description = "数据")private T data;/*** 成功统一响应格式** @param* @param <T>* @return*/public static <T> ApiResponse<T> success() {ApiResponse<T> apiResponse = new ApiResponse<>(200, "成功", null);return apiResponse;}/*** 成功统一响应格式** @param data* @param <T>* @return*/public static <T> ApiResponse<T> success(T data) {ApiResponse<T> apiResponse = new ApiResponse<>(200, "成功", data);return apiResponse;}/*** 失败统一响应格式** @param code* @param message* @param <T>* @return*/public static <T> ApiResponse<T> fail(Integer code, String message) {return new ApiResponse<>(code, message, null);}
}

 ⑦创建UserController控制类,完成用户管理接口申明

package com.yundi.atp.controller;import com.yundi.atp.common.ApiResponse;
import com.yundi.atp.entity.User;
import com.yundi.atp.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;import java.util.List;@Tag(name = "用户管理", description = "用户管理")
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@Operation(summary = "获取全部用户信息", description = "获取全部用户信息")@GetMapping(value = "getAllUserInfo")public Mono<ApiResponse<List<User>>> getAllUserInfo() {Flux<User> userInfo = userService.getAllUserInfo();return userInfo.collectList().map(user -> ApiResponse.success(user));}@Operation(summary = "根据ID获取用户信息", description = "根据ID获取用户信息")@GetMapping(value = "getUserById/{id}")public Mono<ApiResponse<User>> getUserById(@PathVariable("id") Integer id) {Mono<User> user = userService.getUserById(id);Mono<ApiResponse<User>> userMono = user.map(ApiResponse::success);return userMono;}@Operation(summary = "新增用户", description = "新增用户")@PostMapping(value = "saveUser")public Mono<ApiResponse> saveUser(@RequestBody User user) {Mono<User> userMono = userService.saveUser(user);return userMono.thenReturn(ApiResponse.success());}@Operation(summary = "更新用户", description = "更新用户")@PostMapping(value = "updateUser")public Mono<ApiResponse> updateUser(@RequestBody User user) {Mono<User> userMono = userService.updateUser(user);return userMono.thenReturn(ApiResponse.success());}@Operation(summary = "删除用户", description = "删除用户")@DeleteMapping(value = "deleteUser/{id}")public Mono<ApiResponse> deleteUser(@PathVariable("id") Integer id) {Mono<Void> userMono = userService.deleteUser(id);return userMono.thenReturn(ApiResponse.success());}
}

⑧ 创建用户管理接口层UserService,定义接口

package com.yundi.atp.service;import com.yundi.atp.entity.User;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;public interface UserService {/*** 查询全部用户信息** @return*/Flux<User> getAllUserInfo();/*** 根据ID获取用户信息** @param id* @return*/Mono<User> getUserById(Integer id);/*** 新增用户** @param user* @return*/Mono<User> saveUser(User user);/*** 更新用户** @param user* @return*/Mono<User> updateUser(User user);/*** 删除用户** @param id* @return*/Mono<Void> deleteUser(Integer id);
}

 ⑨创建用户管理实现层UserServiceImpl,完成用户管理的业务逻辑

package com.yundi.atp.service.impl;import com.yundi.atp.entity.User;
import com.yundi.atp.repository.UserRepository;
import com.yundi.atp.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;@Service
public class UserServiceImpl implements UserService {@Resourceprivate UserRepository userRepository;@Overridepublic Flux<User> getAllUserInfo() {return userRepository.findAll();}@Overridepublic Mono<User> getUserById(Integer id) {return userRepository.findById(id);}@Overridepublic Mono<User> saveUser(User user) {return userRepository.save(user);}@Overridepublic Mono<User> updateUser(User user) {return userRepository.updateUser(user);}@Overridepublic Mono<Void> deleteUser(Integer id) {return userRepository.deleteById(id);}
}

⑩ 创建UserRepository持久层,并继承R2dbcRepository通用数据库操作接口完成数据库的操作

package com.yundi.atp.repository;import com.yundi.atp.entity.User;
import org.springframework.data.r2dbc.repository.Query;
import org.springframework.data.r2dbc.repository.R2dbcRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Mono;@Repository
public interface UserRepository extends R2dbcRepository<User, Integer> {/*** 更新用户信息** @param user* @return*/@Query("update user set name = :#{#user.name}, age = :#{#user.age} where id = :#{#user.id}")Mono<User> updateUser(@Param("user") User user);/*** 动态更新用户信息** @param user* @return*/@Query("UPDATE User SET " +"name = CASE WHEN :#{#user.name} IS NULL THEN name ELSE :#{#user.name} END, " +"age = CASE WHEN :#{#user.age} IS NULL THEN age ELSE :#{#user.age} END " +"WHERE id = :#{#user.id}")Mono<User> updateUserQuery(@Param("user") User user);
}

⑪ 使用swagger接口文档测试用户管理接口

结语

至此,关于springboot3集成R2DBC实现webflux响应式编程服务案例的内容到这里就结束了,我们下期见。。。。。。

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

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

相关文章

K8s-持久化(持久卷,卷申明,StorageClass,StatefulSet持久化)

POD 卷挂载 apiVersion: v1 kind: Pod metadata:name: random-number spec:containers:- image: alpinename: alpinecommand: ["/bin/sh","-c"]args: ["shuf -i 0-100 -n 1 >> /opt/number.out;"]volumeMounts:- mountPath: /optname: da…

04-Nacos-服务注册基于spring boot实现

官方参考 在不依赖spring cloud 组件基础上&#xff0c;单独的微服务项目&#xff0c;实现nacos接入 1、依赖文件pom.xml <dependency><groupId>com.alibaba.boot</groupId><artifactId>nacos-discovery-spring-boot-starter</artifactId><…

RUST笔记: 动态链接库的创建和使用

生成动态链接库 // https://github.com/vvvm23/funny-shapes # 项目元信息 [package] name "funnyshapes" # 项目名称 version "0.1.0" # 版本号 edition "2021" # Rust语言版本# 更多配置信息可查阅&#xff1…

华为机考入门python3--(3)牛客3-明明的随机数

分类&#xff1a;集合、排序 知识点&#xff1a; 集合添加元素 set.add(element) 集合转列表 list(set) 列表排序 list.sort() 题目来自【牛客】 N int(input().strip()) nums set()for i in range(N):nums.add(int(input().strip()))# 集合转列表 nums_list l…

眼底增强型疾病感知蒸馏模型 FDDM:无需配对,fundus 指导 OCT 分类

眼底增强型疾病感知蒸馏模型 FDDM&#xff1a;fundus 指导 OCT 分类 核心思想设计思路训练和推理 效果总结子问题: 疾病特定特征的提取与蒸馏子问题: 类间关系的理解与建模 核心思想 论文&#xff1a;https://arxiv.org/pdf/2308.00291.pdf 代码&#xff1a;https://github.c…

【模板】拓扑排序

Problem: 【模板】拓扑排序 文章目录 思路解题方法复杂度Code 思路 拓扑排序模板 解题方法 初始化一个队列&#xff0c;将所有入度为0的顶点入队。从队列中取出一个顶点&#xff0c;并将其输出。对于该顶点的所有出边&#xff0c;将出边的终点的入度减1。如果某个顶点的入度变为…

269. 火星词典

Problem: 269. 火星词典 文章目录 思路解题方法复杂度Code 思路 首先&#xff0c;我们先将所有单词中出现的字符标记为 0&#xff0c;没有出现的标记为 1。然后&#xff0c;我们开始建图&#xff0c;对于每一个单词对&#xff0c;我们比较它们的前缀&#xff0c;直到找到第一个…

【笔试常见编程题02】字符串中找出连续最长的数字串、数组中出现次数超过一半的数字、计算糖果、进制转换

1. 字符串中找出连续最长的数字串 读入一个字符串str&#xff0c;输出字符串str中的连续最长的数字串 输入描述 个测试输入包含1个测试用例&#xff0c;一个字符串str&#xff0c;长度不超过255。 输出描述 在一行内输出str中里连续最长的数字串。 示例 1 输入 abcd12345ed125s…

java数据结构与算法刷题-----LeetCode328. 奇偶链表

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 解题思路 将链表按奇偶顺序&#xff0c;分成两个链表。最后将偶数链表放在…

(每日持续更新)jdk api之InterruptedIOException基础、应用、实战

博主18年的互联网软件开发经验,从一名程序员小白逐步成为了一名架构师,我想通过平台将经验分享给大家,因此博主每天会在各个大牛网站点赞量超高的博客等寻找该技术栈的资料结合自己的经验,晚上进行用心精简、整理、总结、定稿,每天都会整理到12点,为了就是能让大家能够真…

Python无人诊断治疗全套系统

Python无人诊断治疗全套系统的研发开发对于医疗行业具有重要性。以下是其重要性的几个方面&#xff1a; 提高诊断精确性&#xff1a;无人诊断系统利用大数据分析和人工智能技术&#xff0c;能够通过对病例的分析和比对&#xff0c;提供更准确的诊断结果。相比于传统的人工诊断&…

LeetCode第500题 - 键盘行

题目 给定一个单词列表&#xff0c;只返回可以使用在键盘同一行的字母打印出来的单词。 示例&#xff1a; 输入: [“Hello”, “Alaska”, “Dad”, “Peace”] 输出: [“Alaska”, “Dad”] 解答 class Solution {public String[] findWords(String[] words) {char[][] keybo…

计算机网络-编制与调制(基带信号 基带传输 宽度信号 宽度传输 编码 调制 )

文章目录 基带信号与宽带信号编码与调制数字数据编码为数字信号数字数据调制为模拟信号模拟数据编码为数字信号模拟数据调制为模拟信号小结 基带信号与宽带信号 信道上传输的信号除了可以分为数字信号和模拟信号&#xff0c;也可以分为基带信号和宽带信号&#xff0c;只是分类…

【每日一题】最大合金数

文章目录 Tag题目来源解题思路方法一&#xff1a;二分枚举答案 写在最后 Tag 【二分枚举答案】【数组】【2024-01-27】 题目来源 2861. 最大合金数 解题思路 方法一&#xff1a;二分枚举答案 思路 如果我们可以制造 x 块合金&#xff0c;那么一定也可以制造 x-1 块合金。于…

【Spring Boot 3】【@Scheduled】动态修改定时任务时间

【Spring Boot 3】【@Scheduled】动态修改定时任务时间 背景介绍开发环境开发步骤及源码工程目录结构总结背景 软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习…

Hadoop-MapReduce-源码跟读-客户端篇

一、源码下载 下面是hadoop官方源码下载地址&#xff0c;我下载的是hadoop-3.2.4&#xff0c;那就一起来看下吧 Index of /dist/hadoop/core 二、从WordCount进入源码 用idea将源码加载进来后&#xff0c;找到org.apache.hadoop.examples.WordCount类&#xff08;快捷方法&…

支持下一代网络IpV6的串口服务器,IpV6串口485接口转网口

和IPv4比较&#xff0c;IPv6有两个极具吸引力的特点&#xff1a;一个是IPv6采用的128位地址格式&#xff0c;而IPv4采用32位的地址格式&#xff0c;因此IPv6使地址空间增大了296&#xff1b;另一个是IPv6物联网数据业务具有更强的支持能力&#xff0c;成为未来物联网的重要协议…

Kafka消息流转的挑战与对策:消息丢失与重复消费问题

消息丢失和重复消费时分布式系统重的常见问题&#xff0c;如果处理不好会对业务造成很大的影响。比如用户下单是通过消息队列处理的&#xff0c;对于用户的订单来说&#xff0c;消息丢失会造成用户下单丢失&#xff0c;影响售卖&#xff0c;如果重复消费&#xff0c;可能会生成…

Ps:创建基于饱和度的蒙版

能够区分图像上哪些区域的饱和度高&#xff0c;哪些区域的饱和度低&#xff0c;在调色过程中是相当有用的。 比如&#xff0c;使得饱和度高的区域更加饱和&#xff0c;可增加图像色彩反差&#xff0c;让画面更引人注目。 或者&#xff0c;使得饱和度区域趋于饱和&#xff0c;让…

技术书评和笔记【01】脑机接口-电路与系统 【2020版】

前言: 荷兰作者,Amir Zjajo博士,毕业于荷兰代尔夫特理工大学,方向 面向移动健康的低功耗混合型号电路与系统,以及,面向认知的神经形态电路。 ,脑机接口 - 电路与系统一书,系统介绍了,脑机接口电路与系统的实现技术,尤其,提到了量产和设计的问题,难能可贵,摘录如…