当前位置: 首页 > news >正文

22. 【.NET 8 实战--孢子记账--从单体到微服务】--记账模块--切换主币种

这篇文章我们将结合主币种设置以及收支记录实现切换主币种后重新计算以前记录的转换后的金额。那么,为什么要在切换主币种后要重新计算转换后的金额呢?有以下两个原因:

  1. 统一的币种,方便我们统计数据
  2. 方便用户按照当地的币种查看收支

下面我们就一起来实现吧。

一、实现逻辑

我们先来看一下要实现这个功能所需要的数据:

  1. 新的主币种
  2. 转换前币种
  3. 转换前金额
    接着我们一起把实现的思路写出来。首先我们要修改主币种配置,将旧的主币种替换成新的主币种,主币种配置修改成后,我们会利用消息队列发送一条主币种修改通知,负责重新计算转换后的金额的代码订阅这个通知,当它收到通知后就开始执行重新计算记录转换后的金额。负责重新计算转换后的金额的代码会先去查询当前用户全部记录,然后对账本中每条记录进行重新计算转换后的金额,最后将修改结果更新到数据库。

二、实现

我们根据上一小节的思路,先自己实现切换主币种的全部功能,然后把自己的代码和下面的代码核对一下,看看哪里不一样。这里提醒一下,我们订阅主币种修改通知的代码应放在RabbitMQBackgroundService类中。

2.1 修改主币种

ConfigController

/// <summary>
/// 更新用户配置
/// </summary>
/// <param name="configViewModel"></param>
/// <returns></returns>
[HttpPut]
[Route("Update")]
public ActionResult<ResponseData<bool>> Update([FromBody] ConfigViewModel configViewModel)
{try{string userId = GetUserId();bool isExist = _configServer.IsExist(userId, configViewModel.Id);if (!isExist){return Ok(new ResponseData<bool>(HttpStatusCode.NotFound, "用户配置不存在"));}_configServer.Update(userId, configViewModel.Id, configViewModel.Value);//如果切换的是主币种,那么就将以前的所有金额全部转换成新的主币种的金额if (configViewModel.ConfigTypeEnum == ConfigTypeEnum.Currency){_ = _rabbitMqPublisher.Publish<MainCurrency>("UpdateConversionAmount", "UpdateConversionAmount",new MainCurrency(){UserId = userId,Currency = configViewModel.Value});}return Ok(new ResponseData<bool>(HttpStatusCode.OK, data: true));}catch (Exception ex){return Ok(new ResponseData<bool>(HttpStatusCode.InternalServerError, "服务器异常"));}
}

这段代码的作用是更新用户配置,并在特定条件下触发与主币种切换相关的业务逻辑。首先,代码通过 GetUserId() 方法获取当前操作用户的唯一标识符 userId。随后,通过 _configServer.IsExist 方法检查用户配置是否存在。如果配置不存在,返回包含 NotFound 状态的响应,提示“用户配置不存在”。如果配置存在,调用 _configServer.Update 方法,更新指定的配置值 configViewModel.Value。接着,代码进一步判断 configViewModel.ConfigTypeEnum 是否为 Currency 类型,即当前更新的配置是否为主币种。当更新的配置是主币种时,通过 _rabbitMqPublisher.Publish 方法向消息队列发送一条 UpdateConversionAmount 消息,其中包含用户 Id 和新的主币种Id。这一步的目的是通知其他系统或模块,执行与主币种切换相关的金额转换逻辑。

2.2 重新计算转换后的金额

RabbitMQBackgroundService

//more codeawait _subscriberService.SubscribeAsync<MainCurrency>("UpdateConversionAmount", "UpdateConversionAmount",
async (mainCurrency) =>
{//1.获取所有收支记录var recordService = _serviceProvider.GetRequiredService<IIncomeExpenditureRecordServer>();var records = recordService.QueryByUserId(mainCurrency.UserId);//2.将所有记录的金额转换为新的主币种(记录中的币种转换为新的主币种)var currencyServer = _serviceProvider.GetRequiredService<ICurrencyServer>();var exchangeRateRecordServer = _serviceProvider.GetRequiredService<IExchangeRateRecordServer>();Currency? query = currencyServer.Query( mainCurrency.Currency);if (query == null){return;}for (int i = 0; i < records.Count; i++){var record = records[i];var currency = record.Currency;//获取记录币种和主币种的汇率ExchangeRateRecord? exchangeRateRecord =exchangeRateRecordServer.Query($"{query.Abbreviation}_{currency.Abbreviation}");if (exchangeRateRecord != null)record.AfterAmount = exchangeRateRecord.ExchangeRate * record.BeforAmount;}//3.更新所有记录recordService.UpdateRecord(records);
});//more code

