主要思路就是将大文件分成多个小文件上传,服务器端将上传上来的小文件先保存成各个临时文件,当所有分片的文件上传完毕后,调用接口将所有的临时文件合并成一个文件
我这里只是一个小小的demo,如果想做好,首先是前端根据文件获取到一个md5值,然后在上传文件的时候根据这个md5值检测之前是否有上传文件,如果没有则从开始位置上传(上传成功后要把相应的数据保存到数据库表里面),如果之前有上传则查看上传到了什么位置,然会给前端,前端好接着从之前的位置传数据
后台代码
package cn.com.modules.file; import lombok.Data; import org.springframework.web.multipart.MultipartFile; import java.io.Serializable; /** * @Author: luojie * @Date: 2021/2/20 11:09 */ @Data public class Chunk implements Serializable { private Long id; /** * 当前文件块,从1开始 */ private Integer chunkNumber; /** * 分块大小 */ private Long chunkSize; /** * 当前分块大小 */ private Long currentChunkSize; /** * 总大小 */ private Long totalSize; /** * 文件标识 */ private String identifier; /** * 文件名 */ private String filename; /** * 相对路径 */ private String relativePath; /** * 总块数 */ private Integer totalChunks; /** * 文件类型 */ private String type; private MultipartFile file; }
package cn.com.esrichina.sip.modules.file; import cn.com.esrichina.sip.commons.exception.RaccoonException; import io.swagger.annotations.Api; import org.apache.commons.io.FileUtils; import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; /** * @Author: luojie * @Date: 2021/2/20 11:10 */ @RestController @Api(value = "/upload", description = "文件上传,支持文件分片上传") @RequestMapping("/upload") @CrossOrigin public class UploadController { private static final String filePath = "C:/resources/sip"; private static final String filePathTemp = "C:/resources/sip/temp"; /** * 分片上传 */ @RequestMapping(method = RequestMethod.POST) @ResponseBody public Boolean upload(HttpServletRequest request, Chunk chunk) throws IOException { boolean isMultipart = ServletFileUpload.isMultipartContent(request); if (isMultipart) { MultipartFile file = chunk.getFile(); if (file == null) { throw new RaccoonException(400, "参数验证失败!"); } Integer chunkNumber = chunk.getChunkNumber(); if (chunkNumber == null) { chunkNumber = 0; } java.io.File outFile = new java.io.File(filePathTemp + java.io.File.separator + chunk.getIdentifier(), chunkNumber + ".part"); InputStream inputStream = file.getInputStream(); FileUtils.copyInputStreamToFile(inputStream, outFile); } return true; } /** * 合并所有分片 * guid 就是 identifier(文件标识) */ @GetMapping("/merge") @ResponseBody public Boolean mergeFile(String filename, String guid) throws Exception { java.io.File file = new java.io.File(filePathTemp + java.io.File.separator + guid); if (file.isDirectory()) { java.io.File[] files = file.listFiles(); if (files != null && files.length > 0) { java.io.File partFile = new java.io.File(filePath + java.io.File.separator + filename); for (int i = 1; i <= files.length; i++) { java.io.File s = new java.io.File(filePathTemp + java.io.File.separator + guid, i + ".part"); FileOutputStream destTempfos = new FileOutputStream(partFile, true); FileUtils.copyFile(s, destTempfos); destTempfos.close(); } FileUtils.deleteDirectory(file); } } return true; } }
前端测试代码
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="Generator" content="EditPlus®"> <meta name="Author" content=""> <meta name="Keywords" content=""> <meta name="Description" content=""> <title>Document</title> </head> <body> <form id="f" method="post" action="#" enctype="multipart/form-data"> 选择图片:<input type="file" id="file6" name="file1"><br /> </form> <a href="#" class="btnFile6">提交</a> <script src="jquery-3.0.0.js"></script> <script> $(function(){ $(".btnFile6").click(function () { var upload = function (file, skip) { var formData = new FormData();//初始化一个FormData对象 var blockSize = 1024*1024;//每块的大小 var nextSize = Math.min((skip + 1) * blockSize, file.size);//读取到结束位置 var fileData = file.slice(skip * blockSize, nextSize);//截取 部分文件 块 formData.append("file", fileData);//将 部分文件 塞入FormData formData.append("fileName", file.name);//保存文件名字 formData.append("chunkSize", blockSize); formData.append("totalSize", file.size); formData.append("identifier", "AA"); formData.append("chunkNumber", (skip + 1)); $.ajax({ url: "http://127.0.0.1:10089/upload", type: "POST", data: formData, processData: false, // 告诉jQuery不要去处理发送的数据 contentType: false, // 告诉jQuery不要去设置Content-Type请求头 success: function (responseText) { $(".result").html("已经上传了" + (skip + 1) + "块文件"); if (file.size <= nextSize) {//如果上传完成,则跳出继续上传 //全部上传成功后执行下面的语句 console.log("--上传完成----"); //合并文档 $.ajax({ type: "GET", url: "http://127.0.0.1:10089/upload/merge?filename=开发文档.docx&guid=AA", dataType: "json", success:function (message) { }, error:function (message) { alert('系统异常'); } }); return; } upload(file, ++skip);//递归调用 } }); }; var file = $("#file6")[0].files[0]; upload(file, 0); }); }) </script> </body> </html>