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

28.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--单体转微服务--币种服务(二)

仅有币种服务还不够,记账应用还需支持不同币种间的转换。要实现这一功能,首先需要获取币种之间的汇率。因此,本文将介绍如何实现汇率的同步。

一、汇率数据从何而来?

汇率数据无时无刻都在变动,因此需要一个可靠的来源来获取最新的汇率信息。通常可以通过以下几种方式获取:

  • 爬取数据:一些专业的金融数据服务商提供汇率数据,可以通过订阅获取。
  • 手动输入:对于小型应用,可以手动输入汇率数据,但这不适合大规模或实时更新的应用。
  • 第三方API:许多金融服务提供商提供免费的或付费的API接口,可以获取实时汇率数据。

下面,我们对这三种方式做一个简单的对比,选择出最适合的获取汇率的方式。首先,爬取数据,需要编写爬虫程序,而且还要无时无刻的关注数据源的变动,比如:页面的变化,数据格式的变化等,这样的工作量是非常大的。而且,编写爬虫获取数据具有一定的法律风险,除非在得到数据源许可的情况,方可爬取。其次,手动输入汇率数据虽然简单,但不适合需要频繁更新的应用,应用管理员每天都要录入汇率数据,这样的工作量也是非常大的。最后,第三方API,通过API获取汇率数据是最简单、最可靠的方式。只需要调用API接口,就可以获取最新的汇率数据,而且大多数API提供商会定期更新数据,确保数据的准确性和实时性。因此,我们的项目将采用第三方API的方式来获取汇率数据。

在选择第三方API时,要考虑一下几点:

  • 数据的准确性:确保API提供的数据是可靠的,最好是由知名金融机构或服务商提供。
  • 更新频率:汇率数据需要实时更新,选择一个更新频率高的API。
  • 使用成本:有些API是免费的,但有些可能需要付费,需要根据项目的预算来选择。
  • 易用性:API的文档和使用方式是否清晰,是否容易集成到现有项目中。

在本文中,我们将使用 exchangerate api 提供的汇率API来获取汇率数据。这个API提供了多种币种之间的汇率转换功能,它有免费版、专业版和商业版三个版本,免费版汇率更新频率是一天更新一次,每月1500次的调用请求,专业版是每小时更新一次,每月3000次的调用请求,商业版是每五分钟更新一次,每月12500次的调用请求。对于我们的项目来说,免费版已经满足我们使用了,因此我们将使用免费版的API。

Tip:具体注册和使用方式这里就不讲解了,可以参考 exchangerate api 的官方文档。

二、汇率数据获取

在币种服务SP.CurrencyService中,新建Task文件夹,这个文件夹将作为币种服务的定时任务类的文件夹,然后在这个文件夹下新建ExchangeRate文件夹作为存储汇率数据获取的定时任务类的文件夹。接着在ExchangeRate文件夹下新建ExchangeRateApiData.cs类文件,代码如下:

using System.Text.Json.Serialization;namespace SP.CurrencyService.Task.ExchangeRate;// <summary>
// 存储从汇率API获取的数据
// </summary>
public class ExchangeRateApiData
{/// <summary>/// 数据状态/// </summary>[JsonPropertyName("result")]public string Result { get; set; }/// <summary>/// 数据文档/// </summary>[JsonPropertyName("documentation")]public string Documentation { get; set; }/// <summary>/// 数据条款/// </summary>[JsonPropertyName("terms_of_use")]public string TermsOfUse { get; set; }/// <summary>/// 上次更新数据时间戳/// </summary>[JsonPropertyName("time_last_update_unix")]public long TimeLastUpdateUnix { get; set; }/// <summary>/// 上次更新数据时间/// </summary>[JsonPropertyName("time_last_update_utc")]public string TimeLastUpdateUtc { get; set; }/// <summary>/// 下次更新数据时间戳/// </summary>[JsonPropertyName("time_next_update_unix")]public long TimeNextUpdateUnix { get; set; }/// <summary>/// 下次更新数据时间/// </summary>[JsonPropertyName("time_next_update_utc")]public string TimeNextUpdateUtc { get; set; }/// <summary>/// 基础货币代码/// </summary>[JsonPropertyName("base_code")]public string BaseCode { get; set; }/// <summary>/// 汇率集合/// </summary>[JsonPropertyName("conversion_rates")]public Dictionary<string, decimal> ConversionRates { get; set; }
}

该类中包含了从exchangerate api获取的汇率数据的各个字段,使用了JsonPropertyName特性来指定JSON序列化时的字段名称。

接着,新建ExchangeRateTimer.cs类文件,这个类将作为获取汇率数据的定时任务类,代码如下:

