专业的JAVA编程教程与资源

网站首页 > java教程 正文

SpringBoot与MinIO整合,实现大文件分片上传与分片合并功能

temp10 2025-05-11 00:55:56 java教程 2 ℃ 0 评论

用户需要上传和存储的文件越来越大,传统的单次上传方式往往会导致上传失败或用户体验不佳。为了解决这一问题,我们引入了大文件分片上传与分片合并功能。该功能可以将大文件分割成多个小分片进行上传,即使在网络不稳定的情况下也能确保上传的成功率,并且在所有分片成功上传后自动合并成完整的文件。

功能特点

1. 分片上传

  • 分片处理:系统会将大文件自动分割成多个较小的分片。
  • 并发上传:每个分片可以独立上传,支持并发传输,提高上传速度。
  • 断点续传:如果某个分片上传失败,只需重新上传该分片,而不需要从头开始。

2. 分片合并

  • 自动合并:当所有分片都成功上传后,系统会自动将这些分片合并成一个完整的文件。
  • 完整性校验:在合并过程中,系统会对每个分片进行校验,确保文件的完整性和准确性。

3. 提升体验

  • 稳定性:即使网络状况较差,也可以保证文件的顺利上传。
  • 效率:通过并发上传和断点续传,大大提高了上传效率。
  • 可靠性:自动合并机制确保最终生成的文件与原始文件完全一致。

应用场景

1. 视频上传

  • 用户可以通过我们的平台上传长视频,无需担心上传过程中的中断问题。
  • 视频上传完成后,系统会自动将其合并并保存到指定位置。

2. 大型文件备份

  • 对于大型文件(如数据库备份、软件安装包等),可以利用分片上传功能进行高效备份。
  • 确保备份文件的完整性和可用性,便于后续恢复操作。

3. 内容发布

  • 平台允许用户上传高清图片、音频、视频等内容,支持多格式文件的分片上传。
  • 内容上传完成后,系统会自动将其合并并展示给其他用户。

代码实操


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

    <!-- MinIO Java SDK -->
    <dependency>
        <groupId>io.minio</groupId>
        <artifactId>minio</artifactId>
        <version>8.4.3</version>
    </dependency>

    <!-- Gson for JSON processing -->
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
    </dependency>
</dependencies>

配置MinIO参数

application.yml文件中添加以下配置:

SpringBoot与MinIO整合,实现大文件分片上传与分片合并功能


minio:
  endpoint: http://localhost:9000
  access-key: minioadmin
  secret-key: minioadmin
  bucket-name: my-bucket

创建服务类

创建一个服务类来处理文件上传、分片合并以及权限控制的业务逻辑:


package com.example.demo.service;

import io.minio.*;
import io.minio.errors.MinioException;
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;
import java.util.UUID;

