当前位置:   article > 正文

Spring Boot 实现大文件分片上传_springboot大文件分片上传

springboot大文件分片上传

Spring Boot 实现大文件分片上传

在 Maven 中添加依赖项

需要在项目中添加以下依赖项:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
 
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

创建控制器类

创建一个控制器类,用于处理上传请求。在该类中,需要实现以下操作:

  • 接收上传的文件
  • 将文件分成多个部分
  • 将每个部分保存到磁盘上的临时文件中
  • 当所有部分都上传完成后,将它们合并成一个完整的文件

下面是一个示例代码:

@RestController
public class FileUploadController {
 
    private static final String UPLOAD_DIRECTORY = "/tmp/uploads";
 
    @PostMapping("/upload")
    public ResponseEntity<String> upload(@RequestParam("file") MultipartFile file,
                                          @RequestParam("fileName") String fileName,
                                          @RequestParam("chunkNumber") int chunkNumber,
                                          @RequestParam("totalChunks") int totalChunks) throws IOException {
        
        
        File uploadDirectory = new File(UPLOAD_DIRECTORY);
        if (!uploadDirectory.exists()) {
            uploadDirectory.mkdirs();
        }
 
        File destFile = new File(UPLOAD_DIRECTORY + File.separator + fileName + ".part" + chunkNumber);
        FileUtils.copyInputStreamToFile(file.getInputStream(), destFile);
 
        if (chunkNumber == totalChunks) { // 如果所有部分都已上传,则将它们组合成一个完整的文件
            String targetFilePath = UPLOAD_DIRECTORY + File.separator + fileName;
            for (int i = 1; i <= totalChunks; i++) {
                File partFile = new File(UPLOAD_DIRECTORY + File.separator + fileName + ".part" + i);
                try (FileOutputStream fos = new FileOutputStream(targetFilePath, true)) {
                    FileUtils.copyFile(partFile, fos);
                    partFile.delete();
                }
            }
        }
 
        return ResponseEntity.ok("Upload successful");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

前端实现

在前端,需要使用 JavaScript 将文件分割成多个部分,并向后端发送分块数据。以下是一个示例代码:

javascript复制代码function uploadFile(file) {
    const chunkSize = 1024 * 1024; // 每个部分的大小(1MB)
    const totalChunks = Math.ceil(file.size / chunkSize); // 总部分数
 
    let currentChunk = 1;
    let startByte = 0;
 
    while (startByte < file.size) { // 分割文件为多个部分,并上传每个部分
        const endByte = Math.min(startByte + chunkSize, file.size);
        const chunk = file.slice(startByte, endByte);
 
        const formData = new FormData();
        formData.append('file', chunk);
        formData.append('fileName', file.name);
        formData.append('chunkNumber', currentChunk);
        formData.append('totalChunks', totalChunks);
 
        axios.post('/upload', formData);
 
        startByte += chunkSize;
        currentChunk++;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

通过以上步骤,就可以使用 Spring Boot 实现大文件分片上传了。

第二种:

package cn.js.Controller;

import org.apache.commons.io.FileUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

 /**
   *@description:
  * 1.前端实现:
  *
  * 使用JavaScript实现前端上传代码。从前端发送请求时,将文件切成若干个小块(每个块大小在1MB到10MB之间),
  * 并发送给后端。当所有的块都上传完成后,再向后端发送“合并”请求。
  *
  * 2.后端实现:
  *
  * 在后端控制器中,首先接收上传的文件,并按照指定的大小进行分块。然后将每一个块存储为临时文件。
  * 当所有块都上传完成后,再将这些临时文件合并成一个完整的文件。
  *
  * 具体实现方法如下:
   **/


  /**
    *@description:
   * 在上述代码中,我们定义了一个接口“/file/upload”,用于接收上传的块。在接收到一个块时,
   * 首先判断是否为第一个块,如果是,则新建一个空文件。然后将当前块写入文件。
   * 如果是最后一个块,则调用 mergeFile() 方法将所有块合并成一个完整的文件。
   *
   * mergeFile() 方法中,我们首先获取所有以 guid 为前缀的临时文件,
   * 并按照文件名排序。然后从第一个文件开始,将每个文件的内容写入目标文件中,
   * 并删除临时文件。最后输出合并完成的消息。
   *
   * 这样,就可以使用Spring Boot实现大文件分片上传了。需要注意的是,
   * 为了防止文件名冲突,可以为每个上传任务生成一个唯一的 guid,并使用该 guid
   * 作为文件名的前缀。此外,如果上传任务长时间未完成,还需要定期清理临时文件。
    **/
@RestController
@RequestMapping("/file")
public class FileUploadController {

    private final String UPLOAD_PATH = "D:/upload/";

    @PostMapping("/upload")
    public String upload(HttpServletRequest request) throws Exception {
        String fileName = request.getHeader("fileName");
        String guid = request.getHeader("guid");
        int chunkIndex = Integer.parseInt(request.getHeader("chunkIndex"));//分片文件的索引从0开始
        int totalChunks = Integer.parseInt(request.getHeader("totalChunks"));//分片文件的索引总数

        // 获取上传的文件
        File file = new File(UPLOAD_PATH + fileName);

        // 如果是第一个块,则新建一个文件
        if (chunkIndex == 0) {
            file.createNewFile();
        }

        // 将当前块写入文件
        FileOutputStream fos = new FileOutputStream(file, true);
        InputStream is = request.getInputStream();
        byte[] buf = new byte[1024];
        int len;
        while ((len = is.read(buf)) != -1) {
            fos.write(buf, 0, len);
        }

        // 如果是最后一个块,则合并文件
        if (chunkIndex == totalChunks - 1) {
            mergeFile(file, guid);
        }

        

        return "success";
    }

    private void mergeFile(File file, String guid) throws Exception {
        String fileName = file.getName();
        String ext = fileName.substring(fileName.lastIndexOf("."));
        File newFile = new File(UPLOAD_PATH + guid + "." + ext);

        List<File> files = Arrays.asList(file.getParentFile().listFiles((dir, name) -> name.startsWith(guid)));
        Collections.sort(files, Comparator.comparing(File::getName));

        FileOutputStream fos = new FileOutputStream(newFile);
        byte[] buf = new byte[1024];
        int len;
        for (File f : files) {
            FileInputStream fis = new FileInputStream(f);
            while ((len = fis.read(buf)) != -1) {
                fos.write(buf, 0, len);
            }
            fis.close();
            f.delete();
        }
        fos.close();

        System.out.println("文件合并完成:" + newFile.getAbsolutePath());
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/528051
推荐阅读
相关标签
  

闽ICP备14008679号