《前端小技能》-- 前端如何实现断点续传,即大文件分片上传

记录在项目开发过程中遇到的小问题,积累开发经验,欢迎大家一起留言探讨

1、问题来源

在日常开发工作中,我们不免会遇到前端进行大文件上传的操作,如果碰到网络差或者网络中断的的情况,可想而知,一整个文件全部上传这种方式是不可取的,所以我们可以断点续传,即分片上传文件。

2、实现思路

将文件分成小文件,按照顺序依次上传,后端接收到数据以后,进行文件追加处理,即使断网,等到网络恢复以后,依然可以从上次未传递完毕的点继续进行传递。

3、前端具体实现

3.1 页面
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>Title</title>
	</head>
	<body>
		<div>
			<input type="file" name="选择文件" id="uploadFile">
			<input type="button" value="上传" id="start" onclick="upload(0)">
			<input type="button" value="继续" id="continue" onclick="continueUpload()">
			<input type="text" id="show">
		</div>
	</body>
</html>

3.2 逻辑处理
<script>
		// //确定分片大小
		var size = (1024 * 1024) * 10;  
		function upload(index) { 
			localStorage.setItem("index", 0)
			var file = document.getElementById("uploadFile").files[0]; //获取文件
			let arr = file.name.split('.'); //获取文件的名字和拓展名
			let fname = arr[0]
			let ext = arr[1]
			var star = index * size; //切片的起点
			if (star > file.size) {
				document.getElementById("show").value = '100%';
				return
			};
			//slice(起点,终点),Blob中的函数
			var bool = file.slice(star, (star + size) > file.size ? file.size : (star + size)); 
			var boolname = fname + "." + ext
			var boolfile = new File([bool], boolname) 
			var form = new FormData()
			form.append("index", index)
			form.append("size", size)
			form.append("name", file.name)
			form.append("file", boolfile)
			form.append("request_id", localStorage.getItem("request_id") || '')
			form.append("file", boolfile);
			// 为了演示方便,此处使用的是原生请求,可以根据需求自行修改
			var xmt = new XMLHttpRequest();
			// 此处是后端接口
			xmt.open("post", "http://172.16.13.89:8080/demo/upload", true) //发送请求
			xmt.send(form)
			xmt.onreadystatechange = function() {
				if (this.readyState == 4 && this.status == 200) {
					let result = JSON.parse(this.responseText)
					if (result.success) {
						// 记录后端回传的 文件标识ID,并回传给后端,便于后端进行文件追加
						localStorage.setItem("request_id", result.request_id)
						index += 1
						upload(index);
						// 存储在本地,记录此次传递的是第几片
						localStorage.setItem("index", index)
						// 计算上传百分比
						document.getElementById("show").value = ((star / file.size) * 100).toFixed(4) + '%'; //显示上传的进度
					} else {
						localStorage.setItem("index", index)
					}
				}else{
					console.log(this.readyState)
				}
			};
		}
			
		// 点击继续上传时,触发这个函数,从上次终端的片数继续进行传递
		function continueUpload() {
			upload(localStorage.getItem("index") || 0)
		}
	</script>

4、后端接口实现(Java)

此处是后端大佬挤时间给写的代码,目前没有注释,咱也不好意思说啥,大家将就看一下emmmm

package com.example.upload.controller;

import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.UUID;

@RestController
@CrossOrigin
public class UploadController {

    @RequestMapping("/upload")
    public DemoUpload upload(@RequestParam("file") MultipartFile file,
                             @RequestParam("index") Integer index,
                             @RequestParam(name = "request_id", required = false) String requestId) {
        DemoUpload demoUpload = new DemoUpload();
        String fileId = requestId;
        if (index == 0) {
            //生成一个文件ID
            fileId = UUID.randomUUID().toString();
            String fileDirPath = "C:\\Users\\ROG\\Downloads\\tmp\\" + fileId;
            File fileDir = new File(fileDirPath);
            fileDir.mkdir();
        }
        if (StringUtils.isEmpty(fileId)) {
            demoUpload.setSuccess(false);
            return demoUpload;
        }
        String fileName = file.getOriginalFilename();
        String tmpFilePath = "C:\\Users\\ROG\\Downloads\\tmp\\" + fileId + "\\" + fileName + ".tmp." + index;
        String realFilePath = "C:\\Users\\ROG\\Downloads\\tmp\\" + fileId + "\\" + fileName;
        File realDest = new File(realFilePath);
        File tmpDest = new File(tmpFilePath);
        try {
            file.transferTo(tmpDest);
            FileInputStream fileInputStream = new FileInputStream(tmpDest);
            FileOutputStream fileOutputStream = new FileOutputStream(realDest, true);

            byte[] buf = new byte[1024];
            int readLen = 0;
            while ((readLen = fileInputStream.read(buf)) != -1) {
                fileOutputStream.write(buf, 0, readLen);
            }

            fileOutputStream.close();
            fileInputStream.close();
            demoUpload.setRequest_id(fileId);
            demoUpload.setSuccess(true);
            return demoUpload;
        } catch (IOException e) {
            e.printStackTrace();
        }
        demoUpload.setSuccess(false);
        return demoUpload;
    }
}

感谢后端大佬奉献源代码,代码自提:
链接:https://pan.baidu.com/s/1iEQVLpi0QRqgkxzRtYg8ZA
提取码:kgpd

  • 5
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值