(一)微服务(垂直AP/分布式缓存/装饰器Pattern)


文章目录

  • 项目地址
  • 一、创建第一个垂直API
    • 1.1 创建Common层
      • 1. ICommand接口
      • 2. IQuery接口
    • 1.2 创建API
      • 1. 实体
      • 2. Handler
      • 3. endpoint
    • 1.3 使用Marten作为ORM
  • 二、Redis缓存
    • 2.1 使用缓存装饰器
      • 1. 创建装饰器
      • 2. 注册装饰器
    • 2.2 创建docker-compose
      • 1. docker-compose
      • 2. docker-compose.override


项目地址

  • 教程作者:
  • 教程地址:
  • 代码仓库地址:
  • 所用到的框架和插件:
dbt 
airflow

一、创建第一个垂直API

1.1 创建Common层

在这里插入图片描述

1. ICommand接口

  1. ICommand.cs
using MediatR;
namespace BuildingBlocks.CQRS;
public interface ICommand : ICommand<Unit>; 
public interface ICommand<out TResponse> : IRequest<TResponse>;
  1. ICommandHandler.cs
using MediatR;
namespace BuildingBlocks.CQRS;
public interface ICommandHandler<in TCommand>  //无返回值: ICommandHandler<TCommand, Unit>where TCommand : ICommand<Unit>;public interface ICommandHandler<in TCommand, TResponse> //有返回值: IRequestHandler<TCommand, TResponse>where TCommand : ICommand<TResponse>where TResponse : notnull;

in(Contravariant):只在参数中使用的泛型类型

2. IQuery接口

  1. IQuery.cs
using MediatR;
namespace BuildingBlocks.CQRS;
public interface IQuery<out TResponse> : IRequest<TResponse>  where TResponse : notnull;
  1. IQueryHandler:
namespace BuildingBlocks.CQRS;
public interface IQueryHandler<in TQuery, TResponse>: IRequestHandler<TQuery, TResponse>where TQuery : IQuery<TResponse>where TResponse : notnull;

1.2 创建API

在这里插入图片描述

1. 实体

namespace Catalog.API.Models;
public class Product
{public Guid Id { get; set; }public string Name { get; set; } = default!;public List<string> Category { get; set; } = new();public string Description { get; set; } = default!;public string ImageFile { get; set; } = default!;public decimal Price { get; set; }
}

2. Handler

namespace Catalog.API.Products.CreateProduct;
public record CreateProductCommand(string Name, List<string> Category, string Description, string ImageFile, decimal Price): ICommand<CreateProductResult>;
public record CreateProductResult(Guid Id);internal class CreateProductCommandHandler : ICommandHandler<CreateProductCommand, CreateProductResult>
{public async Task<CreateProductResult> Handle(CreateProductCommand command, CancellationToken cancellationToken){var product = new Product{Name = command.Name,Category = command.Category,Description = command.Description,ImageFile = command.ImageFile,Price = command.Price};return new CreateProductResult(Guid.NewGuid());        }
}

3. endpoint

namespace Catalog.API.Products.CreateProduct;
public record CreateProductRequest(string Name, List<string> Category, string Description, string ImageFile, decimal Price);
public record CreateProductResponse(Guid Id);
public class CreateProductEndpoint : ICarterModule
{public void AddRoutes(IEndpointRouteBuilder app){app.MapPost("/products",async (CreateProductRequest request, ISender sender) =>{var command = request.Adapt<CreateProductCommand>();var result = await sender.Send(command);var response = result.Adapt<CreateProductResponse>();return Results.Created($"/products/{response.Id}", response);}).WithName("CreateProduct").Produces<CreateProductResponse>(StatusCodes.Status201Created).ProducesProblem(StatusCodes.Status400BadRequest).WithSummary("Create Product").WithDescription("Create Product");}
}

1.3 使用Marten作为ORM

  • Marten只能用于postgresql的ORM使用

二、Redis缓存

2.1 使用缓存装饰器

