webuploader大文件 分片 断点续传

来源:互联网 发布:cad制图机械软件 编辑:程序博客网 时间:2024/05/16 17:25
原文参考于http://blog.csdn.net/chenxiaoyu_csdn/article/details/70847203其中修复了原文章中由于网络中断等问题,断点续传时会再次上传已经上传文件的问题.修复了不需要分片的文件,上传过程中会出现异常的问题.

  1. webupload官网下载需要的Uploader.swf、webuploader.css、webuploader.js  文件
  2. jsp 页面
                         <div id="uploadfile">                <!--用来存放文件信息-->                <div id="thelist" class="uploader-list"></div>                <div class="form-group form-inline">                    <div id="picker">选择文件</div>                    <button id="ctlBtn" class="btn btn-default">开始上传</button>                </div>                <p style="color: red;margin-top: 80px;" id="fileError"></p>            </div>
3.js 代码
<script type="text/javascript">   //var projcetName =$("#project").val();  $(function(){var $list = $('#thelist'),        $btn = $('#ctlBtn'); var fileMd5;//自定义参数 文件名var fileName;    //监听分块上传过程中的三个时间点      WebUploader.Uploader.register({          "before-send-file":"beforeSendFile",  //整个文件上传前调用        "before-send":"beforeSend",  //每个分片上传前        "after-send-file":"afterSendFile",  //分片上传完毕    },{          //时间点1:所有分块进行上传之前调用此函数          beforeSendFile:function(file){          console.log("beforeSendFile");            var deferred = WebUploader.Deferred();              //1、计算文件的唯一标记,用于断点续传              (new WebUploader.Uploader()).md5File(file,0,10*1024*1024)                  .progress(function(percentage){                      $('#item1').find("p.state").text("正在读取文件信息...");                  })                  .then(function(val){                      fileMd5=val;                      $('#item1').find("p.state").text("成功获取文件信息...");                      //获取文件信息后进入下一步                      deferred.resolve();                  });              return deferred.promise();          },          //时间点2:如果有分块上传,则每个分块上传之前调用此函数          beforeSend:function(block){        console.log("beforeSend");            var deferred = WebUploader.Deferred();                            $.ajax({                  type:"POST",                  url:"checkOrMerge?action=checkChunk",                  data:{                      //文件唯一标记                      fileMd5:fileMd5,                      //当前分块下标                      chunk:block.chunk,                      //当前分块大小                      chunkSize:block.end-block.start                  },                  dataType:"json",                  success:function(response){                      if(response.ifExist){                     console.log("分片存在:"+block.chunk)                        //分块存在,跳过                          deferred.reject();                      }else{                    console.log("分片不存在:"+block.chunk)                        //分块不存在或不完整,重新发送该分块内容                          deferred.resolve();                      }                  }              });                            this.owner.options.formData.fileMd5 = fileMd5;            console.log("继续执行")            //deferred.resolve();              return deferred.promise();          },          //时间点3:所有分块上传成功后调用此函数          afterSendFile:function(file){        console.log("afterSendFile");        fileName=file.name; //为自定义参数文件名赋值            //如果分块上传成功,则通知后台合并分块              $.ajax({                  type:"POST",                  url:"checkOrMerge?action=mergeChunks",                  data:{                      fileMd5:fileMd5,                    fileName:fileName,                    ext:file.ext, //文件扩展名                    projectName: $("#project option:selected").text() //项目名称                },                  success:function(response){                var data= eval('(' + response + ')');                var filePath = data.path;                console.log(filePath);                //存储文件路径                var path=$("#filePath").val();            if(path!=""){            path=path+"|"+filePath;            }else{            path=filePath;            }            $("#filePath").val(path);                    //alert("上传成功");                      //var path = "uploads/"+fileMd5+".mp4";                      //$("#item1").attr("src",path);                  }              });          }      });      var uploader = WebUploader.create({      resize: false, // 不压缩image           swf: '/res/webuploader-0.1.5/uploader.swf', // swf文件路径      formData: { projectName: ""},      server: 'upload', // 文件接收服务端。      pick: '#picker', // 选择文件的按钮。可选      chunked: true, //是否要分片处理大文件上传      chunkSize:10*1024*1024, //分片上传,每片2M,默认是5M            //auto: false //选择文件后是否自动上传     chunkRetry : 2, //如果某个分片由于网络问题出错,允许自动重传次数      //runtimeOrder: 'html5,flash',      // 在上传当前文件时,准备好下一个文件   prepareNextFile:true,   duplicate : false,//是否重复上传(同时选择多个一样的文件),true可以重复上传         accept: {         title: '语音上传',         extensions: 'wav,zip,rar',         mimeTypes: 'audio/x-wav,.zip,.rar'       }    });  //当文件被加入队列之前触发    uploader.on('beforeFileQueued', function (file,data) {    //项目名称,在后台作为文件夹路径    var projcetName =$("#project").val();    if(projcetName==""){    $("#projectError").text("请先选择项目名称再上传文件!");    return false;    }else{    $("#projectError").text("");    }    //选定项目名称后 ,不可更改    $("#project").attr("disabled","disabled");    });    // 当有文件被添加进队列的时候    uploader.on( 'fileQueued', function( file ) {        $list.append( '<div id="' + file.id + '" class="item">' +            '<span class="info">' + file.name + '</span>' +            '<b class="state" style="width:90px;">等待上传...</b>' +        '</div>' );    });    //绑定uploadBeforeSend事件来给每个独立的文件添加参数    uploader.on( 'uploadBeforeSend', function( block, data ) {    //设置data参数    data.projectName= $("#project").find("option:selected").text();   // 将存在file对象中的md5数据携带发送过去。},2);    // 文件上传过程中创建进度条实时显示。    uploader.on( 'uploadProgress', function( file, percentage ) {        var $li = $( '#'+file.id ),            $percent = $li.find('.progress .progress-bar');        // 避免重复创建        if ( !$percent.length ) {            $percent = $('<div class="progress progress-striped active">' +              '<div class="progress-bar" role="progressbar" style="width: 0%">' +              '</div>' +            '</div>').appendTo( $li ).find('.progress-bar');        }//进度条以百分比的形式显示        $li.find('b.state').text('上传中'+Math.floor(percentage * 100) + '%' );        $percent.css( 'width', percentage * 100 + '%' );    });    // 文件上传成功    uploader.on( 'uploadSuccess', function( file,ret) {    //返回文件的保存路径    if(ret.flag==true){    console.log(ret.path);    var path=$("#filePath").val();    if(path!=""){    path=path+"|"+ret.path;    }else{    path=ret.path;    }    $("#filePath").val(path);    }        $( '#'+file.id ).find('b.state').text('上传成功');        $( '#'+file.id ).find('b.state').css("color","green");    });    // 文件上传失败,显示上传出错    uploader.on( 'uploadError', function( file,ret ) {    status=false;        $( '#'+file.id ).find('b.state').text('上传失败');    });    // 完成上传完    uploader.on( 'uploadComplete', function( file ) {        $( '#'+file.id ).find('.progress').fadeOut();    });    $btn.on('click', function () {            if ($(this).hasClass('disabled')) {                return false;            }            uploader.upload();            // if (state === 'ready') {            //     uploader.upload();            // } else if (state === 'paused') {            //     uploader.upload();            // } else if (state === 'uploading') {            //     uploader.stop();            // }        });});  </script>  