这段代码实现了一个异步消息订阅和处理的逻辑,用于在主币种发生变更时更新所有收支记录的金额。代码逻辑通过订阅消息队列中的 UpdateConversionAmount 主题来触发。 核心流程是:通过 _subscriberService.SubscribeAsync 方法订阅名为 UpdateConversionAmount 的消息,并注册一个异步处理函数。在处理函数中,首先从依赖注入容器中获取 IIncomeExpenditureRecordServer 服务,查询出指定用户的所有收支记录。接着,使用 ICurrencyServer 查询新的主币种信息,确保其存在;然后通过 IExchangeRateRecordServer 获取当前记录的币种和新的主币种之间的汇率。如果汇率数据存在,则将记录中的金额 (BeforAmount) 转换为以新的主币种为单位的金额 (AfterAmount)。最后,通过 recordService.UpdateRecord 将更新后的记录批量保存到数据库中。

三、总结

通过主币种切换的业务场景,探讨了如何在用户更改主币种配置后重新计算历史收支记录的转换金额。这一功能的实现基于两个核心需求:统一币种便于统计数据,以及方便用户按照本地币种查看收支信息。实现过程中,首先修改主币种配置,当用户设置新的主币种后,系统通过消息队列发送变更通知。相关处理逻辑通过 RabbitMQBackgroundService 订阅该通知,触发重新计算金额的操作。具体流程包括:查询当前用户的所有收支记录,获取新的主币种和原币种之间的汇率,并根据汇率计算每条记录的转换金额,最后更新数据库中的记录。
该方案采用分层设计和异步消息机制,将主币种的配置管理与金额转换逻辑解耦,提升了系统的可扩展性和维护性。整体流程清晰,代码实现规范,为类似场景的开发提供了良好的参考。

相关文章:

22. 【.NET 8 实战--孢子记账--从单体到微服务】--记账模块--切换主币种

这篇文章我们将结合主币种设置以及收支记录实现切换主币种后重新计算以前记录的转换后的金额。那么&#xff0c;为什么要在切换主币种后要重新计算转换后的金额呢&#xff1f;有以下两个原因&#xff1a; 统一的币种&#xff0c;方便我们统计数据方便用户按照当地的币种查看收…...

01.02周四F34-Day43打卡

文章目录 1. 地是湿的。昨晚估计下雨了。2. 你可能把包丢在餐厅里了吧?3. 她说他可能误了航班。4. 我本来应该早点来的,但路上特别堵。5. 约翰可能在那次事故中受了重伤。6. 这是一个情景对话7. 我本可以走另一条路的。8. 我准是瘦了不少,你看我这裤子现在多肥。9. 钱没了!会…...

行业商机信息付费小程序系统开发方案

行业商机信息付费小程序系统&#xff0c;主要是整合优质行业资源&#xff0c;实时更新的商机信息。在当今信息爆炸的时代&#xff0c;精准、高效地获取行业商机信息对于企业和个人创业者而言至关重要。 一、使用场景 日常浏览&#xff1a;用户在工作间隙或闲暇时间&#xff0c…...

cut-命令详解

一、命令 1.cut列截取命令 cut命令的默认分隔符是制表符 2.参数&#xff1a; -f 列号 #提取第几列-d 分隔符 #按照指定分隔符分割列-c 字符范围 #不依赖分隔符来区分列&#xff0c;而是通过字符范围&#xff08;行首为0&#xff09;来进行字段提取。“n-”表…...

Apache MINA 反序列化漏洞CVE-2024-52046

漏洞描述&#xff1a; Apache MINA 是一个功能强大、灵活且高性能的网络应用框架。它通过抽象网络层的复杂性&#xff0c;提供了事件驱动架构和灵活的 Filter 链机制&#xff0c;使得开发者可以更容易地开发各种类型的网络应用。 Apache MINA 框架的 ObjectSerializationDeco…...

二、AI知识(神经网络)

二、AI知识&#xff08;神经网络&#xff09; 1.常用算法 FNN CNN RNN LSTM DNN GRU 2.深度学习中概念及算法 1. 感知机 感知机&#xff08;Perceptron&#xff09;是一种最早的人工神经网络模型之一&#xff0c;通常用来解决二分类问题。它由弗兰克罗森布拉特&#…...

node.js之---子线程(child_process)模块

