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

news2025/1/8 15:07:57

关注: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;

    @Bean
    public 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 {

    @Autowired
    private 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 {

    @Autowired
    private MinioClient minioClient;

    private final String bucketName = "mybucket";  // 从配置中加载桶名

    // 文件上传方法
    public String uploadFile(MultipartFile file) throws IOException {
        try {
            // 获取文件输入流
            InputStream fileInputStream = file.getInputStream();
            // 上传文件到 MinIO
            minioClient.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 {

    @Autowired
    private 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.coloradmin.cn/o/2273275.html

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

相关文章

把vue项目或者vue组件发布成npm包或者打包成lib库文件本地使用

将vue项目发布成npm库文件&#xff0c;第三方通过npm依赖安装使用&#xff1b;使用最近公司接了一个项目&#xff0c;这个项目需要集成到第三方页面&#xff0c;在第三方页面点击项目名称&#xff0c;页面变成我们的项目页面&#xff1b;要求以npm库文件提供给他们&#xff1b;…

Kafka为什么要放弃Zookeeper

1.Kafka简介 Apache Kafka最早是由Linkedin公司开发&#xff0c;后来捐献给了Apack基金会。 Kafka被官方定义为分布式流式处理平台&#xff0c;因为具备高吞吐、可持久化、可水平扩展等特性而被广泛使用。目前Kafka具体如下功能&#xff1a; 消息队列,Kafka具有系统解耦、流…

【JVM】总结篇-类的加载篇之 类的加载器 和ClassLoader分析

文章目录 类的加载器ClassLoader自定义类加载器双亲委派机制概念源码分析优势劣势如何打破Tomcat 沙箱安全机制JDK9 双亲委派机制变化 类的加载器 获得当前类的ClassLoader clazz.getClassLoader() 获得当前线程上下文的ClassLoader Thread.currentThread().getContextClassLoa…

java 转义 反斜杠 Unexpected internal error near index 1

代码&#xff1a; String str"a\\c"; //出现异常&#xff0c;Unexpected internal error near index 1 //System.out.println(str.replaceAll("\\", "c"));//以下三种都正确 System.out.println(str.replace(\\, c)); System.out.println(str.r…

el-table 实现纵向多级表头

为了实现上图效果&#xff0c;最开始打算用el-row、el-col去实现&#xff0c;但发现把表头和数据分成两大列时&#xff0c;数据太多时会导致所在格高度变高。但由于每一格数据肯定不一样&#xff0c;为保持高度样式一致&#xff0c;就需要我们手动去获取最高格的高度之后再设置…

2025最新版Visual Studio Code安装使用指南

2025最新版Visual Studio Code安装使用指南 Installation and Usage Guide for the Latest Visual Studio Code in 2024 By JacksonML 2025-1-7 1. Visual Studio Code背景 早在二十年前&#xff0c;通用的集成开发环境&#xff08;Integrated Deveopment Environment, 简称…

Flutter 鸿蒙化 flutter和鸿蒙next混和渲染

前言导读 这一个节课我们讲一下PlatformView的是使用 我们在实战中有可能出现了在鸿蒙next只加载一部分Flutter的情况 我们今天就讲一下这种情况具体实现要使用到我们的PlatformView 效果图 具体实现: 一、Native侧 使用 DevEco Studio工具打开 platform_view_example\oho…

LabVIEW语言学习过程是什么?

学习LabVIEW语言的过程可以分为几个阶段&#xff0c;每个阶段的重点内容逐步加深&#xff0c;帮助你从入门到精通。以下是一个简洁的学习过程&#xff1a; ​ 1. 基础入门阶段 理解图形化编程&#xff1a;LabVIEW是一种图形化编程语言&#xff0c;与传统的文本编程语言不同&am…

Kubernetes Gateway API-4-TCPRoute和GRPCRoute

1 TCPRoute 目前 TCP routing 还处于实验阶段。 Gateway API 被设计为与多个协议一起工作&#xff0c;TCPRoute 就是这样一个允许管理TCP流量的路由。 在这个例子中&#xff0c;我们有一个 Gateway 资源和两个 TCPRoute 资源&#xff0c;它们按照以下规则分配流量&#xff1…

嵌入式SD/TF卡通用协议-SDIO协议

SD卡&#xff08;SecureDigital MemoryCard&#xff09;即&#xff1a;安全数码卡&#xff0c;它是在MMC的基础上发展而来&#xff0c;是一种基于半导体快闪记忆器的新一代记忆设备&#xff0c;它被广泛地于便携式装置上使用&#xff0c;例如数码相机、个人数码助理(PDA)和多媒…

性能测试05|JMeter:分布式、报告、并发数计算、性能监控

目录 一、JMeter分布式 1、应用场景 2、原理 3、分布式相关注意事项 4、分布式配置与运行 二、JMeter报告 1、聚合报告 2、HTML报告 三、并发用户数&#xff08;线程数&#xff09;计算 四、JMeter下载第三方插件 五、性能监控 1、Concurrency Thread Group 线程组…

wujie无界微前端框架初使用

先说一下项目需求&#xff1a;将单独的四套系统的登录操作统一放在一个入口页面进行登录&#xff0c;所有系统都使用的是vue3&#xff0c;&#xff08;不要问我为啥会这样设计&#xff0c;产品说的客户要求&#xff09; 1.主系统下载wujie 我全套都是vue3&#xff0c;所以直接…

SpringIOC循环依赖与三级缓存

SpringIOC循环依赖与三级缓存 Spring解决循环依赖的核心机制就是通过三级缓存&#xff1a; 一级缓存&#xff08;singletonObjects&#xff09;&#xff1a;存储完全初始化好的Bean&#xff1b;二级缓存&#xff08;earlySingletonObjects&#xff09;&#xff1a;存储原始实例…

【顶刊TPAMI 2025】多头编码(MHE)之极限分类 Part 3:算法实现

目录 1 三种多头编码&#xff08;MHE&#xff09;实现1.1 多头乘积&#xff08;MHP&#xff09;1.2 多头级联&#xff08;MHC&#xff09;1.3 多头采样&#xff08;MHS&#xff09;1.4 标签分解策略 论文&#xff1a;Multi-Head Encoding for Extreme Label Classification 作者…

前端 图片上鼠标画矩形框,标注文字,任意删除

效果&#xff1a; 页面描述&#xff1a; 对给定的几张图片&#xff0c;每张能用鼠标在图上画框&#xff0c;标注相关文字&#xff0c;框的颜色和文字内容能自定义改变&#xff0c;能删除任意画过的框。 实现思路&#xff1a; 1、对给定的这几张图片&#xff0c;用分页器绑定…

【办公利器】ReNamer (批量文件重命名工具) Pro v7.6.0.4 多语便携版,海量文件秒速精准改名!

ReNamer是一款功能强大的文件重命名工具&#xff0c;它可以帮助用户快速方便地批量重命名文件和文件夹。 软件功能 批量重命名&#xff1a;ReNamer可以同时处理多个文件和文件夹&#xff0c;并对其进行批量重命名&#xff0c;从而节省时间和劳动力。灵活的重命名规则&#xff…

unity学习13:gameobject的组件component以及tag, layer 归类

目录 1 gameobject component 是unity的基础 1.1 类比 1.2 为什么要这么设计&#xff1f; 2 从空物体开始 2.1 创建2个物体 2.2 给 empty gameobject添加组件 3 各种组件和新建组件 3.1 点击 add component可以添加各种组件 3.2 新建组件 3.3 组件的操作 3.4 特别的…

数据库模型全解析:从文档存储到搜索引擎

目录 前言1. 文档存储&#xff08;Document Store&#xff09;1.1 概念与特点1.2 典型应用1.3 代表性数据库 2. 图数据库&#xff08;Graph DBMS&#xff09;2.1 概念与特点2.2 典型应用2.3 代表性数据库 3. 原生 XML 数据库&#xff08;Native XML DBMS&#xff09;3.1 概念与…

CSS——1.优缺点

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title><link rel"stylesheet" type"text/css" href"1-02.css"/></head><body><!--css&#xff1a;层叠样式表…

UE5本地化和国际化语言

翻译语言 工具 - 本地化控制板 Localization Dashboard 修改图中这几个地方就可以 点击箭头处&#xff0c;把中文翻译成英语&#xff0c;如果要更多语言就点 添加新语言 最后点击编译即可 编译完&#xff0c;会在目录生成文件夹 设置界面相关蓝图中设置 切换本地化语言 必须在…