计算机系统应用教程网站

网站首页 > 技术文章 正文

Spring Boot实现大文件的分片上传功能?

btikc 2024-09-18 08:35:12 技术文章 25 ℃ 0 评论

大文件上传一直是文件上传开发过程中的一个重要的功能点。它是指能够在网络的环境下,通过HTTP文件上传功能,将一个大型的文件传送到服务器上的功能。在传统的文件上传开发中可能会因为网络带宽、服务器性能、客户端限制等诸多因素的影响导致上传大文件的时候出现超时、上传失败等问题。那么为了解决这个问题,对于大文件的上传通常采用的就是将大文件进行切分,切分成多个小文件进行上传,将这些小文件分片进行上传之后,然后将上传之后的小文件合并成一个大文件。

下面我们就来看看Spring Boot如何实现大文件的分片上传操作。

前端设计实现

创建一个上传文件的表单页面,包括文件选择按钮和上传按钮。然后通过JavaScript来监听文件的选择事件,然后将选择的文件实现分片之后,提交到后端上传的接口中。代码如下所示。

<!DOCTYPE html>
<html>
<head>
  <title>大文件分片上传</title>
</head>
<body>
<input type="file" id="fileInput" multiple>
<button onclick="uploadFile()">上传文件</button>
<progress id="progressBar" value="0" max="100"></progress>
</body>
<script>
  function uploadFile() {
    var files = document.getElementById('fileInput').files;
    var totalChunks = Math.ceil(files[0].size / (10 * 1024 * 1024)); // 假设每个分片大小为 10MB
    var uploadedChunks = 0;

    function sendChunk(chunkIndex) {
      var chunkSize = 10 * 1024 * 1024;
      var start = chunkIndex * chunkSize;
      var end = Math.min(start + chunkSize, files[0].size);
      var chunk = files[0].slice(start, end);

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

      var xhr = new XMLHttpRequest();
      xhr.open('POST', '/upload', true);
      xhr.onload = function() {
        uploadedChunks++;
        var progress = uploadedChunks / totalChunks * 100;
        document.getElementById('progressBar').value = progress;
        if (uploadedChunks < totalChunks) {
          sendChunk(uploadedChunks);
        } else {
          mergeChunks();
        }
      };
      xhr.send(formData);
    }

    function mergeChunks() {
      var xhr = new XMLHttpRequest();
      xhr.open('POST', '/merge', true);
      xhr.send();
    }

    sendChunk(0);
  }
</script>
</html>

在上述操作中完成了如下的四步操作,来支持文件分片上传。

  • 第一步、创建一个HTML页面,包括文件选择表单和上传按钮。
  • 第二步、使用JavaScript监听文件选择事件,并使用File.slice()方法将文件分割成多个分片。
  • 第三步、使用AJAX请求将每个分片发送到后端的分片上传接口。
  • 第四步、在所有分片上传完成后,发送请求告知后端开始合并分片。

后端设计实现

文件上传服务类实现,需要完成分片文件的接收,并且将接收到的分片文件存储到一个临时的目录中。接下来就是在上传完成之后,将分片数据进行合并的操作。如下所示。

@Service
public class FileService {

    private final String UPLOAD_DIR = "uploads/";
    private final String TEMP_DIR = "temp/";

    public void saveFileChunk(MultipartFile file, int totalChunks, int chunkIndex) throws IOException {
        byte[] bytes = file.getBytes();
        String fileName = file.getOriginalFilename();

        String tempFilePath = TEMP_DIR + fileName + "-" + chunkIndex;
        try (FileOutputStream fos = new FileOutputStream(tempFilePath)) {
            fos.write(bytes);
        }
    }

    public void mergeFileChunks() throws IOException {
        File tempDir = new File(TEMP_DIR);
        File[] files = tempDir.listFiles();
        Arrays.sort(files, Comparator.comparing(File::getName));

        String mergedFilePath = UPLOAD_DIR + "merged-file";
        try (FileOutputStream fos = new FileOutputStream(mergedFilePath)) {
            for (File file : files) {
                byte[] bytes = Files.readAllBytes(Paths.get(file.getAbsolutePath()));
                fos.write(bytes);
                file.delete(); // 删除临时文件
            }
        }
    }
}

控制层代码实现,实现一个接收文件分片的POST接口,接收文件分片,并将分片保存到临时目录中。实现一个合并文件分片的POST接口,接收所有分片上传完成的请求,读取临时目录中的分片文件,并将它们合并成完整的文件。将完整的文件保存到指定目录,返回上传成功的响应。

@RestController
public class FileUploadController {

    private final String UPLOAD_DIR = "uploads/";
    private final String TEMP_DIR = "temp/";

    @Autowired
    private FileService fileService;

    @PostMapping("/upload")
    public String uploadFileChunk(@RequestParam("file") MultipartFile file,
                                  @RequestParam("totalChunks") int totalChunks,
                                  @RequestParam("chunkIndex") int chunkIndex) throws IOException {
        fileService.saveFileChunk(file, totalChunks, chunkIndex);
        return "Chunk uploaded successfully.";
    }

    @PostMapping("/merge")
    public String mergeFileChunks() throws IOException {
        fileService.mergeFileChunks();
        return "File uploaded successfully.";
    }
}

注意

在实际生产场景中,需要对可能出现的文件处理异常进行处理,并且添加文件上传接口安全策略,确保不会被黑客利用上传脚本攻击服务器。在分片上传的过程中,也要对各个分片的大小做验证,如果分片不合理的话,需要进行重新分片,另外就是上传分片的顺序问题,导致最终是否能够被合并成一个完整的文件,还有考虑到断点续传、并发上传,如果后端使用了对象存储,还要考虑到对象存储系统如何对接等等问题。

Tags:

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

欢迎 发表评论:

最近发表
标签列表