首页 > 其他分享 >Spring Boot + MinIO 实现文件切片极速上传技术

Spring Boot + MinIO 实现文件切片极速上传技术

时间:2023-12-28 15:00:44浏览次数:27  
标签:文件 minio Spring Boot springframework io import 上传 MinIO

(文章目录)

一、 引言

现代Web应用中,文件上传是一个常见的需求,尤其是对于大文件的上传,如视频、音频或大型文档。为了提高用户体验和系统性能,文件切片上传技术逐渐成为热门选择。本文将介绍如何使用Spring Boot和MinIO实现文件切片极速上传技术,通过将大文件分割成小片段并并行上传,显著提高文件上传速度。 55ebaf85a2434252bce7ab564fa1a4f6.png

二、 文件切片上传简介

文件切片上传是指将大文件分割成小的片段,然后通过多个请求并行上传这些片段,最终在服务器端将这些片段合并还原为完整的文件。这种方式有助于规避一些上传过程中的问题,如网络不稳定、上传中断等,并能提高上传速度。

三、 技术选型

3.1 Spring Boot

Spring Boot是一个基于Spring框架的轻量级、快速开发的框架,提供了许多开箱即用的功能,适合构建现代化的Java应用。

3.2 MinIO

MinIO是一款开源的对象存储服务器,与Amazon S3兼容。它提供了高性能、高可用性的存储服务,适用于大规模文件存储。 2.png

四、 搭建Spring Boot项目

首先,我们需要搭建一个基本的Spring Boot项目。可以使用Spring Initializer(https://start.spring.io/)生成项目骨架,选择相应的依赖,如Web和Thymeleaf。

<!-- pom.xml -->

<dependencies>
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Thymeleaf模板引擎 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

    <!-- MinIO Java客户端 -->
    <dependency>
        <groupId>io.minio</groupId>
        <artifactId>minio</artifactId>
        <version>8.3.3</version>
    </dependency>
</dependencies> 

五、 集成MinIO

5.1 配置MinIO连接信息

在application.properties中配置MinIO的连接信息,包括服务地址、Access Key和Secret Key。

# application.properties

# MinIO配置
minio.endpoint=http://localhost:9000
minio.accessKey=minioadmin
minio.secretKey=minioadmin
minio.bucketName=mybucket

5.2 MinIO配置类

创建MinIO配置类,用于初始化MinIO客户端。

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.endpoint}")
    private String endpoint;

    @Value("${minio.accessKey}")
    private String accessKey;

    @Value("${minio.secretKey}")
    private String secretKey;

    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build();
    }
}

六、 文件切片上传实现

6.1 控制器层

创建一个文件上传的控制器,负责处理文件切片上传的请求。

import io.minio.MinioClient;
import io.minio.errors.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

@RestController
@RequestMapping("/file")
public class FileController {

    @Autowired
    private MinioClient minioClient;

    @Value("${minio.bucketName}")
    private String bucketName;

    @PostMapping("/upload")
    public String upload(@RequestParam("file") MultipartFile file) {
        // 实现文件切片上传逻辑
        // ...

        return "Upload success!";
    }
}

6.2 服务层

创建文件上传服务类,处理文件切片的具体上传逻辑。

import io.minio.MinioClient;
import io.minio.errors.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

@Service
public class FileService {

    @Autowired
    private MinioClient minioClient;

    @Value("${minio.bucketName}")
    private String bucketName;

    public void uploadFile(String objectName, MultipartFile file) throws IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, NoResponseException, ErrorResponseException, InternalException, InvalidBucketNameException, XmlParserException, InvalidArgumentException {
        // 实现文件切片上传逻辑
        // ...
    }
}

6.3 文件切片上传逻辑

在服务层的uploadFile方法中实现文件切片上传逻辑。这里使用MinIO的putObject方法将文件切片上传至MinIO服务器。

import io.minio.PutObjectArgs;
import io.minio.errors.*;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class FileService {

    // 省略其他代码...

    public void uploadFile(String objectName, MultipartFile file) throws IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, NoResponseException, ErrorResponseException, InternalException, InvalidBucketNameException, XmlParserException, InvalidArgumentException {
        InputStream inputStream = file.getInputStream();
        long size = file.getSize();
        long chunkSize = 5 * 1024 * 1024; // 每片大小5MB

        long offset = 0;
        while (offset < size) {
            long currentChunkSize = Math.min(chunkSize, size - offset);
            byte[] chunk = new byte[(int) currentChunkSize];
            inputStream.read(chunk);

            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .stream(inputStream, currentChunkSize, -1)
                            .build()
            );

            offset += currentChunkSize;
        }

        inputStream.close();
    }
}