1. 创建装饰器

  • 给basket添加装饰器,原来的 var basket = await repository.GetBasket(userName, cancellationToken);被其他的方法包裹,这样就被装饰了
 namespace Basket.API.Data;public class CachedBasketRepository(IBasketRepository repository, IDistributedCache cache) : IBasketRepository
{public async Task<ShoppingCart> GetBasket(string userName, CancellationToken cancellationToken = default){var cachedBasket = await cache.GetStringAsync(userName, cancellationToken);if (!string.IsNullOrEmpty(cachedBasket))return JsonSerializer.Deserialize<ShoppingCart>(cachedBasket)!;var basket = await repository.GetBasket(userName, cancellationToken);await cache.SetStringAsync(userName, JsonSerializer.Serialize(basket), cancellationToken);return basket;}public async Task<ShoppingCart> StoreBasket(ShoppingCart basket, CancellationToken cancellationToken = default){await repository.StoreBasket(basket, cancellationToken);await cache.SetStringAsync(basket.UserName, JsonSerializer.Serialize(basket), cancellationToken);return basket;}public async Task<bool> DeleteBasket(string userName, CancellationToken cancellationToken = default){await repository.DeleteBasket(userName, cancellationToken);await cache.RemoveAsync(userName, cancellationToken);return true;}
}

2. 注册装饰器

  • 安装需要的包
     <PackageReference Include="Scrutor" Version="4.2.2" /><PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.1" />
  • 注册装饰器
builder.Services.AddScoped<IBasketRepository, BasketRepository>(); //原来的方法
builder.Services.Decorate<IBasketRepository, CachedBasketRepository>();  //装饰过后带redis缓存的//注册redis
builder.Services.AddStackExchangeRedisCache(options =>
{options.Configuration = builder.Configuration.GetConnectionString("Redis");//options.InstanceName = "Basket";
});  
  • 配置redis 的ConnectionString
 appsettings.json

2.2 创建docker-compose

1. docker-compose

  1. docker-compose.yml 用来说明微服务需要的Container有哪些
version: '3.4'
services:catalogdb:image: postgresbasketdb:image: postgresdistributedcache:image: rediscatalog.api:image: ${DOCKER_REGISTRY-}catalogapibuild:context: .dockerfile: Services/Catalog/Catalog.API/Dockerfilebasket.api:image: ${DOCKER_REGISTRY-}basketapibuild:context: .dockerfile: Services/Basket/Basket.API/Dockerfile
volumes:postgres_catalog:postgres_basket:

2. docker-compose.override

  • 用来配置本地具体环境
version: '3.4'services:catalogdb:container_name: catalogdbenvironment:- POSTGRES_USER=postgres- POSTGRES_PASSWORD=postgres- POSTGRES_DB=CatalogDbrestart: alwaysports:- "5432:5432"volumes:- postgres_catalog:/var/lib/postgresql/data/ basketdb:container_name: basketdbenvironment:- POSTGRES_USER=postgres- POSTGRES_PASSWORD=postgres- POSTGRES_DB=BasketDbrestart: alwaysports:- "5433:5432"volumes:- postgres_basket:/var/lib/postgresql/data/ distributedcache:container_name: distributedcacherestart: alwaysports:- "6379:6379"catalog.api:environment:- ASPNETCORE_ENVIRONMENT=Development- ASPNETCORE_HTTP_PORTS=8080- ASPNETCORE_HTTPS_PORTS=8081- ConnectionStrings__Database=Server=catalogdb;Port=5432;Database=CatalogDb;User Id=postgres;Password=postgres;Include Error Detail=truedepends_on:- catalogdbports:- "6000:8080"- "6060:8081"volumes:- ${APPDATA}/Microsoft/UserSecrets:/home/app/.microsoft/usersecrets:ro- ${APPDATA}/ASP.NET/Https:/home/app/.aspnet/https:robasket.api:environment:- ASPNETCORE_ENVIRONMENT=Development- ASPNETCORE_HTTP_PORTS=8080- ASPNETCORE_HTTPS_PORTS=8081- ConnectionStrings__Database=Server=basketdb;Port=5432;Database=BasketDb;User Id=postgres;Password=postgres;Include Error Detail=true- ConnectionStrings__Redis=distributedcache:6379depends_on:- basketdb- distributedcacheports:- "6001:8080"- "6061:8081"volumes:- ${APPDATA}/Microsoft/UserSecrets:/home/app/.microsoft/usersecrets:ro- ${APPDATA}/ASP.NET/Https:/home/app/.aspnet/https:ro

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

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

