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

Spring Boot | 基于MinIO实现文件上传和下载

关注:CodingTechWork

介绍

  在现代的 web 应用中,文件上传和下载是常见的需求。MinIO 是一个开源的高性能分布式对象存储服务,可以用来存储和管理大量的非结构化数据,如图片、视频、日志文件等。本文将介绍如何在 Spring Boot 应用中,结合 MinIO 来实现文件的上传和下载功能,并使用 Feign 客户端进行远程调用文件上传和下载的服务。

MinIO 相关介绍

  MinIO 是一个高性能的分布式对象存储系统,兼容 Amazon S3 API,通常用于存储和管理大量非结构化数据,如图片、视频、备份、日志等。它提供了与 S3 完全兼容的 API,使得开发者能够使用相同的工具和库与其进行交互。MinIO 被设计为云原生,适用于在 Docker、Kubernetes 和虚拟机中运行。

MinIO 特点

  1. 高性能:支持高吞吐量、高并发的读写操作,适用于需要大规模数据存储的应用。
  2. S3 兼容:MinIO 实现了完整的 Amazon S3 API,支持通过现有的 S3 客户端、SDK 和工具来进行交互。
  3. 高可扩展性:支持水平扩展,支持分布式部署,能够在多台机器上运行并提供统一的对象存储服务。
  4. 轻量级:MinIO 是一个轻量级的应用程序,易于部署和管理,可以在资源受限的环境中运行(如单机或者小型集群)。
  5. 支持对象加密:MinIO 支持对象级加密,可以为上传到存储中的对象加密,保证数据安全。
  6. 支持版本控制:MinIO 支持对象版本管理,允许对存储中的文件进行版本控制。

MinIO 核心概念

桶(Bucket)

  1. 在 MinIO 中,桶类似于文件系统中的文件夹。每个桶用于存储一组对象。
  2. 每个桶都可以有独立的权限配置。
  3. 存储在桶中的对象有唯一的标识符(通常是对象的文件名)。

对象(Object)

  1. 对象是 MinIO 存储的基本单位,类似于文件系统中的文件。
  2. 对象由数据和元数据组成,可以是任何类型的数据,如文本、图像、视频等。

对象键(Object Key)

  1. 对象键是对象在桶中的唯一标识符,通常对应于文件名。

访问密钥和密钥(Access Key & Secret Key)

  1. MinIO 使用访问密钥(Access Key)和密钥(Secret Key)进行身份验证,类似于 S3。
  2. 用户可以配置访问密钥和密钥以确保数据的访问权限。

MinIO API 介绍

  MinIO 的 API 设计遵循 S3 API,几乎所有 S3 的 API 都可以在 MinIO 中使用。以下是 MinIO 支持的常见操作和 API:

Bucket 操作

  1. 创建桶(Create Bucket):创建一个新桶来存储对象。
minioClient.makeBucket("mybucket");
  1. 列举桶(List Buckets):获取当前 MinIO 实例中所有存在的桶。
List<Bucket> buckets = minioClient.listBuckets();
  1. 检查桶是否存在(Bucket Exists):检查桶是否存在。
boolean exists = minioClient.bucketExists("mybucket");
  1. 删除桶(Delete Bucket):删除桶(桶必须为空才能删除)。
minioClient.removeBucket("mybucket");

对象操作

  1. 上传对象(Put Object):上传一个文件到 MinIO 中指定的桶。
minioClient.putObject("mybucket", "myfile.txt", fileInputStream, fileSize, null, null, "application/octet-stream");
  1. 获取对象(Get Object):从指定桶中获取对象内容。
InputStream inputStream = minioClient.getObject("mybucket", "myfile.txt");
  1. 删除对象(Remove Object):删除 MinIO 存储桶中的某个对象。
minioClient.removeObject("mybucket", "myfile.txt");
  1. 列举对象(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());
}
  1. 获取对象元数据(Stat Object):获取对象的元数据,如大小、最后修改时间等。
StatObjectResponse stat = minioClient.statObject("mybucket", "myfile.txt");
System.out.println("Object size: " + stat.size());

文件下载

  1. 下载对象(Get Object):从 MinIO 中下载一个对象,并将其存储到本地文件系统。
minioClient.getObject("mybucket", "myfile.txt", Paths.get("/path/to/destination"));

对象版本控制

  1. 启用版本控制:启用桶的版本控制功能。
minioClient.enableBucketVersioning("mybucket");
  1. 获取对象版本(Get Object Version):获取对象的指定版本。
InputStream inputStream = minioClient.getObject("mybucket", "myfile.txt", "versionId");
  1. 删除对象版本(Remove Object Version):删除某个版本的对象。
minioClient.removeObject("mybucket", "myfile.txt", "versionId");

权限管理

  MinIO 支持基于用户的权限控制,可以通过配置桶的访问策略来管理谁可以访问存储中的对象。

  1. 设置桶的访问权限(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 安全性特性

  1. 加密:
    MinIO 支持两种类型的加密:服务端加密(SSE)客户端加密(CSE)。服务端加密会在对象上传到 MinIO 时自动对其进行加密。
  2. 身份验证与授权:
    MinIO 使用访问密钥(Access Key)密钥(Secret Key)来进行身份验证。用户可以通过配置 MinIO 的访问控制列表(ACL)来限制谁可以访问桶和对象。
  3. TLS/SSL 支持:
    MinIO 支持通过 TLS(即 HTTPS)加密通信来保护数据传输安全。

项目结构

本项目的文件上传和下载功能将分成两个部分:

  1. minio 服务端(本地服务处理文件上传)
  2. 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 官方文档

http://www.lryc.cn/news/517379.html

相关文章:

  • 企业手机号搜索API接口
  • VirtualBox Main API 学习笔记
  • [Linux]Mysql9.0.1服务端脱机安装配置教程(redhat)
  • uniapp--HBuilder开发
  • 计算机毕业设计学习项目-P10080 基于springboot+vue的社团管理系统的设计与实现
  • with as提高sql的执行效率
  • 【银河麒麟高级服务器操作系统实例】tcp半链接数溢出分析及处理全过程
  • 计算机毕业设计Python中华古诗词知识图谱可视化 古诗词智能问答系统 古诗词数据分析 古诗词情感分析模型 自然语言处理NLP 机器学习 深度学习
  • 分布式ID生成-雪花算法实现无状态
  • 【问题】配置 Conda 与 Pip 源
  • Zookeeper是如何保证事务的顺序一致性的?
  • 东土科技参股广汽集团飞行汽车初创公司,为低空经济构建新型产业生态
  • Oracle 中的各种名称(*_name)参数的含义与作用
  • 前端页面的内容格式
  • 数据库1-4讲
  • 设计模式 行为型 命令模式(Command Pattern)与 常见技术框架应用 解析
  • 【Redis】简介|优点|使用场景|为什么Redis快
  • Clisoft SOS与CAD系统集成
  • 【linux系统之redis6】redis的安装与初始化
  • Backend - EF Core(C# 操作数据库 DB)
  • WebSocket 性能优化:从理论到实践
  • 我用AI学Android Jetpack Compose之入门篇(2)
  • 以太网协议在汽车应用中的动与静
  • 【C语言】_指针与数组
  • Selenium 的四种等待方式及使用场景
  • React知识盲点——组件通信、性能优化、高级功能详解(大纲)
  • Vue 按键生成多个表单
  • 网络安全:交换机技术
  • Flask 快速入门
  • C#设计模式(行为型模式):备忘录模式,时光倒流的魔法