一、安装Minio

1.1 拉取镜像

docker pull minio/minio

docker images

1.2创建挂载目录

1.2.1 创建数据目录

mkdir -p /docker-minio/data

1.2.2 创建配置文件目录

mkdir -p /docker-minio/config

1.2.3 设置权限

chmod -R 777 /docker-minio/data /docker-minio/config

1.3启动MinIO容器

docker run -d --name minio \-p 9000:9000 -p 9090:9090 \-e "MINIO_ROOT_USER=minioAdmin" \-e "MINIO_ROOT_PASSWORD=minioAdmin" \-v /docker-minio/data:/data \-v /docker-minio/config:/root/.minio \minio/minio server /data \--console-address ":9090" \--address ":9000"

注意:MinIO 规定 Access key 长度至少为 3,Secret key 长度至少为 8。

这个 Docker 命令用于启动一个 MinIO 对象存储服务器容器。MinIO 是一个高性能、与 Amazon S3 API 兼容的开源对象存储解决方案。下面是详细解释:

1. docker run

  • 作用: Docker 命令的核心部分,用于创建并启动一个新的容器。

2. -d

  • 作用: detach 的缩写。以后台(守护进程)模式运行容器。容器启动后,控制台会立即返回,你可以继续使用终端,而容器在后台运行。要查看容器日志,可以使用 docker logs minio

3. --name minio

  • 作用: 为容器指定一个名称 minio。这使得后续管理容器(如启动、停止、查看日志)更加方便,无需使用复杂的容器 ID。例如:

    • docker stop minio

    • docker start minio

    • docker logs minio

4. -p 9000:9000 -p 9090:9090

  • 作用: 将容器内部的端口映射到宿主机的端口。

    • -p 9000:9000: 将容器内部的 9000 端口映射到宿主机的 9000 端口。这个端口是 MinIO API 服务端口,用于客户端(SDK、命令行工具 mc、应用程序)与 MinIO 服务进行交互(上传、下载、管理对象等),兼容 S3 API。

    • -p 9090:9090: 将容器内部的 9090 端口映射到宿主机的 9090 端口。这个端口是 MinIO 控制台(Web UI)端口,用于通过浏览器访问图形化管理界面来管理存储桶、用户、策略等。

5. -e "MINIO_ROOT_USER=minioAdmin"

  • 作用: 设置容器内的环境变量 MINIO_ROOT_USER。这个变量定义了 MinIO 的 根用户(管理员)用户名。这里设置为 minioAdmin非常重要!

6. -e "MINIO_ROOT_PASSWORD=minioAdmin"

  • 作用: 设置容器内的环境变量 MINIO_ROOT_PASSWORD。这个变量定义了 MinIO 的 根用户(管理员)密码。这里设置为 minioAdmin非常重要!强烈建议在生产环境中使用强密码替代这个示例密码。

7. -v /docker-minio/data:/data

  • 作用: 创建一个数据卷,将宿主机上的目录 /docker-minio/data 挂载到容器内部的目录 /data

    • /docker-minio/data: 宿主机上的目录路径,这个目录将持久化存储 MinIO 对象(文件)本身

    • /data: 容器内部的路径。MinIO 服务器会将所有上传的对象存储在这个目录下。

    • 意义: 这个挂载确保了 MinIO 存储的实际文件数据不会丢失。即使容器被删除或重启,宿主机 /docker-minio/data 下的数据仍然存在。下次启动新容器并挂载同一目录,数据即可恢复。

8. -v /docker-minio/config:/root/.minio

  • 作用: 创建另一个数据卷,将宿主机上的目录 /docker-minio/config 挂载到容器内部的目录 /root/.minio

    • /docker-minio/config: 宿主机上的目录路径,这个目录将持久化存储 MinIO 的服务器配置、用户信息、策略等元数据

    • /root/.minio: 容器内部 MinIO 服务默认存储其配置文件和状态的路径。

    • 意义: 这个挂载确保了 MinIO 的配置、用户账号、访问策略等关键元数据不会丢失。删除或重建容器后,只要挂载回这个目录,所有配置和用户信息都会保留。