4. 后台文件上传及合并代码

// 上传文件@RequestMapping(value = "upload")public void uploadFile(HttpServletRequest request,HttpServletResponse response, String projectName)throws IOException {response.setCharacterEncoding("UTF-8");Map map = new HashMap<>();MultipartFile uploadFile = ((MultipartHttpServletRequest) request).getFile("file");String fileMd5 = request.getParameter("fileMd5");String chunk = request.getParameter("chunk");String path = audioPath;File file = new File(path + fileMd5);if (!file.exists()) {file.mkdirs();// 创建文件夹}// 保存文件File chunkFile = new File(path + fileMd5 + "/" + chunk);if (!chunkFile.exists()) {chunkFile.createNewFile();}uploadFile.transferTo(chunkFile);}// 合并或验证分片文件是否需要上传@RequestMapping(value = "checkOrMerge")public void checkOrMerge(HttpServletRequest request,HttpServletResponse response) throws IOException {response.setCharacterEncoding("UTF-8");String savePath = audioPath;String action = request.getParameter("action");if (action.equals("mergeChunks")) {// 合并文件// 需要合并的文件的目录标记// 文件MD5String fileMd5 = request.getParameter("fileMd5");// 文件名称String fileName = request.getParameter("fileName");// 文件扩展名String suffixName = request.getParameter("ext");// 项目名称String projectName = request.getParameter("projectName");System.out.println("fileMd5  :" + fileMd5);System.out.println("fileName  :" + fileName);System.out.println("projectName  :" + projectName);// 读取目录里的所有文件File f = new File(savePath + fileMd5);File[] fileArray = f.listFiles(new FileFilter() {// 排除目录只要文件@Overridepublic boolean accept(File pathname) {if (pathname.isDirectory()) {return false;}return true;}});System.out.println(" fileArray " + fileArray);// 转成集合,便于排序List<File> fileList = new ArrayList<File>(Arrays.asList(fileArray));// 需要合并的文件才进行排序,即分片的大小大于1if (fileList != null && fileList.size() > 1) {Collections.sort(fileList, new Comparator<File>() {@Overridepublic int compare(File o1, File o2) {// TODO Auto-generated method stubif (Integer.parseInt(o1.getName()) < Integer.parseInt(o2.getName())) {return -1;}return 1;}});}// 合并的文件夹File mergeFile = new File(savePath + projectName);if (!mergeFile.exists()) {mergeFile.mkdirs();}// UUID.randomUUID().toString()-->随机名File outputFile = new File(savePath + projectName + "/" + fileName);// 创建文件outputFile.createNewFile();// 输出流FileChannel outChnnel = new FileOutputStream(outputFile).getChannel();// 合并FileChannel inChannel;for (File file : fileList) {inChannel = new FileInputStream(file).getChannel();inChannel.transferTo(0, inChannel.size(), outChnnel);inChannel.close();// 删除分片file.delete();}outChnnel.close();// 清除文件夹File tempFile = new File(savePath + fileMd5);if (tempFile.isDirectory() && tempFile.exists()) {tempFile.delete();}System.out.println("合并成功");Map<String, String> map = new HashMap<>();// 文件路径map.put("path", projectName + "/" + fileName);response.getWriter().print(JSON.toJSON(map));} else if (action.equals("checkChunk")) {// 检查当前分块是否上传成功String fileMd5 = request.getParameter("fileMd5");String chunk = request.getParameter("chunk");String chunkSize = request.getParameter("chunkSize");File checkFile = new File(savePath + fileMd5 + "/" + chunk);response.setContentType("text/html;charset=utf-8");// 检查文件是否存在,且大小是否一致if (checkFile.exists()&& checkFile.length() == Integer.parseInt(chunkSize)) {// 上传过response.getWriter().write("{\"ifExist\":1}");} else {// 没有上传过response.getWriter().write("{\"ifExist\":0}");}}}