七、 文件合并逻辑

在文件上传完成后,需要将所有的切片文件合并还原为完整的文件。在FileController中增加一个合并文件的接口。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/file")
public class FileController {

    // 省略其他代码...

    @Autowired
    private FileService fileService;

    @PostMapping("/merge")
    public String merge(@RequestParam String objectName) {
        try {
            fileService.mergeFile(objectName);
            return "Merge success!";
        } catch (Exception e) {
            e.printStackTrace();
            return "Merge failed!";
        }
    }
}

在FileService中增加合并文件的方法。

import io.minio.CopyObjectArgs;
import io.minio.GetObjectArgs;
import io.minio.PutObjectArgs;
import io.minio.errors.*;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class FileService {

    // 省略其他代码...

    public void mergeFile(String objectName) throws IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, NoResponseException, ErrorResponseException, InternalException, InvalidBucketNameException, XmlParserException, InvalidArgumentException {
        Iterable<io.minio.messages.Item> parts = minioClient.listObjects(bucketName, objectName);

        // 通过CopyObject将所有分片合并成一个对象
        for (io.minio.messages.Item part : parts) {
            String partName = part.objectName();
            minioClient.copyObject(
                    CopyObjectArgs.builder()
                            .source(bucketName, partName)
                            .destination(bucketName, objectName)
                            .build()
            );
        }

        // 删除所有分片
        for (io.minio.messages.Item part : parts) {
            String partName = part.objectName();
            minioClient.removeObject(bucketName, partName);
        }
    }
}

八、 页面展示

在前端页面,使用Thymeleaf模板引擎展示上传按钮和上传进度。

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>File Upload</title>
</head>
<body>
    <form id="uploadForm" action="/file/upload" method="post" enctype="multipart/form-data">
        <input type="file" name="file" id="file" />
        <input type="submit" value="Upload" />
    </form>

    <div id="progress" style="display: none;">
        <progress id="progressBar" max="100" value="0"></progress>
        <span id="percentage">0%</span>
    </div>

    <script>
        document.getElementById('uploadForm').addEventListener('submit', function (event) {
            event.preventDefault();

            var fileInput = document.getElementById('file');
            var file = fileInput.files[0];
            if (!file) {
                alert('Please choose a file.');
                return;
            }

            var formData = new FormData();
            formData.append('file', file);

            var xhr = new XMLHttpRequest();
            xhr.open('POST', '/file/upload', true);

            xhr.upload.onprogress = function (e) {
                if (e.lengthComputable) {
                    var percentage = Math.round((e.loaded / e.total) * 100);
                    document.getElementById('progressBar').value = percentage;
                    document.getElementById('percentage').innerText = percentage + '%';
                }
            };

            xhr.onload = function () {
                document.getElementById('progress').style.display = 'none';
                alert('Upload success!');
            };

            xhr.onerror = function () {
                alert('Upload failed!');
            };

            xhr.send(formData);

            document.getElementById('progress').style.display = 'block';
        });
    </script>
</body>
</html>

九、 性能优化与拓展

9.1 性能优化

  • 并发上传: 利用多线程或异步任务,将文件切片并行上传,提高上传效率。
  • 分布式部署: 将文件存储和应用部署在不同的服务器,减轻单个服务器的负担,提高整体性能。

9.2 拓展功能

  • 断点续传: 支持文件上传中断后的断点续传功能,提高用户体验。
  • 权限控制: 使用MinIO的访问策略进行权限控制,确保文件上传安全性。

十、 总结

通过本文,我们深入了解了如何使用Spring Boot和MinIO实现文件切片上传技术。通过文件切片上传,我们能够提高文件上传的速度,优化用户体验。在实际应用中,我们可以根据需求进行性能优化和功能拓展,使得文件上传系统更加强大和可靠。希望本文对您理解文件切片上传技术以及Spring Boot和MinIO的使用有所帮助。

标签:文件,minio,Spring,Boot,springframework,io,import,上传,MinIO
From: https://blog.51cto.com/u_16357126/9015221