@Service
publicclass FileUploadService {

    @Value("${minio.endpoint}")
    private String endpoint; // MinIO服务器地址

    @Value("${minio.access-key}")
    private String accessKey; // MinIO访问密钥

    @Value("${minio.secret-key}")
    private String secretKey; // MinIO秘密密钥

    @Value("${minio.bucket-name}")
    private String bucketName; // 存储桶名称

    /**
     * 如果存储桶不存在,则创建存储桶
     */
    public void createBucketIfNotExists() throws IOException, NoSuchAlgorithmException, InvalidKeyException {
        try (MinioClient minioClient = MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build()) {
            boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
            if (!found) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            }
        }
    }

    /**
     * 上传文件分片到MinIO
     *
     * @param fileId   文件标识符
     * @param filePart 文件分片
     * @return 分片对象名称
     */
    public String uploadFilePart(String fileId, MultipartFile filePart) throws IOException, NoSuchAlgorithmException, InvalidKeyException, MinioException {
        try (MinioClient minioClient = MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build()) {
            // 构建分片对象名称
            String objectName = fileId + "/" + UUID.randomUUID();
            // 设置上传参数
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .stream(filePart.getInputStream(), filePart.getSize(), -1)
                    .contentType(filePart.getContentType())
                    .build();
            // 上传文件分片
            minioClient.putObject(putObjectArgs);
            return objectName;
        }
    }

    /**
     * 合并多个文件分片为一个完整文件
     *
     * @param fileId    文件标识符
     * @param partNames 分片对象名称列表
     */
    public void mergeFileParts(String fileId, String[] partNames) throws IOException, NoSuchAlgorithmException, InvalidKeyException, MinioException {
        try (MinioClient minioClient = MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build()) {
            // 构建最终文件对象名称
            String finalObjectName = fileId + ".merged";
            // 构建ComposeSource数组
            ComposeSource[] sources = new ComposeSource[partNames.length];
            for (int i = 0; i < partNames.length; i++) {
                sources[i] = ComposeSource.builder().bucket(bucketName).object(partNames[i]).build();
            }
            // 设置合并参数
            ComposeObjectArgs composeObjectArgs = ComposeObjectArgs.builder()
                    .bucket(bucketName)
                    .object(finalObjectName)
                    .sources(sources)
                    .build();
            // 合并文件分片
            minioClient.composeObject(composeObjectArgs);

            // 删除合并后的分片
            for (String partName : partNames) {
                minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(partName).build());
            }
        }
    }

    /**
     * 删除指定文件
     *
     * @param fileName 文件名
     */
    public void deleteFile(String fileName) throws IOException, NoSuchAlgorithmException, InvalidKeyException, MinioException {
        try (MinioClient minioClient = MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build()) {
            // 删除文件
            minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
        }
    }
}

创建控制器

创建一个控制器来接收客户端的文件上传请求:


package com.example.demo.controller;

import com.example.demo.service.FileUploadService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

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

@RestController
@RequestMapping("/file")
publicclass FileController {

    @Autowired
    private FileUploadService fileUploadService;

    /**
     * 上传文件分片
     *
     * @param filePart 文件分片
     * @return 分片对象名称
     */
    @PostMapping("/upload/part")
    public ResponseEntity<String> uploadFilePart(@RequestParam("file") MultipartFile filePart) throws IOException, NoSuchAlgorithmException, InvalidKeyException, io.minio.errors.MinioException {
        // 生成文件标识符
        String fileId = java.util.UUID.randomUUID().toString();
        // 上传文件分片
        String partName = fileUploadService.uploadFilePart(fileId, filePart);
        return ResponseEntity.ok(partName);
    }

    /**
     * 合并文件分片
     *
     * @param fileId 文件标识符
     * @param parts  分片对象名称列表
     * @return 成功消息
     */
    @PostMapping("/merge")
    public ResponseEntity<String> mergeFileParts(@RequestParam("fileId") String fileId, @RequestParam("parts") List<String> parts) throws IOException, NoSuchAlgorithmException, InvalidKeyException, io.minio.errors.MinioException {
        // 合并文件分片
        fileUploadService.mergeFileParts(fileId, parts.toArray(new String[0]));
        return ResponseEntity.ok("File merged successfully");
    }

    /**
     * 删除文件
     *
     * @param fileName 文件名
     * @return 成功消息
     */
    @DeleteMapping("/delete/{fileName}")
    public ResponseEntity<String> deleteFile(@PathVariable String fileName) throws IOException, NoSuchAlgorithmException, InvalidKeyException, io.minio.errors.MinioException {
        // 删除文件
        fileUploadService.deleteFile(fileName);
        return ResponseEntity.ok("File deleted successfully");
    }
}

启动


package com.example.demo;

import com.example.demo.service.FileUploadService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
publicclass DemoApplication implements CommandLineRunner {

    @Autowired
    private FileUploadService fileUploadService;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        // 确保启动时存储桶存在
        fileUploadService.createBucketIfNotExists();
    }
}

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表