相关文章

Spring AI系列之使用 Spring AI 转录音频文件(基于OpenAI)

概述 企业常常需要从各种类型的音频内容中提取有价值的数据&#xff0c;例如&#xff1a;将客户支持通话转录用于情感分析、为视频生成字幕&#xff0c;或整理会议纪要。然而&#xff0c;手动转录音频文件既耗时又昂贵。 为了解决这一问题&#xff0c;OpenAI 提供了强大的语…

室内VR全景助力房产营销及装修

在当今的地产行业&#xff0c;VR全景已成为不可或缺的应用工具。从地产直播到楼市VR地图&#xff0c;从效果图到水电家装施工记录&#xff0c;整个地产行业的上下游生态中&#xff0c;云VR全景的身影无处不在。本文将探讨VR全景在房产营销及装修领域的应用&#xff0c;并介绍众…

Sentinel限流熔断机制实战

1、核心概念 1.1、流量控制 流量控制是为了 防止系统被过多的请求压垮&#xff0c;确保资源合理分配并保持服务的可用性&#xff0c;比如对请求数量的限制。 流量控制的 3 个主要优势&#xff1a; 防止过载&#xff1a;当瞬间涌入的请求量超出系统处理能力时&#xff0c;会…

深度解析 torch.mean 的替代方案

torch.mean 是什么意思 代码效果解释 segment_vector = torch.mean(segment_embedding, dim=1) # [1, hidden_dim] 这行代码的作用是在指定维度上对张量 segment_embedding 求平均值,实现类似平均池化的效果。 具体来说,dim=1 表示沿着索引为1的维度进行操作。假设 segment…

Paraformer语音模型:一种语音模型加速方法

随着智能语音技术的普及&#xff0c;语音识别&#xff08;ASR&#xff09;、语音合成&#xff08;TTS&#xff09;、声纹识别等应用场景对模型推理效率提出了极高要求&#xff0c;本文介绍将Paraformer语音模型从预训练模型导出为ONNX格式&#xff0c;并使用ONNX Runtime进行推…

本地部署FreeGPT+内网穿透公网远程访问,搞定ChatGPT外网访问难题

‌FreeGPT‌是一个基于GPT 3.5/4的ChatGPT聊天网页用户界面&#xff0c;提供了一个开放的聊天界面&#xff0c;开箱即用‌。ChatGPT是非常热门的&#xff0c;但访问体验一直不太理想。为了解决这一问题&#xff0c;出现了各类方法和工具&#xff0c;其中FreeGPT是一款非常实用的…

ElasticSearch迁移至openGauss

Elasticsearch 作为一种高效的全文搜索引擎&#xff0c;广泛应用于实时搜索、日志分析等场景。而 openGauss&#xff0c;作为一款企业级关系型数据库&#xff0c;强调事务处理与数据一致性。那么&#xff0c;当这两者的应用场景和技术架构发生交集时&#xff0c;如何实现它们之…

品优购项目(HTML\CSS)

项目效果可访问 http://zhousunyu.3vdo.club 查看 主页 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><titl…

因泰立科技:镭眸T51激光雷达,打造智能门控新生态

在高端门控行业&#xff0c;安全与效率是永恒的追求。如今&#xff0c;随着科技的飞速发展&#xff0c;激光雷达与TOF相机技术的融合&#xff0c;为门控系统带来了前所未有的智能感知能力&#xff0c;开启了精准守护的新时代。因泰立科技的镭眸T51激光雷达&#xff0c;作为这一…

MyBatisPlus--快速入门

MyBatisPlus介绍 从名字中就可以感觉到MybatisPlus与MyBatis之间的渊源&#xff0c;而MyBatis是一个非常流行的持久层框架&#xff0c;主要来做数据库的增删改查&#xff0c;而MyBatisPlus这种命名方式让人不得不往MyBatis的升级版去联想&#xff0c;事实也确实如此&#xff0…