9. minio/minio

  • 作用: 指定要运行的 Docker 镜像。这里是官方 MinIO 镜像,从 Docker Hub 的 minio/minio 仓库拉取。如果本地没有,Docker 会自动从 Hub 下载。

10. server /data

  • 作用: 这是传递给 minio/minio 镜像的 启动命令

    • server: 告诉 MinIO 可执行文件以服务器模式运行。

    • /data: 指定 MinIO 服务器在容器内部存储对象数据的路径。这必须与第 7 条 (-v ...:/data) 中挂载到容器内部的路径一致。MinIO 会使用这个目录来保存上传的文件。

11. --console-address ":9090"

  • 作用: MinIO 服务器启动参数。显式指定 MinIO 控制台(Web UI)监听的地址和端口

    • :9090: 表示绑定到容器内的所有网络接口 (0.0.0.0) 的 9090 端口。这直接对应了第 4 条 (-p 9090:9090) 中映射的端口。访问 http://<宿主机IP>:9090 即可打开管理控制台。

12. --address ":9000"

  • 作用: MinIO 服务器启动参数。显式指定 MinIO API 服务(S3 兼容接口)监听的地址和端口

    • :9000: 表示绑定到容器内的所有网络接口 (0.0.0.0) 的 9000 端口。这直接对应了第 4 条 (-p 9000:9000) 中映射的端口。客户端(如 mc,AWS SDK, 应用程序)通过 http://<宿主机IP>:9000 来访问存储服务。

1.4 访问Minio控制台

启动容器后,可以通过浏览器访问 MinIO 控制台:

http://<宿主机IP>:9001

使用之前设置的用户名和密码(minioAdmin 和 minioAdmin)登录。

二、SpringBoot集成minio

2.1 导入maven做标

        <dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.2.0</version></dependency>

2.2 自定义配置

在yml添加如下配置:

minio:url: http://121.40.159.231:9000#minio账户accessKey: minioAdmin#minio密码secretKey: minioAdminbucketName: nbsjfx

然后创建对应的配置类:

@Data
@Component
@ConfigurationProperties(prefix = "minio")
public class MinioProp {/*** Minio存储服务服务的地址*/private String url;/*** Minio的访问账号*/private String accessKey;/*** Minio的访问密码*/private String secretKey;/*** Minio的存储桶名称*/private String bucketName;}

2.3 创建MinioClient(向 Spring 容器中注册一个 MinioClient 类型的 Bean),并创建Bucket

@Configuration
@RequiredArgsConstructor
public class MinioConfig {private final MinioProp minioProp;/*** 创建MinioClient实例*/@Beanpublic MinioClient minioClient() {MinioClient minioClient = MinioClient.builder().endpoint(minioProp.getUrl()).credentials(minioProp.getAccessKey(), minioProp.getSecretKey()).build();return minioClient;}/*** 创建Bucket*/@SneakyThrows@PostConstructpublic void createBucket() {MinioClient minioClient = minioClient();boolean bucketExists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(minioProp.getBucketName()).build());if (!bucketExists) {minioClient.makeBucket(MakeBucketArgs.builder().bucket(minioProp.getBucketName()).build());}}}

2.4 自定义工具类

自定义的MinioUtil代码如下:

@Component
@RequiredArgsConstructor
public class MinioUtil {private final MinioClient minioClient;private final MinioProp minioProp;private final HttpServletResponse httpServletResponse;/*** 检查bucket是否存在,不存在则创建** @param bucketName bucket名称* @return 是否创建成功*/@SneakyThrowspublic Boolean createBucket(String bucketName) {boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());if (!exists) {minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());}return Boolean.TRUE;}/*** 获取所有bucket列表** @return bucket列表*/@SneakyThrowspublic List<Bucket> getAllBuckets() {List<Bucket> bucketList = minioClient.listBuckets();return bucketList;}/*** 删除bucket (桶为空时,才能删除)** @param bucketName bucket名称* @return 是否删除成功*/@SneakyThrowspublic Boolean deleteBucket(String bucketName) {minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());return Boolean.TRUE;}/*** 获取bucket中的所有文件列表** @param bucketName bucket名称* @return 文件列表*/@SneakyThrowspublic List<Item> getAllFilesByBucket(String bucketName) {Iterable<Result<Item>> iterable = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).build());List<Item> itemList = new ArrayList<>();for (Result<Item> result : iterable) {Item item = result.get();itemList.add(item);}return itemList;}/*** 上传文件** @param inputStream 文件输入流* @param bucketName  bucket名称* @param fileName    文件名称* @return 是否上传成功*/@SneakyThrowspublic Boolean uploadFile(InputStream inputStream, String bucketName, String fileName) {minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(inputStream, -1, 5242889L).build());return Boolean.TRUE;}/*** 上传文件** @param multipartFile 文件对象* @return 是否上传成功*/@SneakyThrowspublic Boolean uploadFile(MultipartFile multipartFile) {return uploadFile(multipartFile.getInputStream(), minioProp.getBucketName(), multipartFile.getOriginalFilename());}/*** 删除文件** @param bucketName bucket名称* @param fileName   文件名称* @return 是否删除成功*/@SneakyThrowspublic Boolean deleteFile(String bucketName, String fileName) {minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());return Boolean.TRUE;}/*** 删除文件** @param fileName 文件名称* @return 是否删除成功*/public Boolean deleteFile(String fileName) {return deleteFile(minioProp.getBucketName(), fileName);}/*** 下载文件** @param bucketName bucket名称* @param fileName   文件名称*/@SneakyThrowspublic void downloadFile(String bucketName, String fileName) {GetObjectResponse getObjectResponse = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(fileName).build());byte[] buf = new byte[1024];int len;try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()) {while ((len = getObjectResponse.read(buf)) != -1) {os.write(buf, 0, len);}os.flush();byte[] bytes = os.toByteArray();httpServletResponse.setCharacterEncoding("utf-8");// 设置强制下载不打开//httpServletResponse.setContentType("application/force-download");httpServletResponse.addHeader("Access-Control-Expose-Headers", "Content-Disposition");httpServletResponse.addHeader("Content-Disposition", "attachment;filename=".concat(URLEncoder.encode(fileName, "UTF-8")));try (ServletOutputStream stream = httpServletResponse.getOutputStream()) {stream.write(bytes);stream.flush();}}}/*** 下载文件** @param fileName 文件名称*/public void downloadFile(String fileName) {downloadFile(minioProp.getBucketName(), fileName);}/*** 获取预览文件url (预览链接默认7天后过期)** @param bucketName bucket名称* @param fileName   文件名称* @return 文件url*/@SneakyThrowspublic String getPreviewFileUrl(String bucketName, String fileName) {GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(fileName).build();return minioClient.getPresignedObjectUrl(args);}/*** 获取预览文件url (预览链接默认7天后过期)** @param fileName 文件名称* @return 文件url*/public String getPreviewFileUrl(String fileName) {return getPreviewFileUrl(minioProp.getBucketName(), fileName);}}

三、nginx代理minio的文件链接

3.1 前置说明

当我们创建桶后,Minio会在数据挂载目录下,创建一个和桶同名的文件夹。

上面的过程中,我们创建了一个为nbsjfx的桶,对应的文件夹如下:

目前桶里有一个文件,为1.jpg:

3.2 反向代理