为什么需要子线程&#xff08;child_process&#xff09;模块 Worker Threads 的基本概念 如何使用 Worker Threads Worker Threads 的性能 Worker 线程的优势和限制 进阶用法&#xff1a;共享内存 为什么需要子线程&#xff08;child_process&#xff09;模块 在 Node.js…...

Json字符串解析失败

通过第三方服务&#xff0c;拿到响应体的data对象&#xff08;拿到的时候对象是有值的&#xff09; 通过JSON.parseObject方法&#xff0c;拿到的对象&#xff0c;值为null 通过查看对应的json字符串&#xff0c;发现命名不一样... JSONField SeriealizedName注解是用来解析j…...

LeetCode算法题——螺旋矩阵ll

题目描述 给你一个正整数n&#xff0c;生成一个包含1到n2所有元素&#xff0c;且元素按顺时针顺序螺旋排列的n x n正方形矩阵matrix 。 示例 输入&#xff1a;n 3 输出&#xff1a;[[1,2,3],[8,9,4],[7,6,5]]题解 思路&#xff1a; 将整个过程分解为逐圈填充的过程&#xf…...

【开源社区openEuler实践】hpcrunner

title: 探索 Hpcrunner&#xff1a;高性能计算的得力助手 date: ‘2024-12-31’ category: blog tags: Hpcrunner高性能计算任务调度资源优化 sig: HPC archives: ‘2024-12’ author:way_back summary: Hpcrunner 作为高性能计算领域的一款实用工具&#xff0c;专注于优化任务…...

linux下安装达梦数据库v8详解

目录 操作系统、数据库 1、下载达梦数据库 2、安装前准备 2.1、建立数据库用户和组 2.2、修改文件打开最大数 2.3、挂载镜像 2.4、新建安装目录 3、数据库安装 4、配置环境变量 5、初始化数据库实例 6、注册服务 7、使用数据库 8、卸载数据库 9、多实例管理 10、…...

Redis的常用命令

Redis中文字典网站 redis 命令手册https://redis.com.cn/commands.html Keys * 查看当前库所有的key exists ke 判断某个key是否存在 type key查看你的key是什么类型 Del key删除执行的key数据 unlink key非阻塞删除&#xff0c;仅仅将keys从keyspace元数据中删除&#xf…...

Docker入门常用命令总结

1.从远程仓库拉取一个纯净的镜像 docker pull docker .io/centos 2.创建并进入容器&#xff08;左外右内&#xff09; docker run --name xxx -dit 镜像id&#xff08;镜像名称:Tag&#xff09; /bin/bash 【参数必须放在镜像ID之前】 -i 让Docker分配一个伪终端&#xff0c;并…...

【Qt】容器控件、布局管理控件

目录 容器控件 QGroupBox QTabWidget 布局管理控件 QVBoxLayout 例子&#xff1a; QHBoxLayout 例子&#xff1a; QGridLayout 例子&#xff1a; 例子&#xff1a; QFormLayout 例子&#xff1a; QSpacerItem 例子&#xff1a; 容器控件 QGroupBox 表示一个带有…...

cesium小知识:常见的20多种property详解

要详细解释 Cesium 中所有的 Property 类,内容确实会非常丰富且详尽。 Property 基础 Property 是 Cesium 中用于表示随时间或条件变化的值的基础类。它允许你定义属性值如何根据时间、用户交互或其他逻辑动态改变。Property 的设计使得你可以创建复杂的动画和交互效果,而…...

图数据库 | 17、高可用分布式设计(上)

我们在前面的文章中&#xff0c;探索了多种可能的系统扩展方式&#xff0c;以及每种扩展方式的优劣。 本篇文章将通过具体的架构设计方案来对每一种方案的设计、投入产出比、各项指标与功能&#xff0c;以及孰优孰劣等进行评价。 在设计高性能、高可用图数据库的时候&#xf…...

1.运控概述

以下并不是我原创&#xff08;包括图片&#xff09;&#xff0c;都是来源于网络收集。如CSDN博主&#xff0c;朝夕教育&#xff0c;AI等。 什么是运动控制 运控是指“控制移动”之意&#xff0c;可以利用各种电机进行位置控制等操作&#xff0c;让机器听懂你的指令。 什么是…...

DuckDB:密钥管理器及其应用

密钥管理器(Secrets Manager)为所有使用密钥的后端提供了统一的用户界面。密钥信息可以被限定范围&#xff0c;因此不同的存储前缀可以有不同的密钥信息&#xff0c;例如允许在单个查询中连接跨组织的数据。密钥也可以持久化&#xff0c;这样就不需要在每次启动DuckDB时都指定它…...

