本文介绍解决大文件上传超时问题的分片断点上传方案。前端将文件切割为指定大小的块,通过异步方式多次上传;每次上传前查询已上传大小以支持断点续传,后端接收后追加至目标文件。
分片断点上传原理与接口需求
在项目开发中,处理大文件上传时经常遭遇链接超时,因此采用文件分片上传成为必要的解决方案。其核心原理在于:前端将文件划分为指定大小的“文件块”,并分多次进行传输。每次上传前,需先向后端查询已成功上传的文件部分大小,随后从指定位置截取一块文件进行上传;后端接收到文件块后,将其追加到指定的目标文件中。
本文内容适合具备一定后台开发基础,或拥有后台开发人员配合的前端工程师阅读。
实现此功能需要后台提供两个关键接口:一个是用于接收上传文件的接口,另一个是用于查询已上传文件大小的接口。

前端相关代码可参考仓库:https://github.com/li5454yong/FileUpload.git
以下是后台处理的核心代码部分。
后台核心代码实现
package com.fs.controller;import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.Iterator;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.csource.ClientGlobal;
import org.csource.common.MyException;
import org.csource.fastdfs.FileInfo;
import org.csource.fastdfs.StorageClient;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
import org.junit.Test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisShardInfo;
import com.alibaba.fastjson.JSON;
import com.fs.entity.UploadedFileInfo;
import com.fs.util.UploadUtil;
/**
* @author admin
*
* 2016年12月20日下午8:59:38
*/
@Controller
public class FastDFSUpLoadController {
@Resource
private UploadUtil uploadUtil;
@RequestMapping(value = "v1/uploadSize", method = RequestMethod.POST)
@ResponseBody
public Long uploadSize(HttpServletRequest request) {
String name = request.getParameter("name");
Long size = Long.parseLong(request.getParameter("size"));
try {
JedisShardInfo jedisShardInfo = new JedisShardInfo("192.168.0.12");
Jedis jedis = new Jedis(jedisShardInfo);
String str = jedis.get(name);
UploadedFileInfo uploadedFileInfo = null;
// 如果首次上传,已上传大小为 0
if (StringUtils.isEmpty(str)) {
uploadedFileInfo = new UploadedFileInfo();
jedis.set(name, JSON.toJSONString(uploadedFileInfo));
jedis.close();
return 0L;
}
uploadedFileInfo = JSON.parseObject(str, UploadedFileInfo.class);
jedis.close();
//已经全部上传
if(size <= uploadedFileInfo.getSize()){
System.out.println("上传完成");
}
//UploadUtil.getFileInfo(uploadedFileInfo.getFileId());
return uploadedFileInfo.getSize();
} catch (Exception e) {
e.printStackTrace();
return 0L;
}
}
@RequestMapping(value = "v1/uploadFile", method = RequestMethod.POST)
@ResponseBody
public int upload(HttpServletRequest request) {
// CommonsMultipartResolver resolver = new
// CommonsMultipartResolver(request.getSession().getServletContext());
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
Iterator<String> t = multiRequest.getFileNames();
MultipartFile fileDetail = multiRequest.getFile(t.next());
String name = request.getParameter("name");
JedisShardInfo jedisShardInfo = new JedisShardInfo("192.168.0.12");
Jedis jedis = new Jedis(jedisShardInfo);
UploadedFileInfo uploadedFileInfo = JSON.parseObject(jedis.get(name), UploadedFileInfo.class);
uploadedFileInfo.setFileName(name);
String path = "d:/testUpload";
File file = new File(path);
if (!file.exists() && !file.isDirectory()) {
boolean b = file.mkdirs();
}
RandomAccessFile randomFile = null;
try {
randomFile = new RandomAccessFile(path+"/"+name, "rw");
randomFile.seek(randomFile.length());
randomFile.write(fileDetail.getBytes());
uploadedFileInfo.setLocalPath(path+"/"+name);
uploadedFileInfo.setSize(randomFile.length());
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
randomFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// 将上传文件信息保存到redis
jedis.set(name, JSON.toJSONString(uploadedFileInfo));
jedis.close();
return 0;
}
}
以上介绍了JS异步文件分片断点上传的实现思路,希望对读者有所帮助。如有任何疑问,欢迎留言,小编会及时回复。同时也感谢大家对本站的支持!