Spring Boot | 基于MinIO实现文件上传和下载
关注:CodingTechWork
介绍
在现代的 web 应用中,文件上传和下载是常见的需求。MinIO 是一个开源的高性能分布式对象存储服务,可以用来存储和管理大量的非结构化数据,如图片、视频、日志文件等。本文将介绍如何在 Spring Boot 应用中,结合 MinIO 来实现文件的上传和下载功能,并使用 Feign 客户端进行远程调用文件上传和下载的服务。
MinIO 相关介绍
MinIO 是一个高性能的分布式对象存储系统,兼容 Amazon S3 API,通常用于存储和管理大量非结构化数据,如图片、视频、备份、日志等。它提供了与 S3 完全兼容的 API,使得开发者能够使用相同的工具和库与其进行交互。MinIO 被设计为云原生,适用于在 Docker、Kubernetes 和虚拟机中运行。
MinIO 特点
- 高性能:支持高吞吐量、高并发的读写操作,适用于需要大规模数据存储的应用。
- S3 兼容:MinIO 实现了完整的 Amazon S3 API,支持通过现有的 S3 客户端、SDK 和工具来进行交互。
- 高可扩展性:支持水平扩展,支持分布式部署,能够在多台机器上运行并提供统一的对象存储服务。
- 轻量级:MinIO 是一个轻量级的应用程序,易于部署和管理,可以在资源受限的环境中运行(如单机或者小型集群)。
- 支持对象加密:MinIO 支持对象级加密,可以为上传到存储中的对象加密,保证数据安全。
- 支持版本控制:MinIO 支持对象版本管理,允许对存储中的文件进行版本控制。
MinIO 核心概念
桶(Bucket)
- 在 MinIO 中,桶类似于文件系统中的文件夹。每个桶用于存储一组对象。
- 每个桶都可以有独立的权限配置。
- 存储在桶中的对象有唯一的标识符(通常是对象的文件名)。
对象(Object)
- 对象是 MinIO 存储的基本单位,类似于文件系统中的文件。
- 对象由数据和元数据组成,可以是任何类型的数据,如文本、图像、视频等。
对象键(Object Key)
- 对象键是对象在桶中的唯一标识符,通常对应于文件名。
访问密钥和密钥(Access Key & Secret Key)
- MinIO 使用访问密钥(Access Key)和密钥(Secret Key)进行身份验证,类似于 S3。
- 用户可以配置访问密钥和密钥以确保数据的访问权限。
MinIO API 介绍
MinIO 的 API 设计遵循 S3 API,几乎所有 S3 的 API 都可以在 MinIO 中使用。以下是 MinIO 支持的常见操作和 API:
Bucket 操作
- 创建桶(Create Bucket):创建一个新桶来存储对象。
minioClient.makeBucket("mybucket");
- 列举桶(List Buckets):获取当前 MinIO 实例中所有存在的桶。
List<Bucket> buckets = minioClient.listBuckets();
- 检查桶是否存在(Bucket Exists):检查桶是否存在。
boolean exists = minioClient.bucketExists("mybucket");
- 删除桶(Delete Bucket):删除桶(桶必须为空才能删除)。
minioClient.removeBucket("mybucket");
对象操作
- 上传对象(Put Object):上传一个文件到 MinIO 中指定的桶。
minioClient.putObject("mybucket", "myfile.txt", fileInputStream, fileSize, null, null, "application/octet-stream");
- 获取对象(Get Object):从指定桶中获取对象内容。
InputStream inputStream = minioClient.getObject("mybucket", "myfile.txt");
- 删除对象(Remove Object):删除 MinIO 存储桶中的某个对象。
minioClient.removeObject("mybucket", "myfile.txt");
- 列举对象(List Objects):列举桶中的所有对象(可以按前缀过滤)。
Iterable<Result<Item>> objects = minioClient.listObjects("mybucket");
for (Result<Item> result : objects) {Item item = result.get();System.out.println("Object name: " + item.objectName());
}
- 获取对象元数据(Stat Object):获取对象的元数据,如大小、最后修改时间等。
StatObjectResponse stat = minioClient.statObject("mybucket", "myfile.txt");
System.out.println("Object size: " + stat.size());
文件下载
- 下载对象(Get Object):从 MinIO 中下载一个对象,并将其存储到本地文件系统。
minioClient.getObject("mybucket", "myfile.txt", Paths.get("/path/to/destination"));
对象版本控制
- 启用版本控制:启用桶的版本控制功能。
minioClient.enableBucketVersioning("mybucket");
- 获取对象版本(Get Object Version):获取对象的指定版本。
InputStream inputStream = minioClient.getObject("mybucket", "myfile.txt", "versionId");
- 删除对象版本(Remove Object Version):删除某个版本的对象。
minioClient.removeObject("mybucket", "myfile.txt", "versionId");
权限管理
MinIO 支持基于用户的权限控制,可以通过配置桶的访问策略来管理谁可以访问存储中的对象。
- 设置桶的访问权限(Bucket Policy):设置桶的访问权限来限制用户对对象的访问。
String policy = "{ \"Version\": \"2025-01-07\", \"Statement\": [ { \"Effect\": \"Allow\", \"Principal\": { \"AWS\": \"*\" }, \"Action\": [ \"s3:GetObject\" ], \"Resource\": [ \"arn:aws:s3:::mybucket/*\" ] } ] }";
minioClient.setBucketPolicy("mybucket", policy);
MinIO 安全性特性
- 加密:
MinIO 支持两种类型的加密:服务端加密(SSE)
和客户端加密(CSE)
。服务端加密会在对象上传到 MinIO 时自动对其进行加密。 - 身份验证与授权:
MinIO 使用访问密钥(Access Key)
和密钥(Secret Key)
来进行身份验证。用户可以通过配置 MinIO 的访问控制列表(ACL)
来限制谁可以访问桶和对象。 - TLS/SSL 支持:
MinIO 支持通过TLS(即 HTTPS)
加密通信来保护数据传输安全。
项目结构
本项目的文件上传和下载功能将分成两个部分:
- minio 服务端(本地服务处理文件上传)
- Feign 客户端(模拟远程文件上传请求)
file-upload-demo
│
├── src/main/java/com/example/fileupload
│ ├── controller
│ │ └── FileController.java
│ ├── service
│ │ └── FileService.java
│ ├── feign
│ │ └── FileFeignClient.java
│ ├── FileUploadDemoApplication.java
│ └── ...
├── pom.xml
└── resources└── application.properties
Maven 依赖
在 pom.xml 中添加以下依赖:
<dependencies><!-- Spring Boot Web 依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Feign 依赖 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!-- minio 客户端依赖 --><dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.3.5</version></dependency><!-- 文件上传需要的依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>
</dependencies>
同时,在 application.properties 中配置文件上传大小限制:
properties配置文件
# MinIO 配置
minio.url=http://localhost:9000
minio.access-key=your-access-key
minio.secret-key=your-secret-key
minio.bucket-name=mybucket# 文件上传大小限制
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
代码示例
MinIO 配置
创建一个 MinIO 配置类来初始化 MinIO 客户端。
MinioConfig.java
package com.example.fileupload.config;import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MinioConfig {@Value("${minio.url}")private String minioUrl;@Value("${minio.access-key}")private String accessKey;@Value("${minio.secret-key}")private String secretKey;@Value("${minio.bucket-name}")private String bucketName;@Beanpublic MinioClient minioClient() {try {MinioClient minioClient = MinioClient.builder().endpoint(minioUrl).credentials(accessKey, secretKey).build();// 如果桶不存在则创建桶boolean isExist = minioClient.bucketExists(bucketName);if (!isExist) {minioClient.makeBucket(bucketName);}return minioClient;} catch (Exception e) {throw new RuntimeException("初始化 MinIO 客户端失败", e);}}
}
Controller 层:文件上传与下载接口
在 Controller 层,我们定义文件上传和下载的接口。上传文件时将文件存储到 MinIO 中,下载文件时从 MinIO 拉取文件。
FileController.java
package com.example.fileupload.controller;import com.example.fileupload.service.FileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;@RestController
@RequestMapping("/api/files")
public class FileController {@Autowiredprivate FileService fileService;// 文件上传接口@PostMapping("/upload")public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {try {String fileUrl = fileService.uploadFile(file);return ResponseEntity.ok("文件上传成功: " + fileUrl);} catch (IOException e) {return ResponseEntity.status(500).body("文件上传失败: " + e.getMessage());}}// 文件下载接口@GetMapping("/download/{filename}")public ResponseEntity<InputStreamResource> downloadFile(@PathVariable String filename) {try {InputStreamResource resource = fileService.downloadFile(filename);return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + filename).contentType(MediaType.APPLICATION_OCTET_STREAM).body(resource);} catch (IOException e) {return ResponseEntity.status(500).body(null);}}
}
Service 层:文件处理业务
在 Service 层,我们定义实际的文件处理逻辑,包括文件上传和下载。我们使用 MultipartFile 来接收文件,并将其保存到服务器上。
FileService.java
package com.example.fileupload.service;import io.minio.MinioClient;
import io.minio.errors.MinioException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.io.InputStream;@Service
public class FileService {@Autowiredprivate MinioClient minioClient;private final String bucketName = "mybucket"; // 从配置中加载桶名// 文件上传方法public String uploadFile(MultipartFile file) throws IOException {try {// 获取文件输入流InputStream fileInputStream = file.getInputStream();// 上传文件到 MinIOminioClient.putObject(bucketName, file.getOriginalFilename(), fileInputStream, file.getSize(), null, null, "application/octet-stream");return "http://localhost:9000/" + bucketName + "/" + file.getOriginalFilename(); // MinIO 文件 URL} catch (MinioException | IOException e) {throw new IOException("上传文件失败", e);}}// 文件下载方法public InputStreamResource downloadFile(String filename) throws IOException {try {// 获取文件输入流InputStream fileInputStream = minioClient.getObject(bucketName, filename);return new InputStreamResource(fileInputStream);} catch (MinioException | IOException e) {throw new IOException("下载文件失败", e);}}
}
Feign 客户端:远程调用文件上传下载服务
Feign 是一个声明式的 HTTP 客户端,它简化了 HTTP 请求的调用过程。在这个例子中,我们使用 Feign 来调用远程的文件上传和下载接口。
FileFeignClient.java
package com.example.fileupload.feign;import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;@FeignClient(name = "file-upload-service", url = "http://localhost:8080/api/files")
public interface FileFeignClient {@PostMapping("/upload")String uploadFile(@RequestParam("file") MultipartFile file);@GetMapping("/download/{filename}")byte[] downloadFile(@PathVariable("filename") String filename);
}
Feign 使用示例
在 Service 层,我们可以使用 Feign 客户端来调用远程的文件上传和下载接口。
FileService.java(使用 Feign 上传下载文件)
package com.example.fileupload.service;import com.example.fileupload.feign.FileFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;@Service
public class FileService {@Autowiredprivate FileFeignClient fileFeignClient;// 使用 Feign 上传文件public String uploadFileViaFeign(MultipartFile file) {return fileFeignClient.uploadFile(file);}// 使用 Feign 下载文件public byte[] downloadFileViaFeign(String filename) {return fileFeignClient.downloadFile(filename);}
}
总结
本文通过详细的代码示例,展示了如何将 MinIO 集成到 Spring Boot 中,来实现文件的上传和下载。通过 Feign 客户端的远程调用,可以将文件上传和下载的请求发送到远程服务中进行处理。
参考资料
Spring Boot 官方文档
Spring Cloud Feign 官方文档
相关文章:
Spring Boot | 基于MinIO实现文件上传和下载
关注:CodingTechWork 介绍 在现代的 web 应用中,文件上传和下载是常见的需求。MinIO 是一个开源的高性能分布式对象存储服务,可以用来存储和管理大量的非结构化数据,如图片、视频、日志文件等。本文将介绍如何在 Spring Boot 应用…...

企业手机号搜索API接口
每日免费每次消耗:按量每日限制:10 次每次请求积分消耗:50 积分 / 次总次数限制:10000 次每次请求间隔:0 秒,并发:50 请求地址 http(s)://api.aiqimao.com/index/apiphoneget/ 调试 请求方法…...
VirtualBox Main API 学习笔记
1. Philosophy 1.1 对于Python,推荐使用"WEBSERVICE"连接方式 Gemini 2.0 Flash Experimental: 对于 Java 和 Python: 文档建议您首先使用"WEBSERVICE",因为它提供了一种更直观的方式来使用 API。 2. Configuration pi…...

[Linux]Mysql9.0.1服务端脱机安装配置教程(redhat)
前言 本教程适用于在yum源不可用的LInux主机上安装Mysql的场景。 以redhat系主机做操作示例,debian系主机可参照步骤,将对应的rpm -ivh命令换成dpkg -i。 1. 官网下载安装包 https://dev.mysql.com/downloads/mysql/ 1.1 版本分类 MySQL Enterprise…...

uniapp--HBuilder开发
提示:本文为学习内容,若有错误,请联系作者,谦虚受教。 文章目录 前言一、下载HBuilder二、添加modbus相关库1.下载nodejs2.下载modbus库3.项目添加modbus库 三、HBuilder相关功能语句1.文件夹说明2.消息信息框3.开关按钮4.选中按钮…...

计算机毕业设计学习项目-P10080 基于springboot+vue的社团管理系统的设计与实现
项目说明 本号所发布的项目均由我部署运行验证,可保证项目系统正常运行,以及提供完整源码。 如需要远程部署/定制/讲解系统,可以联系我。定制项目未经同意不会上传! 项目源码获取方式放在文章末尾处 注:项目仅供学…...

with as提高sql的执行效率
实战sql with cte(UNIT_ID, UNIT_NAME, PARENT_UNIT_ID, UNIT_CODE ) as (select UNIT_ID, UNIT_NAME, PARENT_UNIT_ID , UNIT_CODEfrom HPFM_UNITunion allselect t.UNIT_ID, t.UNIT_NAME, t.PARENT_UNIT_ID, t.UNIT_CODEfrom HPFM_UNIT tjoin cte on t.PARENT_UNIT_ID cte.U…...

【银河麒麟高级服务器操作系统实例】tcp半链接数溢出分析及处理全过程
了解更多银河麒麟操作系统全新产品,请点击访问 麒麟软件产品专区:https://product.kylinos.cn 开发者专区:https://developer.kylinos.cn 文档中心:https://document.kylinos.cn 服务器环境以及配置 系统环境 物理机/虚拟机/云…...

计算机毕业设计Python中华古诗词知识图谱可视化 古诗词智能问答系统 古诗词数据分析 古诗词情感分析模型 自然语言处理NLP 机器学习 深度学习
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...

分布式ID生成-雪花算法实现无状态
雪花算法这里不再赘述,其缺点是有状态(多副本隔离时,依赖手动配置workId和datacenterId),代码如下: /*** 雪花算法ID生成器*/ public class SnowflakeIdWorker {/*** 开始时间截 (2017-01-01)*/private st…...
【问题】配置 Conda 与 Pip 源
通常情况下,使用 conda 命令或者 pip 命令都是从国外的服务器上下载需要的模块包的,这在网速不佳的情况下会消耗大量的时间。所以这里建议更换国内的源来进行模块下载,速度会大大提升。 具体方法如下: 打开命令行 cmd 工具,输入以下命令。 ① Conda 换源 conda config…...

Zookeeper是如何保证事务的顺序一致性的?
大家好,我是锋哥。今天分享关于【Zookeeper是如何保证事务的顺序一致性的?】面试题。希望对大家有帮助; Zookeeper是如何保证事务的顺序一致性的? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Zookeeper 通过多个机制来保证事务的顺序一…...

东土科技参股广汽集团飞行汽车初创公司,为低空经济构建新型产业生态
近日,广汽集团旗下专注于飞行汽车领域的初创公司广东高域科技有限公司于2024年12月31日正式成立,在穿透后的股东信息中,东土科技通过广州瓴云科技投资合伙企业(有限合伙)赫然在列。 此前12月18日,广汽集团…...
Oracle 中的各种名称(*_name)参数的含义与作用
Oracle 中的各种名称(*_name)参数的含义与作用 目录 Oracle 中的各种名称(*_name)参数的含义与作用一、数据库名:db_name二、数据库所在的域:db_domain三、全局数据库名:global_name四、服务名&…...

前端页面的内容格式
TaskBuilder可以编辑的前端页面类型分为HTML和tfp(Taskmsg Front Page)两种格式,HTML格式只能用代码编辑器编辑,这种模式基本很少有人用,大家都用tfp格式,因为使用TaskBuilder向导创建的前端页面都是采用的…...

数据库1-4讲
各种名词区分 内模式也叫物理模式、存储模式。 概念模式也叫全局模式、逻辑模式。 外模式也叫用户模式。 笛卡尔积:D1、D2、D3集合中任取一个的所有可能情况。 因此上述笛卡尔积的基数22312 关系模型的三个完整性: 实体完整性&#x…...

设计模式 行为型 命令模式(Command Pattern)与 常见技术框架应用 解析
命令模式(Command Pattern)是一种行为型设计模式,它旨在将请求发送者和接收者解耦,通过将一个请求封装为一个对象,从而允许参数化客户端对象以进行不同的请求、排队请求或记录请求,并支持可撤销操作。 在软…...

【Redis】简介|优点|使用场景|为什么Redis快
目录 一、简介 二、特性(优点) 三、使用场景 一、简介 内存中存储数据的中间件,用于数据库,数据缓存,在分布式系统中能够大展拳脚 中间件:应用程序可以直接从 Redis 中获取数据,而不必频繁地…...

Clisoft SOS与CAD系统集成
Clisoft SOS与CAD系统集成 以下内容大部分来自官方文档,目前只用到与Cadence Virtuoso集成,其他还未用到,如有问题或相关建议,可以留言。 与Keysight ADS集成 更新SOS客户端配置文件sos.cfg,以包含支持ADS的模板&am…...

【linux系统之redis6】redis的安装与初始化
下载redis的linux对应的安装包,并上传到linux虚拟机里面 解压压缩包 tar -zxzf redis-6.2.6.tar.gz解压后,进入redis文件 cd redis-6.2.6执行编译 make && make install看到下图,就说明redis安装成功了 默认的安装路径,…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...

Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...