完美组合SpringBoot + Minio 快速文件切片上传

前言

在现代互联网应用中,文件上传是一个常见的功能需求。对于大文件上传,传统的单次上传方式可能会导致网络不稳定、上传失败等问题。这次将介绍如何使用SpringBoot和Minio实现文件切片上传,解决大文件上传的痛点,同时支持秒传和续传功能。

一、Minio简介

Minio是一款开源的对象存储服务器,支持多种操作系统(如Linux、Windows、MacOS等),并提供了简单、可扩展、高可用的对象存储解决方案。Minio的主要特点包括:

  1. 简单易用:安装和配置简单,提供Web UI管理界面。

  2. 可扩展性:支持单节点、多节点部署,可扩展到多个节点。

  3. 高可用性:支持数据冗余备份、数据复制和故障转移。

  4. 安全性:支持SSL/TLS加密、访问控制和数据加密。

  5. 多语言支持:支持Java、Python、Go等多种编程语言。

  6. 对象存储:支持任意数量和大小的对象存储。

Minio适用于多种场景,包括大规模数据存储、图像和媒体存储、云原生应用、数据保护与灾难恢复、分布式计算和机器学习等。

二、Minio安装与配置

1. 安装Minio

使用Docker安装Minio
# 拉取Minio镜像
docker pull minio/minio

# 启动Minio容器
docker run -p 9000:9000 -p 9090:9090 \
  --name minio \
  -d --restart=always \
  -e "MINIO_ACCESS_KEY=IT@WangHui" \
  -e "MINIO_SECRET_KEY=IT@WangHui" \
  minio/minio server /data --console-address ":9000" --address ":9090"
  • 9000:Web管理界面端口

  • 9090:服务端口

  • MINIO_ACCESS_KEYMINIO_SECRET_KEY:访问凭证

防火墙配置

确保防火墙允许访问9000和9090端口:

firewall-cmd --zone=public --add-port=9000/tcp --permanent
firewall-cmd --zone=public --add-port=9090/tcp --permanent
firewall-cmd --reload

2. 访问Minio

启动后,通过浏览器访问 http://localhost:9000,使用启动时设置的用户名和密码登录。

三、SpringBoot集成Minio

1. 项目依赖

在SpringBoot项目中引入Minio的Java SDK依赖:

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

2. 配置文件

application.yml 中配置Minio相关信息:

spring:
  minio:
    access-key: dAMaxkWaXUD1CV1JHbqw
    secret-key: AXt3SD0JFkDENFbMeJKOOQb5wj8KvabZWu33Rs84
    url: http://192.168.18.14:9090
    bucket-name: wanghui

3. Minio配置类

创建一个配置类,用于初始化Minio客户端:

@Configuration
@ConfigurationProperties(prefix = "spring.minio")
public class MinioConfig {
    private String accessKey;
    private String secretKey;
    private String url;
    private String bucketName;

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

4. Minio工具类

创建工具类,封装文件上传、下载等操作:

@Component
public class MinioUtils {
    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioConfig configuration;

    public boolean existBucket(String name) {
        try {
            boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(name).build());
            if (!exists) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(name).build());
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public void upload(MultipartFile file, String fileName) {
        try {
            InputStream inputStream = file.getInputStream();
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(configuration.getBucketName())
                    .object(fileName)
                    .stream(inputStream, file.getSize(), -1)
                    .contentType(file.getContentType())
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public ResponseEntity<byte[]> download(String fileName) {
        try {
            InputStream in = minioClient.getObject(GetObjectArgs.builder()
                    .bucket(configuration.getBucketName())
                    .object(fileName)
                    .build());
            // 处理下载逻辑
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

四、实现文件切片上传

1. 前端切片上传

前端使用JavaScript将文件切片,并逐个上传到Minio:

function uploadFile(file) {
    const chunkSize = 1024 * 1024 * 5; // 每片5MB
    const chunks = Math.ceil(file.size / chunkSize);
    const fileSlice = File.prototype.slice || File.prototype.webkitSlice || File.prototype.mozSlice;

    for (let i = 0; i < chunks; i++) {
        const start = i * chunkSize;
        const end = Math.min(file.size, start + chunkSize);
        const chunk = fileSlice.call(file, start, end);
        uploadChunk(chunk, i, chunks);
    }
}

function uploadChunk(chunk, chunkIndex, totalChunks) {
    // 调用后端接口上传切片
    const formData = new FormData();
    formData.append('file', chunk);
    formData.append('chunkIndex', chunkIndex);
    formData.append('totalChunks', totalChunks);

    fetch('/api/uploadChunk', {
        method: 'POST',
        body: formData
    }).then(response => response.json())
      .then(data => console.log(data));
}

2. 后端合并切片

后端接收到所有切片后,按照顺序合并成完整文件:

@PostMapping("/uploadChunk")
public AjaxResult uploadChunk(@RequestParam("file") MultipartFile file,
                              @RequestParam("chunkIndex") Integer chunkIndex,
                              @RequestParam("totalChunks") Integer totalChunks,
                              @RequestParam("fileName") String fileName) {
    // 存储切片
    String chunkName = fileName + "_chunk_" + chunkIndex;
    minioUtils.upload(file, chunkName);

    // 检查是否所有切片都已上传
    if (chunkIndex == totalChunks - 1) {
        mergeChunks(fileName, totalChunks);
    }

    return AjaxResult.success("切片上传成功");
}

private void mergeChunks(String fileName, Integer totalChunks) {
    List<String> chunkNames = new ArrayList<>();
    for (int i = 0; i < totalChunks; i++) {
        chunkNames.add(fileName + "_chunk_" + i);
    }

    // 合并切片
    minioUtils.mergeObjects(chunkNames, fileName);
}

五、功能测试

1. 大文件上传测试

上传一个大文件(如1GB视频),观察上传速度和稳定性。

2. 断点续传测试

模拟网络中断,重新上传未完成的切片,验证续传功能。

3. 秒传功能测试

上传一个已存在的文件,验证是否直接返回文件URL。

六、总结

通过SpringBoot和Minio实现文件切片上传,可以有效解决大文件上传的性能问题,同时支持断点续传和秒传功能。Minio的高可用性和扩展性使其成为理想的对象存储解决方案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

脑洞消息铺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值