大文件分片上传demo

主要思路就是将大文件分成多个小文件上传,服务器端将上传上来的小文件先保存成各个临时文件,当所有分片的文件上传完毕后,调用接口将所有的临时文件合并成一个文件

我这里只是一个小小的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>

  

posted on 2021-02-20 15:12  james-roger  阅读(283)  评论(0编辑  收藏  举报