超大文件上传解决方案:分片断点上传(一)

思路:
1.前端进行文件分割,然后上传文件片段;
2.后端进行文件接收,和合并操作。

前端代码:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <link th:replace="fragments/layout2::header">
        <!--引入JQ-->
        <script th:src="@{/static/Inspinia/js/jquery-3.3.1/jquery.min.js}"></script>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <form>
            <input type="file" id="files">
            <input type="button" value="上传" onclick="uploadFile()" id = "uploadButton">
        </form>
        <div th:replace="fragments/layout2::js"></div>
<script src="../../static/md5/md5.js"></script>
<script>
    // i :分片文件的标号
    var i = -1;
    //succeed :已上传成功的分片数量
    var succeed = 0;
    //action:upload方法要执行的操作(false时去检验分片是否上传过(默认); true时进行上传文件操作) 
    var action = false;
    //验证大文件整体是否上传过的方法,参数为单个文件对象
    function isUpload(file) {
        //构造一个表单
        var form = new FormData();
        //整体文件的md5
        var fileWholeMd5 = hex_md5(file);
        form.append("fileMd5",fileWholeMd5);
        form.append("originalFileName",file.name);
        form.append("fileSize",file.size);

        //发ajax到后台验证整体文件是否上传过
        $.ajax({
            url: "/upload/fileRecordWhole/isUpload",
            type: "POST",
            data: form,
            async: true,        //异步
            processData: false,  //很重要,告诉jquery不要对form进行处理
            contentType: false,  //很重要,指定为false才能形成正确的Content-Type
            success: function(result){
                console.log(result);
                if(result != null){
                    var data = result.data;
                    if(data != undefined && data.status == 0){
                        //如果返回数据的状态为0(未完成),则上传各个分片文件
                        upload(file,data.id,fileWholeMd5,data.fileType,data.filePath,data.fileServerSn);
                    }else if(data != undefined && data.status == 1){
                        //如果返回数据的状态为1(已完成且存在),则提示上传成功;是否在此时创建任务需要后续确认
                        alert("上传成功");
                    }
                }
            },error: function(XMLHttpRequest, textStatus, errorThrown) {
                alert("服务器出错!");
            }
        })
    }

    /**
     * 分片并递归上传分片文件的方法
     * @param file  大文件对象
     * @param fileWholeId  整体文件记录 的id
     * @param fileWholeMd5  整体文件的Md5
     * @param fileType 文件类型(后缀)
     * @param 整体文件的存储路径
     * @param fileServerSn 整体文件存储的文件服务器序列号
     */
    function upload(file, fileWholeId, fileWholeMd5,fileType,filePath,fileServerSn) {
        var size = file.size;        //总大小
        var shardSize = 30 * 1024 * 1024,    //以5MB为一个分片
            shardCount = Math.ceil(size / shardSize);  //总片数(取整)
        if(i < shardCount){
            //如果当前要执行校验分片是否存在的操作
            if(!action){
                i ++;
            }
        }else{
           i = -1;
        }
        //计算每一片的起始位置和结束位置
        var start = i * shardSize,
            end = Math.min(size , start + shardSize);
        //创建一个表单对象
        var form = new FormData();
        //分片文件名:整体文件的MD5 + (i+1)
        var fileName =  fileWholeMd5 + (i+1);
        form.append("fileName",fileName);
        form.append("fileWholeId",fileWholeId);
        form.append("fileServerSn",fileServerSn);
        //获取分片文件的存储路径
        var wholeFileName = fileWholeMd5 + "." + fileType;
        var shardFilePath = filePath.replace(wholeFileName,fileName);
        form.append("filePath",shardFilePath);
        //按大小切割文件段  
        var data = file.slice(start, end);
        //这里使用文件阅读器,等待加载;可以防止递归调用被系统判定为死循环报错
        var r = new FileReader();
        r.readAsBinaryString(data);
        $(r).on('load',function (e) {
            var md5 = hex_md5(data);
            form.append("fileMd5",md5);
            if(!action){
                //要执行的操作:校验分片是否上传
                form.append("action","check");
            }else{
                //要执行的操作:上传分片文件
                form.append("action","upload");
                //分片文件对象
                form.append("file",data);
            }
            $.ajax({
                url: "/upload/fileRecordTem/upload",
                type: "POST",
                data: form,
                async: false,        //异步
                processData: false,  //很重要,告诉jquery不要对form进行处理
                contentType: false,  //很重要,指定为false才能形成正确的Content-Type
                success: function(result){
                    // console.log(result);
                    var data = result.data;
                    // console.log(data);
                    if(data != undefined){
                        console.log("进来了");
                        if(data){
                            //分片文件已存在或上传成功,则进行下一片文件的操作
                            action = false;
                            succeed ++;
                            if(succeed <  shardCount){
                                //递归调用
                                // console.log("递归调用")
                                upload(file,fileWholeId,fileWholeMd5,fileType,filePath,fileServerSn);
                            }else{
                                //进行文件合并
                                // console.log("合并文件")
                                mergeFile(fileWholeId,filePath,fileServerSn,shardCount);
                            }
                        }else{
                            //分片文件不存在或上传失败,则重新上传一次
                            action = true;
                            // console.log("重新上传")
                            //递归调用
                            upload(file,fileWholeId,fileWholeMd5,fileType,filePath,fileServerSn);
                        }
                    }else{
                        alert(result.msg);
                    }
                },error: function(XMLHttpRequest, textStatus, errorThrown) {
                    alert("抱歉,请重试");
                }
            });
        });
    }

    /**
     * 所有分片文件上传成功后请求合并文件的方法
     * @param fileWholeId 整体文件记录的id
     * @param filePath 整体文件的存储路径
     * @param fileServerSn 整体文件存储的文件服务器编号
     * @param total 总分片数
     */
    function mergeFile(fileWholeId , filePath , fileServerSn , total) {
        var form = new FormData();
        form.append("fileWholeId",fileWholeId);
        form.append("filePath",filePath);
        form.append("fileServerSn",fileServerSn);
        form.append("total",total);
        $.ajax({
            url: "/upload/fileRecordTem/mergeFile",
            type: "POST",
            data: form,
            async: false,        //异步
            processData: false,  //很重要,告诉jquery不要对form进行处理
            contentType: false,  //很重要,指定为false才能形成正确的Content-Type
            success: function(result){
                console.log(result);
                //合并成功
                var data = result.data;
                if(data != undefined && data){
                    alert("上传成功");
                }else{
                    alert(result.msg);
                }
            },error: function(XMLHttpRequest, textStatus, errorThrown) {
                alert("抱歉,请重试");
            }
        });
    }
    function uploadFile() {
        document.getElementById("uploadButton").disabled = "disabled";
        //获取要上传的文件对象
        var files = document.getElementById("files").files;
        //初始化数值
        i = -1;
        succeed = 0 ;
        action = false;
        isUpload(files[0]);
    }     
</script>
    </body>
</html>

后端代码:

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值