redis持久化策略

RDB 是通过生成数据快照来实现持久化的&#xff0c;相当于给内存中的数据拍一张"照片"保存到磁盘上。AOF 记录所有写操作命令&#xff0c;以Redis协议格式追加到文件末尾。 RDB 在满足特定条件时触发内存快照&#xff0c;生成新的RDB文件替换旧文件 AOF 先写入内…

Spring Boot中使用@JsonAnyGetter和@JsonAnySetter处理动态JSON属性

Spring Boot 中使用 @JsonAnyGetter 和 @JsonAnySetter 处理动态 JSON 属性 在实际的后端开发中,尤其是使用 Spring Boot 构建 API 时,我们经常会遇到需要处理动态 JSON 属性的场景。例如,前端传递过来的 JSON 数据结构不固定,或者业务需求变更频繁,导致实体类无法预先定…

拉取gitlab项目

一、下载nvm管理node 先下载配置好nvm,再用nvm下载node 下载链接&#xff1a;开始 下载nvm - nvm中文官网 情况&#xff1a;npm i 下载依赖缓慢&#xff0c;可能是node版本不对&#xff0c;可能node版本太高 可能得问题&#xff1a;使用nvm 下载低版本的node时&#xff0c;…

【解决办法】ubuntu重启不起来,输入用户名和密码进不去,又重新返回登录页。

项目场景&#xff1a; ubuntu重启不起来&#xff0c;输入用户名和密码进不去&#xff0c;又重新返回登录页。 问题描述 在华硕天选一代笔记本上面安装了ubuntu22.04.5桌面版&#xff0c;但是重启以后出现&#xff0c;输入了用户名和密码&#xff0c;等待一会还让输入用户名和…

# 云端大模型:智能时代的新引擎

云端大模型&#xff1a;智能时代的新引擎 在人工智能技术的迅猛发展中&#xff0c;云端大模型扮演着至关重要的角色。它们不仅推动了技术的边界&#xff0c;也为各行各业带来了前所未有的机遇。本文将结合一系列图片和代码示例&#xff0c;深入探讨云端大模型的功能、应用及其…

(1)pytest简介和环境准备

1. pytest简介 pytest是python的一种单元测试框架&#xff0c;与python自带的unittest测试框架类似&#xff0c;但是比unittest框架使用起来更简洁&#xff0c;效率更高。根据pytest的官方网站介绍&#xff0c;它具有如下特点&#xff1a; 非常容易上手&#xff0c;入门简单&a…

实验设计与分析(第6版,Montgomery)第5章析因设计引导5.7节思考题5.5 R语言解题

本文是实验设计与分析&#xff08;第6版&#xff0c;Montgomery著&#xff0c;傅珏生译) 第5章析因设计引导5.7节思考题5.5 R语言解题。主要涉及方差分析&#xff0c;正态假设检验&#xff0c;残差分析&#xff0c;交互作用图。 dataframe <-data.frame( wrapc(17,20,12,9,…

线程池的详细知识(含有工厂模式)

前言 下午学习了线程池的知识。重点探究了ThreadPoolExecutor里面的各种参数的含义。我详细了解了这部分的知识。其中有一个参数涉及工厂模式&#xff0c;我将这一部分知识分享给大家~ 线程池的详细介绍(含工厂模式) 结语 分享到此结束啦。byebye~

嵌入式开发学习(第二阶段 C语言笔记)

内存操作 我们对于内存操作需要依赖于string.h头文件中相关的函数库。 内存操作函数 内存填充 头文件&#xff1a;#include <string.h> 函数原型&#xff1a; void* memset(void *s,int c,size_t n)函数功能&#xff1a;将内存块s的前n个字节填充为c&#xff0c;一般…

C++学习-入门到精通【9】面向对象编程:继承

C学习-入门到精通【9】面向对象编程&#xff1a;继承 目录 C学习-入门到精通【9】面向对象编程&#xff1a;继承一、基类与派生类CommunityMember类的继承层次结构如何定义一个派生类呢 二、基类和派生类间的关系1.创建并使用类CommissionEmployee2.不使用继承创建类BasePlusCo…