using System.Text.Json;
using Quartz;
using SP.CurrencyService.Models.Entity;
using SP.CurrencyService.Models.Response;
using SP.CurrencyService.Service;namespace SP.CurrencyService.Task.ExchangeRate;/// <summary>
/// 获取汇率定时器
/// </summary>
public class ExchangeRateTimer : IJob
{private readonly IHttpClientFactory _httpClientFactory;private readonly IConfiguration _configuration;private readonly IServiceScopeFactory _serviceScopeFactory;private readonly ICurrencyServer _currencyServer;/// <summary>/// 构造函数/// </summary>/// <param name="httpClientFactory"></param>/// <param name="configuration"></param>/// <param name="serviceScopeFactory"></param>/// <param name="currencyServer"></param>public ExchangeRateTimer(IHttpClientFactory httpClientFactory,IConfiguration configuration, IServiceScopeFactory serviceScopeFactory,ICurrencyServer currencyServer){_httpClientFactory = httpClientFactory;_configuration = configuration;_serviceScopeFactory = serviceScopeFactory;_currencyServer = currencyServer;}/// <summary>/// 执行/// </summary>/// <param name="context"></param>/// <returns></returns>public System.Threading.Tasks.Task Execute(IJobExecutionContext context){string exchangeRateUrl = _configuration["ExchangeRate"];//获取全部币种List<CurrencyResponse> currencies = _currencyServer.Query().ToList();//获取对每种币种的汇率foreach (var currency in currencies){_httpClientFactory.CreateClient().GetAsync($"{exchangeRateUrl}{currency.Abbreviation}").ContinueWith(response =>{using var scope = _serviceScopeFactory.CreateScope();var exchangeRateRecordService =scope.ServiceProvider.GetRequiredService<IExchangeRateRecordServer>();List<ExchangeRateRecord> exchangeRateRecords = new();if (response.Result.IsSuccessStatusCode){var result = response.Result.Content.ReadAsStringAsync().Result;var resultModel = JsonSerializer.Deserialize<ExchangeRateApiData>(result);if (resultModel?.Result == "success"){foreach (var rate in resultModel.ConversionRates){//只获取人民币、日元、欧元、韩元、美元、港币、澳门元、英镑、新台币之间的汇率//其他币种的汇率直接跳过if (currencies.All(c => c.Abbreviation != rate.Key)){continue;}exchangeRateRecords.Add(new ExchangeRateRecord{ExchangeRate = rate.Value,//汇率记录的币种代码是基础币种代码和目标币种代码的组合ConvertCurrency = $"{resultModel.BaseCode}_{rate.Key}",SourceCurrencyId = currency.Id,TargetCurrencyId = currencies.First(c => c.Abbreviation == rate.Key).Id,Date = DateTime.Now,CreateDateTime = DateTime.Now,CreateUserId = 7333155174099406848,IsDeleted = false});}//存入数据库exchangeRateRecordService.Add(exchangeRateRecords);}}});}return System.Threading.Tasks.Task.CompletedTask;}
}

该类实现了IJob接口,表示这是一个Quartz定时任务。它的构造函数接受了IHttpClientFactoryIConfigurationIServiceScopeFactory三个参数,分别用于创建HTTP客户端、获取配置和创建服务作用域。Execute方法是定时任务的执行入口,首先从配置中获取汇率API的URL,然后查询所有币种信息。接着,对于每个币种,通过HTTP客户端调用汇率API获取该币种的汇率数据,并将结果存储到数据库中。

Tip:这里使用了异步的方式来处理HTTP请求,以避免阻塞定时任务的执行。每次获取汇率数据后,都会创建一个新的服务作用域,以确保在多线程环境下能够正确地访问数据库。

最后,我们需要将这个定时任务注册到Quartz中。在Program.cs文件中,添加以下代码:

// 添加定时任务
builder.Services.AddQuartz(q =>
{var exchangeRateTimerJobKey = new JobKey("ExchangeRateTimer");q.AddJob<ExchangeRateTimer>(opts => opts.WithIdentity(exchangeRateTimerJobKey));q.AddTrigger(opts => opts.ForJob(exchangeRateTimerJobKey).WithIdentity("ExchangeRateTimerTrigger").StartNow().WithCronSchedule("0 0 1 * * ?"));
});
builder.Services.AddQuartzHostedService(options =>
{//启用 Quartz 的托管服务,`WaitForJobsToComplete = true` 表示在应用程序停止时等待任务完成后再关闭。options.WaitForJobsToComplete = true;
});

这段代码将ExchangeRateTimer定时任务注册到Quartz中,并设置为每天凌晨1点执行一次。AddQuartzHostedService方法用于启用Quartz的托管服务,确保在应用程序停止时等待任务完成后再关闭。

三、总结

通过以上步骤,我们成功实现了从第三方API获取汇率数据的功能,并将其存储到数据库中。这个功能为币种服务提供了强大的支持,使得记账应用能够处理不同币种之间的转换和汇率计算。

http://www.xdnf.cn/news/15861.html

相关文章:

  • Spring Boot 配置文件解析
  • SpringBoot集成MyBatis的SQL拦截器实战
  • Java学习第六十部分——JVM
  • [硬件电路-52]:什么是模拟电路与数字电路;它们的共同点、核心差异点(原理、目标、关注点等)以及它们如何相互转化
  • LeetCode 852:山脉数组的峰顶索引解析与实现
  • STM32CubeMX的一些操作步骤的作用
  • 7-20 关于mysql
  • 网络安全隔离技术解析:从网闸到光闸的进化之路
  • 【硬件】GalaxyTabPro10.1(SM-T520)刷机/TWRP/LineageOS14/安卓7升级小白向保姆教程
  • RxSwift-事件属性
  • JVM-Java
  • LINUX(三)文件I/O、对文件打开、读、写、偏移量
  • 股票及金融笔记
  • 使用Qt6 QML/C++ 和CMake构建海康威视摄像头应用(代码开源)
  • 双8无碳小车“cad【17张】三维图+设计说名书
  • 【橘子分布式】gRPC(编程篇-下)
  • 嵌入式硬件篇---机械臂运动学解算(3自由度)
  • 机器学习-数据预处理
  • 【机器学习【9】】评估算法:数据集划分与算法泛化能力评估
  • 物联网安装调试-继电器
  • Java设计模式之行为型模式(备忘录模式)实现方式与测试用例
  • 【Unity3D实例-功能-移动】角色移动-通过WSAD(CharacterController方式)
  • 第四次作业
  • haproxy七层代理
  • 嵌入式硬件篇---继电器
  • C#.NET EFCore.BulkExtensions 扩展详解
  • 物联网安装调试-温湿度传感器
  • 分布式文件系统04-DataNode海量数据分布式高可靠存储
  • python中读取 Excel 表格数据
  • 【数据结构】揭秘二叉树与堆--用C语言实现堆