相关文章

  • 【SpringBoot零基础入门到项目实战②】安装Java和Maven,创建你的第一个项目
    文章目录导言安装JavaWindows系统macOS系统Linux系统安装和配置MavenWindows系统macOS系统Linux系统配置Maven本地仓库使用阿里镜像加速创建第一个SpringBoot项目拓展学习(提前了解后面会讲到)1.深入理解SpringBoot的项目结构2.学习SpringBoot的自动配置3.掌握SpringBoot......
  • 项目中使用spring.session.store-type=redis和@EnableRedisHttpSession 的区别
    spring项目的session存在哪里SpringSession提供了多种存储策略,可以选择将session存储在内存、数据库或Redis缓存中。内存存储:这是默认的存储方式,适用于单个应用程序的情况。SpringSession会在应用程序启动时创建一个ConcurrentHashMap对象,用于存储session数据。JDBC存......
  • Java 系统学习 | Springboot 写 hello world
    经过一段时间基础学习,现在开始使用Springboot框架完成项目,特地记录一下,方便后续查漏补缺。本篇使用Springboot3框架,IDEA2022编辑器,java17版本。新建项目file->new->project弹框中填入自己的信息Name项目名称Location项目存放路径LanguageJavaB......
  • 如何使用 Prometheus 监控SpringBoot系统
    公众号「架构成长指南」,专注于生产实践、云原生、分布式系统、大数据技术分享在从零开始:使用Prometheus与Grafana搭建监控系统中,主要讲解了如何使用监控系统资源并进行告警,这节主要分享下,如何在业务系统中使用Prometheus来监控业务系统指标,业务系统使用SpringBoot构建。我们要......
  • 手把手从安装本地虚拟机,基于docker,部署springboot+vue项目(若依框架前后端分离版本演示
    目录1.安装本地虚拟机centos2.安装docker,拉取镜像,创建容器3.打包部署后端4.配置nginx5.打包部署前端6.常见问题汇总1.安装本地虚拟机centos部署环境提供vm16,和centos7,其中把镜像改成.iso文件就可以了阿里云链接:https://www.alipan.com/s/BTnpjuHWtEp为什么用阿里云,不限速啊,秉......
  • SpringBoot+JaywayJsonPath实现Json数据的DSL(按照指定节点表达式解析json获取指定数
    场景若依前后端分离版手把手教你本地搭建环境并运行项目:若依前后端分离版手把手教你本地搭建环境并运行项目_前后端分离项目本地运行在上面搭建SpringBoot项目的基础上,并且在项目中引入fastjson、hutool等所需依赖后。JaywayJsonPath:GitHub-json-path/JsonPath:JavaJsonPathi......
  • 【SpringBoot快速入门】(4)SpringBoot项目案例代码示例
    目录1创建工程3配置文件4静态资源之前我们已经学习的Spring、SpringMVC、Mabatis、Maven,详细讲解了Spring、SpringMVC、Mabatis整合SSM的方案和案例,上一节我们学习了SpringBoot的开发步骤、工程构建方法以及工程的快速启动,从这一节开始,我们开始学习SpringBoot配置文件。接下来......
  • 【SpringBoot快速入门】(3)SpringBoot整合junit和MyBatis 详细代码示例与讲解
    目录1.SpringBoot整合junit1.1环境准备1.2编写测试类2.SpringBoot整合mybatis2.1回顾Spring整合Mybatis2.2SpringBoot整合mybatis2.2.1创建模块2.2.2定义实体类2.2.3定义dao接口2.2.4定义测试类2.2.5编写配置2.2.6测试2.2.7使用Druid数据源之前我们已经学习的Spring、......
  • 【SpringBoot快速入门】(2)SpringBoot的配置文件与配置方式详细讲解
    之前我们已经学习的Spring、SpringMVC、Mabatis、Maven,详细讲解了Spring、SpringMVC、Mabatis整合SSM的方案和案例,上一节我们学习了SpringBoot的开发步骤、工程构建方法以及工程的快速启动,从这一节开始,我们开始学习SpringBoot配置文件。接下来,我们逐步开始学习,本教程所有示例均基于......
  • 【Spring教程31】SSM框架整合实战:从零开始学习SSM整合配置,如何编写Mybatis SpringMVC
    目录1流程分析2整合配置2.1步骤1:创建Maven的web项目2.2步骤2:添加依赖2.3步骤3:创建项目包结构2.4步骤4:创建SpringConfig配置类2.5步骤5:创建JdbcConfig配置类2.6步骤6:创建MybatisConfig配置类2.7步骤7:创建jdbc.properties2.8步骤8:创建SpringMVC配置类2.9步骤9:创......