单元测试4.0+思路总结

Jmockit使用笔记_增加代码覆盖率_覆盖try catch_使用new MockUp私有方法-CSDN博客 一般使用new MockUp模拟被测试代码中的私有方法(常用&#xff09; 使用new Expetations模拟被测试代码中的方法?...

epoll 水平ET跟边缘LT触发的区别是什么

epoll默认的是水平触发 意思就是当我们depoll默认的是水平触发 LT 模式&#xff08;水平触发&#xff09; 工作机制&#xff1a;在 LT 模式下&#xff0c;只要文件描述符&#xff08;例如套接字&#xff09;对应的 I/O 缓冲区中有数据可读或者可写空间&#xff08;对于写操作…...

设计模式 创建型 单例模式(Singleton Pattern)与 常见技术框架应用 解析

单例模式&#xff08;Singleton Pattern&#xff09;是一种创建型设计模式&#xff0c;旨在确保某个类在应用程序的生命周期内只有一个实例&#xff0c;并提供一个全局访问点来获取该实例。这种设计模式在需要控制资源访问、避免频繁创建和销毁对象的场景中尤为有用。 一、核心…...

Java项目实战II基于微信小程序的家庭大厨(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、核心代码 五、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 一、前言 在快节奏的生活中&#xff0c;家庭聚餐成为了连接亲情…...

【JVM】总结篇-字节码篇

字节码篇 Java虚拟机的生命周期 JVM的组成 Java虚拟机的体系结构 什么是Java虚拟机 虚拟机&#xff1a;指以软件的方式模拟具有完整硬件系统功能、运行在一个完全隔离环境中的完整计算机系统 &#xff0c;是物理机的软件实现。常用的虚拟机有VMWare&#xff0c;Visual Box&…...

HTML——28.音频的引入

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>音频引入</title></head><body><!--audio:在网页中引入音频当属性名和属性值一样&#xff0c;可以只写属性名src属性:指定音频文件路径&#xff0c;必…...

Visual Point Cloud Forecasting enables Scalable Autonomous Driving——点云论文阅读(12)

此内容是论文总结,重点看思路!! 文章概述 这篇文章介绍了一个名为 ViDAR 的视觉点云预测框架,它通过预测历史视觉输入生成未来点云,作为自动驾驶的预训练任务。ViDAR 集成了语义、三维几何和时间动态信息,有效提升了感知、预测和规划等自动驾驶核心任务的性能。实验表明…...

《Xsens动捕与人形机器人训练》讲座将于1月9日下午2:30在线上召开

《Xsens动捕与人形机器人训练》讲座将于1月9日下午2:30在线上召开&#xff0c;本次讲座中来自Xsens的人形机器人与动捕技术专家Jeffrey Muller与Dennis Kloppenburg不仅将就Xsens动作捕捉系统与人形机器人行为训练中的实际应用进行详细讲解&#xff0c;同时还会对目前大家所关注…...

Mac 安装 Flutter 提示 A network error occurred while checking

错误信息 A network error occurred while checking "https://maven.google.com/": Operation timed out原因 在中国大陆(由于访问 Google 服务器的限制导致超时),无法连接到 https://maven.google.com/ 解决方案 需要使用镜像网站 #flutter 使用国内的镜像 export …...

形态学:图像处理中的强大工具

在图像处理中&#xff0c;形态学&#xff08;Morphology&#xff09; 是一类基于形状的操作&#xff0c;主要用于提取、分析和处理图像中的几何结构。尽管形态学操作最初是为二值图像设计的&#xff0c;但它也可以应用于灰度图像&#xff0c;帮助提取图像中的结构特征。形态学操…...

树莓派 Pico RP2040 教程点灯 双核编程案例

双核点亮不同的 LED 示例&#xff0c;引脚分别是GP0跟GP1。 #include "pico/stdlib.h" #include "pico/multicore.h"#define LED1 0 // 核心 0 控制的 LED 引脚 #define LED2 1 // 核心 1 控制的 LED 引脚// the setup function runs once when you press …...

2024年大型语言模型(LLMs)的发展回顾

2024年对大型语言模型&#xff08;LLMs&#xff09;来说是充满变革的一年。以下是对过去一年中LLMs领域的关键进展和主题的总结。 GPT-4的壁垒被打破 去年&#xff0c;我们还在讨论如何构建超越GPT-4的模型。如今&#xff0c;已有18个组织拥有在Chatbot Arena排行榜上超越原…...