webuploader大文件 分片 断点续传

原文参考于http://c7.gg/cds8e

其中修复了原文章中由于网络中断等问题,断点续传时会再次上传已经上传文件的问题.修复了不需要分片的文件,上传过程中会出现异常的问题.

 

 

 

  1. webupload官网下载需要的Uploader.swf、webuploader.css、webuploader.js  文件
  2. jsp 页面
 
  1. <div id="uploadfile">

  2. <!--用来存放文件信息-->

  3. <div id="thelist" class="uploader-list"></div>

  4. <div class="form-group form-inline">

  5. <div id="picker">选择文件</div>

  6. <button id="ctlBtn" class="btn btn-default">开始上传</button>

  7. </div>

  8. <p style="color: red;margin-top: 80px;" id="fileError"></p>

  9. </div>

3.js 代码

 
  1. <script type="text/javascript">

  2. //var projcetName =$("#project").val();

  3. $(function(){

  4. var $list = $('#thelist'),

  5. $btn = $('#ctlBtn');

  6.  
  7. var fileMd5;

  8. //自定义参数 文件名

  9. var fileName;

  10. //监听分块上传过程中的三个时间点

  11. WebUploader.Uploader.register({

  12. "before-send-file":"beforeSendFile", //整个文件上传前调用

  13. "before-send":"beforeSend", //每个分片上传前

  14. "after-send-file":"afterSendFile", //分片上传完毕

  15. },{

  16. //时间点1:所有分块进行上传之前调用此函数

  17. beforeSendFile:function(file){

  18. console.log("beforeSendFile");

  19. var deferred = WebUploader.Deferred();

  20. //1、计算文件的唯一标记,用于断点续传

  21. (new WebUploader.Uploader()).md5File(file,0,10*1024*1024)

  22. .progress(function(percentage){

  23. $('#item1').find("p.state").text("正在读取文件信息...");

  24. })

  25. .then(function(val){

  26. fileMd5=val;

  27. $('#item1').find("p.state").text("成功获取文件信息...");

  28. //获取文件信息后进入下一步

  29. deferred.resolve();

  30. });

  31. return deferred.promise();

  32. },

  33. //时间点2:如果有分块上传,则每个分块上传之前调用此函数

  34. beforeSend:function(block){

  35. console.log("beforeSend");

  36. var deferred = WebUploader.Deferred();

  37.  
  38. $.ajax({

  39. type:"POST",

  40. url:"checkOrMerge?action=checkChunk",

  41. data:{

  42. //文件唯一标记

  43. fileMd5:fileMd5,

  44. //当前分块下标

  45. chunk:block.chunk,

  46. //当前分块大小

  47. chunkSize:block.end-block.start

  48. },

  49. dataType:"json",

  50. success:function(response){

  51. if(response.ifExist){

  52. console.log("分片存在:"+block.chunk)

  53. //分块存在,跳过

  54. deferred.reject();

  55. }else{

  56. console.log("分片不存在:"+block.chunk)

  57. //分块不存在或不完整,重新发送该分块内容

  58. deferred.resolve();

  59. }

  60. }

  61. });

  62.  
  63. this.owner.options.formData.fileMd5 = fileMd5;

  64. console.log("继续执行")

  65. //deferred.resolve();

  66. return deferred.promise();

  67. },

  68. //时间点3:所有分块上传成功后调用此函数

  69. afterSendFile:function(file){

  70. console.log("afterSendFile");

  71. fileName=file.name; //为自定义参数文件名赋值

  72. //如果分块上传成功,则通知后台合并分块

  73. $.ajax({

  74. type:"POST",

  75. url:"checkOrMerge?action=mergeChunks",

  76. data:{

  77. fileMd5:fileMd5,

  78. fileName:fileName,

  79. ext:file.ext, //文件扩展名

  80. projectName: $("#project option:selected").text() //项目名称

  81. },

  82. success:function(response){

  83. var data= eval('(' + response + ')');

  84. var filePath = data.path;

  85. console.log(filePath);

  86. //存储文件路径

  87. var path=$("#filePath").val();

  88. if(path!=""){

  89. path=path+"|"+filePath;

  90. }else{

  91. path=filePath;

  92. }

  93. $("#filePath").val(path);

  94. //alert("上传成功");

  95. //var path = "uploads/"+fileMd5+".mp4";

  96. //$("#item1").attr("src",path);

  97. }

  98. });

  99. }

  100. });

  101.  
  102.  
  103. var uploader = WebUploader.create({

  104. resize: false, // 不压缩image

  105. swf: '/res/webuploader-0.1.5/uploader.swf', // swf文件路径

  106. formData: { projectName: ""},

  107. server: 'upload', // 文件接收服务端。

  108. pick: '#picker', // 选择文件的按钮。可选

  109. chunked: true, //是否要分片处理大文件上传

  110. chunkSize:10*1024*1024, //分片上传,每片2M,默认是5M

  111.  
  112. //auto: false //选择文件后是否自动上传

  113. chunkRetry : 2, //如果某个分片由于网络问题出错,允许自动重传次数

  114. //runtimeOrder: 'html5,flash',

  115. // 在上传当前文件时,准备好下一个文件

  116. prepareNextFile:true,

  117. duplicate : false,//是否重复上传(同时选择多个一样的文件),true可以重复上传

  118. accept: {

  119. title: '语音上传',

  120. extensions: 'wav,zip,rar',

  121. mimeTypes: 'audio/x-wav,.zip,.rar'

  122. }

  123. });

  124. //当文件被加入队列之前触发

  125. uploader.on('beforeFileQueued', function (file,data) {

  126. //项目名称,在后台作为文件夹路径

  127. var projcetName =$("#project").val();

  128. if(projcetName==""){

  129. $("#projectError").text("请先选择项目名称再上传文件!");

  130. return false;

  131. }else{

  132. $("#projectError").text("");

  133. }

  134. //选定项目名称后 ,不可更改

  135. $("#project").attr("disabled","disabled");

  136. });

  137. // 当有文件被添加进队列的时候

  138. uploader.on( 'fileQueued', function( file ) {

  139. $list.append( '<div id="' + file.id + '" class="item">' +

  140. '<span class="info">' + file.name + '</span>' +

  141. '<b class="state" style="width:90px;">等待上传...</b>' +

  142. '</div>' );

  143. });

  144. //绑定uploadBeforeSend事件来给每个独立的文件添加参数

  145. uploader.on( 'uploadBeforeSend', function( block, data ) {

  146. //设置data参数

  147. data.projectName= $("#project").find("option:selected").text(); // 将存在file对象中的md5数据携带发送过去。

  148. },2);

  149. // 文件上传过程中创建进度条实时显示。

  150. uploader.on( 'uploadProgress', function( file, percentage ) {

  151. var $li = $( '#'+file.id ),

  152. $percent = $li.find('.progress .progress-bar');

  153.  
  154. // 避免重复创建

  155. if ( !$percent.length ) {

  156. $percent = $('<div class="progress progress-striped active">' +

  157. '<div class="progress-bar" role="progressbar" style="width: 0%">' +

  158. '</div>' +

  159. '</div>').appendTo( $li ).find('.progress-bar');

  160. }

  161. //进度条以百分比的形式显示

  162. $li.find('b.state').text('上传中'+Math.floor(percentage * 100) + '%' );

  163.  
  164. $percent.css( 'width', percentage * 100 + '%' );

  165. });

  166. // 文件上传成功

  167. uploader.on( 'uploadSuccess', function( file,ret) {

  168. //返回文件的保存路径

  169. if(ret.flag==true){

  170. console.log(ret.path);

  171. var path=$("#filePath").val();

  172. if(path!=""){

  173. path=path+"|"+ret.path;

  174. }else{

  175. path=ret.path;

  176. }

  177. $("#filePath").val(path);

  178. }

  179. $( '#'+file.id ).find('b.state').text('上传成功');

  180. $( '#'+file.id ).find('b.state').css("color","green");

  181. });

  182.  
  183. // 文件上传失败,显示上传出错

  184. uploader.on( 'uploadError', function( file,ret ) {

  185. status=false;

  186. $( '#'+file.id ).find('b.state').text('上传失败');

  187. });

  188. // 完成上传完

  189. uploader.on( 'uploadComplete', function( file ) {

  190. $( '#'+file.id ).find('.progress').fadeOut();

  191. });

  192.  
  193. $btn.on('click', function () {

  194. if ($(this).hasClass('disabled')) {

  195. return false;

  196. }

  197. uploader.upload();

  198. // if (state === 'ready') {

  199. // uploader.upload();

  200. // } else if (state === 'paused') {

  201. // uploader.upload();

  202. // } else if (state === 'uploading') {

  203. // uploader.stop();

  204. // }

  205. });

  206.  
  207. });

  208. </script>

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

 
  1. // 上传文件

  2. @RequestMapping(value = "upload")

  3. public void uploadFile(HttpServletRequest request,

  4. HttpServletResponse response, String projectName)

  5. throws IOException {

  6. response.setCharacterEncoding("UTF-8");

  7. Map map = new HashMap<>();

  8. MultipartFile uploadFile = ((MultipartHttpServletRequest) request)

  9. .getFile("file");

  10. String fileMd5 = request.getParameter("fileMd5");

  11. String chunk = request.getParameter("chunk");

  12. String path = audioPath;

  13. File file = new File(path + fileMd5);

  14. if (!file.exists()) {

  15. file.mkdirs();// 创建文件夹

  16. }

  17. // 保存文件

  18. File chunkFile = new File(path + fileMd5 + "/" + chunk);

  19. if (!chunkFile.exists()) {

  20. chunkFile.createNewFile();

  21. }

  22. uploadFile.transferTo(chunkFile);

  23. }

  24.  
  25. // 合并或验证分片文件是否需要上传

  26. @RequestMapping(value = "checkOrMerge")

  27. public void checkOrMerge(HttpServletRequest request,

  28. HttpServletResponse response) throws IOException {

  29. response.setCharacterEncoding("UTF-8");

  30. String savePath = audioPath;

  31.  
  32. String action = request.getParameter("action");

  33.  
  34. if (action.equals("mergeChunks")) {

  35. // 合并文件

  36. // 需要合并的文件的目录标记

  37. // 文件MD5

  38. String fileMd5 = request.getParameter("fileMd5");

  39. // 文件名称

  40. String fileName = request.getParameter("fileName");

  41. // 文件扩展名

  42. String suffixName = request.getParameter("ext");

  43. // 项目名称

  44. String projectName = request.getParameter("projectName");

  45. System.out.println("fileMd5 :" + fileMd5);

  46. System.out.println("fileName :" + fileName);

  47. System.out.println("projectName :" + projectName);

  48. // 读取目录里的所有文件

  49. File f = new File(savePath + fileMd5);

  50. File[] fileArray = f.listFiles(new FileFilter() {

  51. // 排除目录只要文件

  52. @Override

  53. public boolean accept(File pathname) {

  54. if (pathname.isDirectory()) {

  55. return false;

  56. }

  57. return true;

  58. }

  59. });

  60. System.out.println(" fileArray " + fileArray);

  61. // 转成集合,便于排序

  62. List<File> fileList = new ArrayList<File>(Arrays.asList(fileArray));

  63. // 需要合并的文件才进行排序,即分片的大小大于1

  64. if (fileList != null && fileList.size() > 1) {

  65. Collections.sort(fileList, new Comparator<File>() {

  66. @Override

  67. public int compare(File o1, File o2) {

  68. // TODO Auto-generated method stub

  69. if (Integer.parseInt(o1.getName()) < Integer

  70. .parseInt(o2.getName())) {

  71. return -1;

  72. }

  73. return 1;

  74. }

  75. });

  76. }

  77. // 合并的文件夹

  78. File mergeFile = new File(savePath + projectName);

  79. if (!mergeFile.exists()) {

  80. mergeFile.mkdirs();

  81. }

  82. // UUID.randomUUID().toString()-->随机名

  83. File outputFile = new File(savePath + projectName + "/" + fileName);

  84. // 创建文件

  85. outputFile.createNewFile();

  86. // 输出流

  87. FileChannel outChnnel = new FileOutputStream(outputFile)

  88. .getChannel();

  89. // 合并

  90. FileChannel inChannel;

  91. for (File file : fileList) {

  92. inChannel = new FileInputStream(file).getChannel();

  93. inChannel.transferTo(0, inChannel.size(), outChnnel);

  94. inChannel.close();

  95. // 删除分片

  96. file.delete();

  97. }

  98. outChnnel.close();

  99. // 清除文件夹

  100. File tempFile = new File(savePath + fileMd5);

  101. if (tempFile.isDirectory() && tempFile.exists()) {

  102. tempFile.delete();

  103. }

  104. System.out.println("合并成功");

  105. Map<String, String> map = new HashMap<>();

  106. // 文件路径

  107. map.put("path", projectName + "/" + fileName);

  108. response.getWriter().print(JSON.toJSON(map));

  109. } else if (action.equals("checkChunk")) {

  110. // 检查当前分块是否上传成功

  111. String fileMd5 = request.getParameter("fileMd5");

  112. String chunk = request.getParameter("chunk");

  113. String chunkSize = request.getParameter("chunkSize");

  114.  
  115. File checkFile = new File(savePath + fileMd5 + "/" + chunk);

  116.  
  117. response.setContentType("text/html;charset=utf-8");

  118. // 检查文件是否存在,且大小是否一致

  119. if (checkFile.exists()

  120. && checkFile.length() == Integer.parseInt(chunkSize)) {

  121. // 上传过

  122. response.getWriter().write("{\"ifExist\":1}");

  123. } else {

  124. // 没有上传过

  125. response.getWriter().write("{\"ifExist\":0}");

  126. }

  127. }

  128.  
  129. }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值