Java+Vue 断点续传功能实现

实现断点续传功能通常涉及前后端的协同工作。前端负责文件的分片上传和状态管理,后端负责接收文件分片并进行合并。下面是一个简单的示例,展示如何使用Java和Vue来实现断点续传功能。

前端(Vue)


1. 安装依赖


首先,确保你的Vue项目中安装了axios用于HTTP请求:

npm install axios

2. 创建文件上传组件


创建一个Vue组件来处理文件上传和断点续传逻辑:

<template>
  <div>
    <input type="file" @change="handleFileChange" />
    <button @click="uploadFile">Upload</button>
    <button @click="pauseUpload">Pause</button>
    <button @click="resumeUpload">Resume</button>
    <div v-if="progress > 0">Progress: {{ progress }}%</div>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      file: null,
      chunks: [],
      chunkSize: 1024 * 1024, // 1MB
      currentChunk: 0,
      progress: 0,
      paused: false,
    };
  },
  methods: {
    handleFileChange(event) {
      this.file = event.target.files[0];
      this.chunks = this.createChunks(this.file);
      this.currentChunk = 0;
      this.progress = 0;
      this.paused = false;
    },
    createChunks(file) {
      const chunks = [];
      const totalChunks = Math.ceil(file.size / this.chunkSize);

      for (let i = 0; i < totalChunks; i++) {
        const start = i * this.chunkSize;
        const end = Math.min(file.size, start + this.chunkSize);
        chunks.push(file.slice(start, end));
      }

      return chunks;
    },
    async uploadFile() {
      if (!this.file) {
        alert('Please select a file first.');
        return;
      }

      for (; this.currentChunk < this.chunks.length; this.currentChunk++) {
        if (this.paused) {
          break;
        }

        const formData = new FormData();
        formData.append('file', this.chunks[this.currentChunk]);
        formData.append('chunkNumber', this.currentChunk);
        formData.append('totalChunks', this.chunks.length);
        formData.append('fileName', this.file.name);

        try {
          await axios.post('/api/upload', formData, {
            headers: {
              'Content-Type': 'multipart/form-data',
            },
            onUploadProgress: (progressEvent) => {
              const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
              this.progress = ((this.currentChunk * 100) / this.chunks.length) + (percentCompleted / this.chunks.length);
            },
          });
        } catch (error) {
          console.error('Upload failed:', error);
          break;
        }
      }

      if (this.currentChunk === this.chunks.length) {
        alert('File uploaded successfully!');
      }
    },
    pauseUpload() {
      this.paused = true;
    },
    resumeUpload() {
      this.paused = false;
      this.uploadFile();
    },
  },
};
</script>

后端(Java)


1. 添加依赖


确保你的Spring Boot项目中添加了以下依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.11.0</version>
    </dependency>
</dependencies>

2. 创建文件上传控制器


创建一个控制器来处理文件分片上传和合并:

import org.apache.commons.io.FileUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;

@RestController
@RequestMapping("/api")
public class FileUploadController {

    private static final String UPLOAD_DIR = "uploads/";

    @PostMapping("/upload")
    public String uploadFile(@RequestParam("file") MultipartFile file,
                             @RequestParam("chunkNumber") int chunkNumber,
                             @RequestParam("totalChunks") int totalChunks,
                             @RequestParam("fileName") String fileName,
                             HttpServletRequest request) throws IOException {
        String tempDir = UPLOAD_DIR + UUID.randomUUID().toString() + "/";
        Path tempPath = Paths.get(tempDir);
        if (!Files.exists(tempPath)) {
            Files.createDirectories(tempPath);
        }

        String chunkFileName = fileName + ".part" + chunkNumber;
        File chunkFile = new File(tempDir + chunkFileName);
        file.transferTo(chunkFile);

        if (chunkNumber == totalChunks - 1) {
            mergeChunks(tempDir, fileName, totalChunks);
            FileUtils.deleteDirectory(new File(tempDir));
        }

        return "Chunk uploaded successfully";
    }

    private void mergeChunks(String tempDir, String fileName, int totalChunks) throws IOException {
        File outputFile = new File(UPLOAD_DIR + fileName);
        for (int i = 0; i < totalChunks; i++) {
            File chunkFile = new File(tempDir + fileName + ".part" + i);
            FileUtils.copyFile(chunkFile, outputFile, true);
            chunkFile.delete();
        }
    }
}

3. 配置文件


确保在application.properties中配置文件上传的大小限制:

spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB

4. 运行项目


启动Spring Boot应用和Vue前端应用,然后尝试上传一个大文件,测试断点续传功能。


总结


通过上述步骤,你可以在Java后端和Vue前端之间实现一个简单的断点续传功能。前端负责文件的分片上传和状态管理,后端负责接收文件分片并进行合并。希望这个示例对你有所帮助!

以下是一个简单的 Spring Boot + Vue 的文件上传断点续传的示例代码,供参考: 前端代码: ```vue <template> <div> <!-- 选择文件按钮 --> <input type="file" ref="fileInput" @change="selectFile"> <!-- 上传按钮 --> <button @click="upload">上传</button> <!-- 进度条 --> <div> <div :style="{ width: progress + '%' }"></div> </div> </div> </template> <script> export default { data() { return { file: null, // 选择的文件 progress: 0, // 上传进度 uploadedChunks: [], // 已上传的分块 chunkSize: 1024 * 1024, // 分块大小 }; }, methods: { // 选择文件 selectFile() { this.file = this.$refs.fileInput.files[0]; }, // 上传文件 async upload() { const totalChunks = Math.ceil(this.file.size / this.chunkSize); for (let i = 0; i < totalChunks; i++) { const start = i * this.chunkSize; const end = Math.min(start + this.chunkSize, this.file.size); const chunk = this.file.slice(start, end); // 如果该分块已上传,则跳过 if (this.uploadedChunks.includes(i)) { continue; } // 构造 FormData 对象 const formData = new FormData(); formData.append('file', chunk); formData.append('chunk', i); formData.append('totalChunks', totalChunks); // 发送分块上传请求 const res = await this.$http.post('/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' }, onUploadProgress: (progressEvent) => { // 更新上传进度 this.progress = Math.round((start + progressEvent.loaded) / this.file.size * 100); }, }); // 如果上传成功,则记录已上传的分块 if (res.data) { this.uploadedChunks.push(i); } } // 如果所有分块都上传成功,则发送合并请求 if (this.uploadedChunks.length === totalChunks) { await this.$http.post('/merge', { filename: this.file.name }); } }, }, }; </script> ``` 后端代码: ```java @RestController public class FileController { private final String uploadDir = "/tmp/upload/"; // 上传文件存储路径 private final String mergeDir = "/tmp/merge/"; // 合并文件存储路径 private final int chunkSize = 1024 * 1024; // 分块大小 // 分块上传接口 @PostMapping("/upload") public boolean upload(@RequestParam("file") MultipartFile file, @RequestParam("chunk") int chunk, @RequestParam("totalChunks") int totalChunks) throws IOException { // 构造上传文件的路径文件名 String filename = file.getOriginalFilename(); String filepath = uploadDir + filename + "_" + chunk; // 如果该分块已上传,则直接返回上传成功 if (new File(filepath).exists()) { return true; } // 将分块保存到临时文件中 file.transferTo(new File(filepath)); // 如果所有分块都已上传,则返回上传成功 if (new File(uploadDir).list().length == totalChunks) { return true; } return false; } // 合并文件接口 @PostMapping("/merge") public void merge(@RequestParam("filename") String filename) throws IOException { // 构造合并后的文件路径文件名 String filepath = mergeDir + filename; File mergedFile = new File(filepath); // 如果合并后的文件已存在,则删除原文件 if (mergedFile.exists()) { mergedFile.delete(); } // 将所有分块合并成一个文件 for (int i = 0; i < Integer.MAX_VALUE; i++) { String chunkPath = uploadDir + filename + "_" + i; File chunkFile = new File(chunkPath); // 如果该分块不存在,则说明所有分块都已合并完成 if (!chunkFile.exists()) { break; } // 将该分块添加到合并文件中 Files.write(mergedFile.toPath(), Files.readAllBytes(chunkFile.toPath()), StandardOpenOption.APPEND); } // 删除上传文件分块文件 FileUtils.deleteDirectory(new File(uploadDir)); FileUtils.deleteDirectory(new File(mergeDir)); } } ``` 以上代码实现了一个简单的文件上传断点续传的示例,其中前端使用 Vue 实现了文件选择上传操作,后端使用 Spring Boot 实现了分块上传合并操作。需要注意的是,这只是一个简单的示例,实际应用中需要根据具体的需求问题来选择不同的技术组件,并合理地设置参数配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Favor_Yang

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

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

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

打赏作者

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

抵扣说明:

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

余额充值