 server {listen 9999;server_name 127.0.0.1;location / {root /docker-minio/data;}

测试结果:

四、适配器模式(实战教程)

百度百科对于适配器的介绍:适配器模式_百度百科

        在计算机编程中,适配器模式(有时候也称包装样式或者包装)将一个类的接口适配成用户所期待的。一个适配允许通常因为接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。

        适配器模式(Adapter Pattern)是一种结构型设计模式,它允许接口不兼容的类能够一起工作。适配器模式通过将一个类的接口转换成客户期望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。

        在这个场景中,我们需要实现一个统一的OSS(对象存储服务)接口,然后为不同的云存储服务(如minio、阿里云OSS、京东云OSS)提供适配器。这样,客户端就可以通过统一的接口来操作不同的云存储服务,而无需关心底层不同服务的具体实现细节。

4.1 创建OSS适配器接口

/*** OSS适配器接口*/
public interface OssAdapter {/*** 上传文件* @param multipartFile 上传的文件* @return 上传成功返回true,否则返回false*/Boolean uploadFile(MultipartFile multipartFile);}

我们这里通过上传文件方法作为案例,希望不管什么厂商的Oss都通过这个接口的方式进行文件上传

4.2 创建对应的适配器实现类

4.2.1 创建minio适配器实现类

/*** Minio Oss 适配器*/
@Slf4j
public class MinioOssAdapter implements OssAdapter {@Autowiredprivate MinioUtil minioUtil;@Overridepublic Boolean uploadFile(MultipartFile multipartFile) {log.info("Minio适配器实现文件上传");return minioUtil.uploadFile(multipartFile);}}

注意到,此处我们没有把该类注册为spring的bean,所以@Autowired注解在提升错误。

因为我们的系统,一般都只使用一种文件存储服务,使用我们这里预期是到时候通过配置类的形式交由spring容器进行管理。

4.2.2 创建aliyun适配器实现类

/*** 阿里云 OSS 适配器*/
@Slf4j
public class AliyunOssAdapter implements OssAdapter {//也是注入阿里云Oss相关的工具类和实现等@Overridepublic Boolean uploadFile(MultipartFile multipartFile) {log.info("阿里云适配器实现文件上传");// TODO 阿里云 OSS 上传文件return null;}}

4.2.3 创建配置类,按需注入

首先在yml文件中,自定义类型:

oss:oss-type: minio

然后创建配置类如下:(根据类型完成注入)

@Slf4j
@Configuration
public class OssConfig {@Value("${oss.oss-type}")private String ossType;@Beanpublic OssAdapter ossAdapter(){log.info("文件存储ossType: {}", ossType);if ("minio".equals(ossType)){return new MinioOssAdapter();}else if ("aliyun".equals(ossType)){return new AliyunOssAdapter();}throw new IllegalArgumentException("未找到对应的Oss文件存储适配器");}}

4.3 抽取文件服务类(根据自己的系统自定义)

@Service
public class FileService {@Autowiredprivate OssAdapter ossAdapter;public Boolean uploadFile(MultipartFile multipartFile) {return ossAdapter.uploadFile(multipartFile);}}

4.4 编写控制层进行测试

@RestController
@RequestMapping("/file")
public class FileController {@Autowiredprivate FileService fileService;@RequestMapping("/uploadFile")public IResult uploadFile(MultipartFile multipartFile) {return new ResultBean<>(fileService.uploadFile(multipartFile));}}

当配置文件配置的类型为minio时,测试结果:

同时minio中也确实上传了文件:

当我们把配置文件的类型改为aliyun时,测试结果:

4.5 总结

至此,我们实现将不同 OSS 提供商的接口抽象成一个统一的接口,从而实现解耦和灵活切换。

优势:

  1. 统一接口:客户端使用一致的API操作不同云存储

  2. 解耦:业务代码与具体云服务实现解耦

  3. 可扩展:新增云服务只需添加新适配器

  4. 易维护:各云服务实现相互隔离,修改互不影响

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

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

相关文章

LLaMA-Factory 对 omnisql 进行 ppo dpo grpo nl2sql任务 实现难度 时间 全面对比

在LLaMA-Factory框架下&#xff0c;针对omnisql任务&#xff08;自然语言到SQL生成&#xff09;应用PPO、DPO、GRPO三种算法的实现难度、时间及全面对比如下&#xff1a; 一、实现难度对比 1. PPO&#xff08;近端策略优化&#xff09; 难度&#xff1a;★★☆☆☆&#xff…

Kingbase 数据库中的 sys_guid() 函数报错

解决 Kingbase 数据库中的 sys_guid() 函数报错问题 问题背景 Kingbase 数据库在迁移或使用过程中&#xff0c;可能会遇到 select sys_guid() 函数报错 , 提示函数不存在的情况&#xff0c;这通常是由于以下几种原因造成的&#xff1a; 函数未正确安装或未启用函数参数不符合…

零基础RT-thread第五节:电容按键(2)

上一章的电容按键完全使用的HAL库的代码&#xff0c;并没有使用线程。这里尝试使用线程来控制电容按键。 依旧是 F767 本来以为会很容易实现&#xff0c;没想到尝试了很久&#xff0c;电容按键一直没有反应。 static rt_uint32_t measure_charge_time(void) {// 步骤1: 放电 …

华为云Flexus+DeepSeek征文|单机部署 与 CCE 高可用部署下 Dify 性能实测

引言 在当今的 AI 应用开发领域&#xff0c;选择合适的部署方式对于应用的性能表现、资源利用和成本控制至关重要。华为云为开发者提供了多样化的部署选择&#xff0c;其中基于单机 Flexus 实例的基础版部署和基于 CCE 容器的高可用版部署是两种常见的方式。本文将深入对比这两…

钉钉小程序框架:Pinia 状态管理与持久化存储封装

上一篇文章完成了 Pinia 在钉钉小程序中的引入与基础配置 文章地址&#xff1a;钉钉小程序框架引入 Pinia 状态管理-CSDN博客 本文将深入探讨如何通过Pinia 结合持久化存储 实现用户状态 在上一章节中&#xff0c;我们已经完成了 Pinia 在钉钉小程序中的引入与基础配置。本章将…

云计算产业链

一、云计算定义与分类体系 本质特征 按需服务模式&#xff1a;以网络化方式提供可配置的计算资源共享池&#xff08;网络/服务器/存储/应用&#xff09;。核心能力&#xff1a;快速弹性扩容、资源池化共享、按使用量付费、低管理开销。技术原理&#xff1a;通过分布式计算将大型…

git使用详解和示例

什么是 Git&#xff1f; Git 是一个 分布式版本控制系统&#xff08;DVCS&#xff09;&#xff0c;用于跟踪文件的变化&#xff0c;协调多人协作开发。由 Linus Torvalds 开发&#xff0c;用于管理 Linux 内核代码。 Git 的核心概念 名称说明工作区 (Working Directory)你看到…

深度学习的引出

虽然我们的神经⽹络给出了令⼈印象深刻的表现&#xff0c;但这样的表现带有⼏分神秘 ⽹络中的权重和偏置是被⾃动发现的。这意味着我们不能⽴即解释⽹络怎么做的、做了什么。我们能否找 到⼀些⽅法来理解我们的⽹络通过什么原理分类⼿写数字&#xff1f;并且&#xff0c;在知道…

GEO(生成式引擎优化)—— 内容创作者与企业的生死新战场

在搜索引擎优化&#xff08;SEO&#xff09;定义了互联网信息获取规则数十年后&#xff0c;一场由生成式人工智能&#xff08;AIGC&#xff09;驱动的风暴正悄然重塑整个格局。当ChatGPT、Claude、Gemini等AI助手能够直接生成整合后的答案&#xff0c;而非仅仅提供链接列表时&a…

混合密度模型GMM的似然函数(二)

设 Θ { π k , θ k } k 1 K \varTheta \{ \pi_k, \boldsymbol {\theta}_k \}_{k1}^{K} Θ{πk​,θk​}k1K​为参数向量&#xff0c; X { x 1 , ⋯ , x n } \mathcal {X} \{ {\bm x}_1, \cdots, {\bm x}_n \} X{x1​,⋯,xn​}为观测数据&#xff0c;给定数据点的独立性&a…

selenium元素定位

当我们可以打开浏览器后我们如果想要进行web测试我们自然要对网页的一些功能进行单独拿出来进行测试&#xff0c;但是我们要怎么才能拿到我们想要的元素&#xff0c;并且对其进行操作呢。 我们就以百度主页的输入框为例&#xff0c;如果我们想要王输入框中输入一些内容我们就需…

2025第十五届上海生物发酵展:江苏健达干燥盛装赴会

2025 年 8 月 7 - 9 日&#xff0c;上海新国际博览中心将迎来一场生物发酵行业的盛会 —— 第 15 届上海国际生物发酵产品与技术装备展览会&#xff08;BIOCHINA 2025&#xff09;。作为国内干燥设备领域的领军企业&#xff0c;江苏健达干燥工程有限公司受邀盛装参展&#xff0…

【效率工具】单机游戏修改方案:轻量管理器+全能平台组合

大家好&#xff01;今天我要给大家介绍两款超级实用的软件&#xff0c;专门为喜欢玩单机游戏的小伙伴们准备。 一、风灵月影管理器 不想满网翻修改器&#xff1f;这个 27M 的小工具直接帮你一键搞定&#xff0c;这款软件是由B站UP鸦无量 开发。 收录上千款游戏补丁&#xff0c;…

七天学会SpringCloud分布式微服务——01——基础概念

重点是复习体系&#xff0c;从今天6.24开始&#xff0c;确保转化为自己的东西心平气和&#xff0c;脚踏实地学习的是尚硅谷微服务 1、从单体架构到集群架构再到分布式架构 单体架构 就是 所有的功能&#xff08;服务&#xff09;模块 都部署在同一台服务器&#xff08;一台服…

三分钟学会利用deepseek将复杂信息转换成可视化图表

数据可视化是传达复杂信息的重要手段。通过将数据转化为直观的图表、图形和交互式界面,我们可以更高效地理解信息、发现趋势并做出决策。对于普通人来说,要将数据可视化可谓千难万难。但在AI工具飞速发展的今天,这个过程将会变得非常简单。今天分享的内容就是如何使用生成式…

PDF处理控件Spire.PDF系列教程:Python中快速提取PDF文本、表格、图像及文档信息

在 Python 中读取 PDF 文档是实现文档自动化、内容分析和数据提取的基础操作之一。无论你处理的是合同、报告、发票&#xff0c;还是科研论文&#xff0c;能够通过代码访问 PDF 内容&#xff0c;不仅能节省时间&#xff0c;还能带来更高效的处理流程。 要在 Python 中准确提取…

微软人工智能证书AI-102 | 如何快速通过?

微软 AI-102 考试&#xff0c;全称 “Designing and Implementing a Microsoft Azure AI Solution”&#xff0c;是微软推出的用于验证考生在 Azure 平台上设计和实施 AI 解决方案核心能力的认证考试。以下是具体介绍&#xff1a; 考试描述&#xff1a; 考试主要衡量考生实施计…

github使用指南

1、生成SSH密钥对 ssh-keygen -t ed25519 -C "你的github邮箱"然后根据提示保存路径&#xff0c;设置密码 2、将公钥添加到github cat ~/.ssh/id_ed25519.pub复制输出内容。 在gihub中点击New SSH Key&#xff0c;添加密钥 3、配置git使用SSH地址 git remote se…

AD22以上的基础操作

1.检测创建的原理图器件库 2.原理图页加大 Size&#xff1a;常规和自定义 推荐可视化栅格100mil 快捷键VG 3.原理图器件器件号排序 自动排序&#xff1a;快捷键TAA 先解锁 4.BOM(Bill of Material)物料表导出 description描述&#xff1a;类似精度。 导出各种类型bom表 5…

FastAPI技术深度解析与实战指南

导读&#xff1a;在Python Web开发领域经历了Django和Flask多年统治后&#xff0c;FastAPI的崛起正在重新定义API开发的技术标准。这篇深度技术解析将为开发者揭示FastAPI如何通过独特的架构设计解决传统框架的核心痛点。 传统Python Web框架在面对高并发场景时暴露出明显的性能…