使用 ABP vNext 集成 MinIO 构建高可用 BLOB 存储服务
🚀 使用 ABP vNext 集成 MinIO 构建高可用 BLOB 存储服务
本文基于 ABP vNext + MinIO 的对象存储集成实践,系统讲解从 MinIO 部署、桶创建、ABP 集成、上传 API、安全校验、预签名访问,到测试、扩展及多租户支持的全过程。目标是构建一套可复现、可维护、可扩展的企业级文件存储服务。
📚 目录
- 🚀 使用 ABP vNext 集成 MinIO 构建高可用 BLOB 存储服务
- 📘 背景与目标
- 🏗 技术架构与依赖
- 🏗️ 系统架构流程图
- 🔧 MinIO部署与桶准备
- 🛠 集成 MinIO 到 ABP 项目
- 1️⃣ 安装 NuGet 包
- 2️⃣ 配置 appsettings.json
- 3️⃣ 模块注册 + 自动建桶
- 🛠️ 桶自动创建流程图
- 🧩 上传服务封装
- 定义容器接口
- 实现上传服务
- 🧩 上传流程图
- 🛡 上传接口(权限 + 预览链接)
- 🔗 访问链接生成服务
- 🔗 预签名流程图
- 🧠 扩展建议
📘 背景与目标
非结构化数据(图片、视频、PDF 等)管理是现代应用中的常见需求,尤其在多租户系统中,对存储隔离、安全、预览等能力要求更高。ABP vNext 提供了 BlobStoring 模块,MinIO 提供 S3 兼容的存储服务,两者结合可构建灵活高可用的文件服务系统。
🏗 技术架构与依赖
- 框架:ABP vNext
- 对象存储:MinIO(兼容 S3)
- NuGet 依赖:
Volo.Abp.BlobStoring.AmazonS3
AWSSDK.S3
- 部署方式:Docker 容器部署 MinIO
🏗️ 系统架构流程图
🔧 MinIO部署与桶准备
docker run -d -p 9000:9000 -p 9001:9001 \--name minio \-e MINIO_ROOT_USER=admin \-e MINIO_ROOT_PASSWORD=admin123 \-v /data/minio:/data \minio/minio server /data --console-address ":9001"
📍 管理控制台:http://localhost:9001
🔐 用户密码:admin / admin123
📦 桶名(Bucket):demo-bucket
(可手动或代码创建)
🛠 集成 MinIO 到 ABP 项目
1️⃣ 安装 NuGet 包
dotnet add package Volo.Abp.BlobStoring.AmazonS3
dotnet add package AWSSDK.S3
2️⃣ 配置 appsettings.json
"Abp": {"BlobStoring": {"AmazonS3": {"AccessKey": "admin","SecretKey": "admin123","RegionEndpoint": "us-east-1","BucketName": "demo-bucket","ServiceUrl": "http://localhost:9000","ForcePathStyle": true}}
},
"BlobStorage": {"BasePreviewUrl": "http://localhost:9000/demo-bucket/"
}
3️⃣ 模块注册 + 自动建桶
public class BlobStorageOptions
{public string BasePreviewUrl { get; set; } = string.Empty;
}public class DemoApplicationModule : AbpModule
{public override void ConfigureServices(ServiceConfigurationContext context){var config = context.Services.GetConfiguration();context.Services.Configure<BlobStorageOptions>(config.GetSection("BlobStorage"));context.Services.AddSingleton<IAmazonS3>(_ =>new AmazonS3Client("admin", "admin123", new AmazonS3Config{ServiceURL = "http://localhost:9000",ForcePathStyle = true}));context.Services.AddSingleton<IBlobUrlGenerator, BlobUrlGenerator>();context.Services.AddScoped<IS3SignedUrlService, S3SignedUrlService>();Configure<AbpBlobStoringOptions>(opt =>{opt.Containers.Configure<DemoBlobContainer>(c => c.UseAmazonS3());});}public override void OnApplicationInitialization(ApplicationInitializationContext context){var s3 = context.ServiceProvider.GetRequiredService<IAmazonS3>();AsyncHelper.RunSync(async () =>{const string bucket = "demo-bucket";if (!(await s3.DoesS3BucketExistAsync(bucket))){await s3.PutBucketAsync(bucket);}});}
}
🛠️ 桶自动创建流程图
🧩 上传服务封装
定义容器接口
[BlobContainer("demo-bucket")]
public interface IDemoBlobContainer : IBlobContainer {}
实现上传服务
public class FileAppService : ApplicationService
{private readonly IDemoBlobContainer _container;private readonly ILogger<FileAppService> _logger;public FileAppService(IDemoBlobContainer container, ILogger<FileAppService> logger){_container = container;_logger = logger;}public async Task<string> UploadAsync(IFormFile file){if (file == null || file.Length == 0)throw new UserFriendlyException("文件不能为空");var ext = Path.GetExtension(file.FileName).ToLower();var allowed = new[] { ".png", ".jpg", ".pdf" };if (!allowed.Contains(ext))throw new UserFriendlyException("文件类型不支持");var tenantId = CurrentTenant.Id?.ToString() ?? "public";var folder = $"{tenantId}/{DateTime.UtcNow:yyyy/MM/dd}";var fileName = $"{folder}/{Guid.NewGuid()}{ext}";await using var stream = file.OpenReadStream();_logger.LogInformation("上传文件:{File}", fileName);await _container.SaveAsync(fileName, stream, true);return fileName;}
}
🧩 上传流程图
🛡 上传接口(权限 + 预览链接)
[Authorize]
[Route("api/files")]
public class FileController : AbpController
{private readonly FileAppService _appService;private readonly IBlobUrlGenerator _urlGen;public FileController(FileAppService appService, IBlobUrlGenerator urlGen){_appService = appService;_urlGen = urlGen;}[HttpPost]public async Task<IActionResult> Upload(IFormFile file){var path = await _appService.UploadAsync(file);var url = _urlGen.Generate(path);return Ok(new { path, url });}
}
🔗 访问链接生成服务
public interface IBlobUrlGenerator
{string Generate(string path);
}public class BlobUrlGenerator : IBlobUrlGenerator
{private readonly BlobStorageOptions _options;public BlobUrlGenerator(IOptions<BlobStorageOptions> options) => _options = options.Value;public string Generate(string path){return new Uri(new Uri(_options.BasePreviewUrl), path).ToString();}
}
🔗 预签名流程图
🧠 扩展建议
能力 | 实践方式 |
---|---|
✅ 多租户隔离 | 按租户ID生成路径前缀 |
✅ 安全预览 | 使用 GetPreSignedUrlRequest 生成限时链接 |
✅ 文件分层存储 | 使用日期+租户组合分目录 |
✅ 重试与监控 | 注入 Polly 重试策略 + OpenTelemetry 埋点 |
✅ 单元测试 | 使用 ReplaceService 注入 InMemoryBlobContainer |
相关文章:
使用 ABP vNext 集成 MinIO 构建高可用 BLOB 存储服务
🚀 使用 ABP vNext 集成 MinIO 构建高可用 BLOB 存储服务 本文基于 ABP vNext MinIO 的对象存储集成实践,系统讲解从 MinIO 部署、桶创建、ABP 集成、上传 API、安全校验、预签名访问,到测试、扩展及多租户支持的全过程。目标是构建一套可复…...
3.安卓逆向2-安卓文件目录
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 内容参考于:图灵Python学院 上一个内容:2.安卓逆向2-adb指令 首先使用adb连接到手机,如下图使用adb命令列出手机的目录&am…...
云原生时代的系统可观测性:理念变革与实践体系
📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:为什么可观测性在云原生时代变得更加重要? 传统应用系统运行于固定服务器,拓扑结构稳定、依赖路径清晰,排查故障依赖日志和人工经验已足够支撑运维。但在云原生环境中,系统正快速演变为: 微…...
力扣网-复写零
1.题目要求 2.题目链接 1089. 复写零 - 力扣(LeetCode) 3.题目解答 class Solution {public void duplicateZeros(int[] arr) {int cur0,dest-1,narr.length;while(cur<n){//遇到0就dest走两步if(arr[cur]0){dest2;}//遇到非零元素dest就走一步els…...
高项-挣值管理TCPI
TCPI(完工尚需绩效指数)的英文全称及含义 TCPI 是项目管理(尤其是挣值管理EVM, Earned Value Management)中的一个关键指标,其英文全称为: To-Complete Performance Index 中文译为**“完工尚需绩效指数”…...
Java大厂面试三轮问答:微服务与数据库技术深度解析
Java大厂面试:谢飞机的三轮挑战 第一轮:微服务基础与电商场景设计 面试官: "谢飞机,假设我们要设计一个电商平台,需要支持用户下单、支付以及订单追踪。你会如何设计微服务架构?" 谢飞机: "呃&#…...
Linux 移植 Docker 详解
一、移植前的环境准备 在将 Docker 移植到 Linux 系统之前,需要确保系统满足一定的条件,以保证 Docker 能够稳定运行。 1. 操作系统版本要求 Docker 对 Linux 操作系统版本有一定的要求,不同的 Docker 版本适配不同的 Linux 发行版及版本。常…...
滑动验证码缺口识别与自动化处理技术解析
在如今的网络安全环境中,滑动验证码作为一种主流的人机验证方案,被广泛应用。它的核心挑战主要集中在两个方面:一是如何准确地识别出缺口位置,二是如何模拟出逼真的拖动轨迹。 一、缺口识别技术方案 (一)…...
C++字符串处理:`std::string`和`std::string_view`的区别与使用
在 C中,std::string和std::string_view都用于处理字符串,但它们的用途和性能特点有很大不同。本教程将通过代码示例和流程图,帮助你快速掌握它们的使用方法。 1.什么是std::string和std::string_view? 1.1std::string std::str…...
Uniapp中动态控制scroll-view滚动的方式
在Uniapp 4.45中,动态修改scroll-view的scroll-left属性时无法触发滚动(直接设置scroll-left属性值没问题),这通常是因为数据更新与 DOM 渲染之间的异步特性导致的。知道了原因,但是直接修改scroll-left属性值还是失败…...
手机怎么查看网络ip地址?安卓/iOS设备查询指南
在移动互联网时代,IP地址作为设备的网络身份证,无论是网络调试、远程连接还是排查故障都至关重要。本文将系统介绍安卓和iOS设备查看IP地址的多种方法,帮助您快速掌握这一实用技能。 一、安卓手机查看IP地址方法 1、通过WiFi设置查看 打开设…...
R语言+贝叶斯网络:涵盖贝叶斯网络的基础、离散与连续分布、混合网络、动态网络,Gephi可视化,助你成为数据分析高手!
🔍 在现代生态、环境及地学研究中,变量及其因果关系的推断是核心课题之一。然而,传统的因果关系研究通常依赖于昂贵的实验,而实验结果往往与天然环境中的实际因果联系存在较大偏差。例如,在生态系统中,物种…...
手机内存不够,哪些文件可以删?
1️⃣应用缓存文件 安卓:通过「文件管理器」→「Android」→「data」或「cache」文件夹(部分需权限),或直接在应用设置中清除缓存 iOS:无需手动清理,系统会自动管理,或在应用内设置中清除&…...
C语言之 比特(bit)、字节(Byte)、字(Word)、整数(Int)
在C语言中,经常出现上述的概念,即比特(bit)、字节(Byte)、字(Word)、整数(Int)。查看C语言标准,比特(bit)的定义如下&…...
组态王通过开疆智能profinet转ModbusTCP网关连接西门子PLC配置案例
本案例是组态王通过使用开疆智能研发的Profinet转ModbusTCP网关采集西门子1200PLC中数据的案例。 网关配置 首先来配置网关的参数,打开网关配置软件“Gateway Configuration Studio” 由于组态王那侧设定为ModbusTCP客户端所以网关作为ModbusTCP服务器。新建项目…...
GO语言学习(五)
GO语言学习(五) 前面我们已经学了一些关于golang的基础知识,从这一期开始,我们就来讲解一下基于golang为后端的web开发,首先这一期为一些golang为后端的web开发基础讲解,我们将会从web的工作方式、golang如…...
Supermemory:让大模型拥有“长效记忆“
目录 引言:打破大语言模型的记忆瓶颈,迎接AI交互新范式 一、Supermemory 核心技术 1.1 透明代理机制 1.2 智能分段与检索系统 1.3 自动Token管理 二、易用性 三、性能与成本 四、可靠性与兼容性 五、为何选择 Supermemory? 六、对…...
Hooks实现原理与自定义Hooks
React Hooks 是 React 16.8 引入的一种机制,允许在函数组件中使用状态(state)、副作用(effect)等功能,而无需编写 class 组件。其核心原理是通过闭包和链表结构,在 React 的 Fiber 架构中管理组…...
【NLP】35. 构建高质量标注数据
如何构建高质量标注数据?大语言模型背后的那只“看不见的手” 在讨论大语言模型(LLM)性能突破时,人们总是聚焦在模型参数、结构设计和训练技巧上。但真正懂行的人都知道——再好的模型也离不开一手好数据,尤其是那些“…...
2024CCPC吉林省赛长春邀请赛 Java 做题记录
目录 I. The Easiest Problem G. Platform Game L. Recharge E. Connected Components I. The Easiest Problem 签到题 直接输出 21 即可 // github https://github.com/Dddddduo // github https://github.com/Dddddduo/acm-java-algorithm // github https://github.com/…...
黑马程序员C++2024新版笔记 第三章 数组
1.数组定义 数组是一批相同类型的元素(element)的集合组成的数据结构。 声明语法: <数据类型> <数组名> [<数组长度>] int v[6] // 声明了可以存放6个int数字的数组 数组的每个元素有编号,称之为下标索引…...
Golang的网络安全策略实践
Golang的网络安全策略实践 一、理解网络安全的重要性 当今的网络环境中,安全问题日益突出,各种类型的攻击如雨后春笋般涌现,给个人和组织的信息资产造成了严重威胁。因此,制定和实施有效的网络安全策略至关重要。 二、Golang在网络…...
SAP学习笔记 - 开发13 - CAP 之 添加数据库支持(Sqlite)
上一章学习了CAP开发准备,添加Service。 SAP学习笔记 - 开发12 - CAP 之 开发准备,添加服务-CSDN博客 本章继续学习CAP开发 - 添加数据库支持(Sqlite)。 目录 1,数据库准备 - H2 内存数据库 - Sqlite数据库 a&…...
DRIVEGPT4: 通过大语言模型实现可解释的端到端自动驾驶
《DriveGPT4: Interpretable End-to-End Autonomous Driving via Large Language Model》 2024年10月发表,来自香港大学、浙江大学、华为和悉尼大学。 多模态大型语言模型(MLLM)已成为研究界关注的一个突出领域,因为它们擅长处理…...
LLM最后怎么输出值 解码语言模型:从权重到概率的奥秘
LM Head Weights(语言模型头部权重):左侧的“LM Head Weights”表示语言模型头部的权重矩阵,它是模型参数的一部分。权重矩阵与输入数据进行运算。Logits(未归一化对数概率):经过与LM Head Weig…...
Better Faster Large Language Models via Multi-token Prediction 原理
目录 模型结构: Memory-efficient implementation: 实验: 1. 在大规模模型上效果显著: 2. 在不同类型任务上的效果: 为什么MLP对效果有提升的几点猜测: 1. 并非所有token对生成质量的影响相同 2. 关…...
【NLP】34. 数据专题:如何打造高质量训练数据集
构建大语言模型的秘密武器:如何打造高质量训练数据集? 在大语言模型(LLM)如 GPT、BERT、T5 爆发式发展的背后,我们常常关注模型架构的演化,却忽视了一个更基础也更关键的问题:训练数据从哪里来…...
uniapp 微信小程序 获取openId
嗨,我是小路。今天主要和大家分享的主题是“uniapp 微信小程序 获取openId”。 一、主要属性 1.uni.login 二、实例代码 1、前端代码 uni.login({provider: weixin,success: (res) > {uni.showLoading({title: 登录中...,mask: true})let code res.…...
企业标准信息公共服务平台已开放标准通编辑器访问入口
标准通 数字化标准编辑器 专业、高效、便捷 企业标准信息公共服务平台 近日,企业标准信息公共服务平台已开放标准通编辑器访问入口,可进入官网指定版块使用! 核心功能亮点 解决企业痛点 传统标准编制,需反复核对格式、逐条…...
小米MUJIA智能音频眼镜来袭
智能眼镜赛道风云再起,小米新力作MIJIA智能音频眼镜2正式亮相,引发市场热议。 这款产品在设计和功能上都有显著提升,为用户带来更舒适便捷的佩戴体验,同时也标志着小米在智能眼镜领域的持续深耕。 轻薄设计,舒适体验 …...
Node.js 实战八:服务部署方案对比与实践
你开发好了接口,准备上线,然后开始犹豫: “直接 node app.js 启就行了吗?” “要不要用 PM2?听说 Docker 更稳?” “Serverless 是不是就不用管服务器了?” 部署是从“能运行”到“能长久运行”…...
地下水安全监测实施方案
一、方案目标 本方案的核心目标在于构建一个全方位、科学严谨且高效运转的地下水监测体系,旨在实现对地下水资源全方位的动态监测、科学化的管理和有效的保护。监测的具体目标涵盖了地下水位、流量以及水质等多个关键性指标,通过精准的数据采集和分析&am…...
HTTP由浅入深
概述 超文本传输协议(HTTP, Hypertext Transfer Protocol) 是一种用于传输超媒体文档(例如 HTML)的应用层协议。它最初被设计用于 Web 浏览器与 Web 服务器之间的通信,但也广泛应用于其他客户端与服务器的交互。 HTT…...
Conda 环境下安装 GCC 和 glibc (crypt.h) 教程
Conda 环境下安装 GCC 和 glibc (crypt.h) 教程 由于运行Low-Light Image Enhancement via Structure Modeling and Guidance原始论文代码,发现服务器的gcc版本太老,没法运行。同时缺少libxcrypt (crypt.h),不得不询问gpt进行解答。发现可以…...
C++面试3——const关键字的核心概念、典型场景和易错陷阱
const关键字的核心概念、典型场景和易错陷阱 一、const本质:类型系统的守护者 1. 与#define的本质差异 维度#defineconst编译阶段预处理替换编译器类型检查作用域无作用域(全局污染)遵循块作用域调试可见性符号消失保留符号信息类型安全无类…...
超小多模态视觉语言模型MiniMind-V 训练
简述 MiniMind-V 是一个超适合初学者的项目,让你用普通电脑就能训一个能看图说话的 AI。训练过程就像教小孩:先准备好图文材料(数据集),教它基础知识(预训练),再教具体技能…...
深入理解仿函数(Functors):从概念到实践
文章目录 1. 什么是仿函数?2. 仿函数与普通函数的区别3. 标准库中的仿函数4. 仿函数的优势4.1 状态保持4.2 可定制性4.3 性能优势 5. 现代C中的仿函数5.1 Lambda表达式5.2 通用仿函数 6. 仿函数的高级应用(使用C2020标准库及以上版本)6.1 函数…...
第二届parloo杯的RSA_Quartic_Quandary
(害,还是太菜了,上去秒了一道题之后就动不了了,今晚做个记录,一点点的往回拾起吧) # from Crypto.Util.number import getPrime, bytes_to_long # import math # # FLAG b************** # # # def gene…...
团队氛围紧张,如何提升工作积极性?
当团队氛围长期处于紧张状态时,员工的积极性、创造力和凝聚力会显著下降。要有效提升工作积极性,应从建设心理安全环境、优化管理沟通方式、提升认可与激励机制、加强情感联结与归属感等方面系统改善。其中,建设心理安全环境是最重要的基础&a…...
vuex的基本使用
个人简介 👨💻个人主页: 魔术师 📖学习方向: 主攻前端方向,正逐渐往全栈发展 🚴个人状态: 研发工程师,现效力于政务服务网事业 🇨🇳人生格言&…...
chrome因使用selenium无图模式导致不再加载图片问题解决
因为使用了selenium的无图模式访问chrome的本地用户数据导致正常使用chrome访问网页时图片不加载。现在页面出现验证码,验证码显示不了。 第一步:关闭所有chrome 第二步:找到Perferences文件 文件的目录为:C:\Users\用户名\AppDa…...
并发编程(5)
抛异常时会释放锁。 当线程在 synchronized 块内部抛出异常时,会自动释放对象锁。 public class ExceptionUnlockDemo {private static final Object lock new Object();public static void main(String[] args) {Thread t1 new Thread(() -> {synchronized …...
自己拥有一台服务器可以做哪些事情
上大学时候,买了自己的第一台服务器在HoRain Cloud上,结果没有好好利用,刚工作时候,又买了一台HoRain Cloud服务器,就想着好好利用。 可以搭建一些学习环境,比如说数据库,gitlab什么的 …...
Node.js聊天室开发:从零到上线的完整指南
为让你全面了解Node.js聊天室开发,我会先介绍开发背景与技术栈,再按搭建项目、实现核心功能、部署上线的流程展开,还会分享优化思路。 Node.js聊天室开发实战:从入门到上线 在即时通讯日益普及的今天,基于Node.js搭建…...
Unity 如何使用Timeline预览、播放特效
在使用unity制作和拟合动画时,我们常用到Timeline,前后拖动滑轨,预览动画正放倒放非常方便。如果我们想对特效也进行这个操作,可以使用下文的步骤。 至此,恭喜你又解锁了一个新的技巧。如果我的分享对你有帮助…...
实物工厂零件画图案例(下)
文章目录 总练习模块文章索引气动顶针轴直线轴承座法兰盘平皮带中空传动轴减速机V带轮减速机箱体 简介:点击此处可以下载该文章的案例模型,加上这篇文章总共有七篇文章是用来练习solidworks软件应用与建模思路的,大概有30多个案例模型&#x…...
esp32课设记录(五)整个项目开源github
我把该项目开源到了github:https://github.com/whyovo/ESP32_course_project 以下是readme文档: ESP32 课设 项目概述 这是一个基于ESP32的课设,实现了多种功能模式的集成,包括信息显示、图片展示、MQTT通信、摩尔斯电码处理以…...
力扣每日一题5-19
class Solution { public String triangleType(int[] nums) { Arrays.sort(nums); if (nums[0] nums[1] < nums[2]) return “none”; if (nums[0] nums[1] && nums[1] nums[2]) return “equilateral”; if (nums[0] nums[1] || nums[1] nums[2]) return “is…...
CI/CD 深度实践:灰度发布、监控体系与回滚机制详解
CI/CD 深度实践:灰度发布、监控体系与回滚机制详解 一、引言 在现代软件开发中,持续集成与持续交付(CI/CD)是加快交付速度、提升质量的关键。面对复杂的分布式系统和海量用户,如何安全、快速地发布新版本,…...
【日常笔记】wps如何将值转换成东西南北等风向汉字
在WPS表格中,若要将数值(如角度值)转换成“东、南、西、北”等风向汉字,可通过以下步骤结合自定义函数或条件判断实现: 一、wps如何将值转换 方法一:使用LOOKUP函数(简化公式)&…...