webuploader分片上传的实现代码(前后端分离)


Posted in Javascript onSeptember 10, 2018

本文介绍了webuploader分片上传的实现代码(前后端分离),分享给大家,具体如下:

WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件。在现代的浏览器里面能充分发挥HTML5的优势,同时又不摒弃主流IE浏览器,沿用原来的FLASH运行时,兼容IE6+,iOS 6+, android 4+。两套运行时,同样的调用方式,可供用户任意选用。采用大文件分片并发上传,极大的提高了文件上传效率。(这个是从官网上直接copy的解释)

功能描述

1、webuploader是百度研发的上传组件,文档不是特别规整,但是也够用了。

2、前端使用官网的上传图片demo,在此基础上代码略微调整做分片。既可以上传图片也可以上传文件。文件超过分片大小才启用分片。

3、分片上传已做md5校验,达到秒传的效果。分片以后需要合并,可以先分片后合并,也可以边分片边合并,本示例采用的是边分片边合并的方案。

4、后端用springboot做框架搭建。springMVC做rest服务,开启跨域访问。

5、容器用springboot内置的tomcat插件,运行Application的main方法即可启动服务;

显示效果

webuploader分片上传的实现代码(前后端分离)

webuploader分片上传的实现代码(前后端分离)

webuploader分片上传的实现代码(前后端分离)

关键代码前端

WebUploader.Uploader.register({ 
      'name': 'webUploaderHookCommand', 
      'before-send-file': 'beforeSendFile', 
      "before-send": "beforeSend" 
    }, { 
      beforeSendFile: function(file) { 
        var task = new WebUploader.Deferred(); 
        fileName = file.name; 
        fileSize = file.size; 
        (new WebUploader.Uploader()).md5File(file, 0, 10 * 1024 * 1024).progress(function(percentage) {}).then(function(val) { 
          fileMd5 = val; 
          var url = checkUrl; 
          var data = { 
            type: 0, 
            fileName: fileName, 
            fileMd5: fileMd5, 
            fileSize: fileSize 
          }; 
          $.ajax({ 
            type: "POST", 
            url: url, 
            data: data, 
            cache: false, 
            async: false, // 同步 
            timeout: 1000, // todo 超时的话,只能认为该分片未上传过 
            dataType: "json", 
            error: function(XMLHttpRequest, textStatus, errorThrown) { 
              file.statusText = 'server_error'; 
              task.reject(); 
            } 
          }).then(function(data, textStatus, jqXHR) { 
            if(data.rtn == 0) { 
              if(data.obj == 1) { 
                file.statusText = 'file_existed'; 
                task.reject(); 
              } else { 
                task.resolve(); 
              } 
            } else { 
              task.reject(); 
            } 
          }); 
        }); 
        return task.promise(); 
      }, 
      beforeSend: function(block) { 
        var task = new WebUploader.Deferred(); 
        var url = checkUrl; 
        var data = { 
          type: 1, 
          fileName: fileName, 
          fileMd5: fileMd5, 
          chunk: block.chunk, 
          fileSize: block.end - block.start 
        }; 
        $.ajax({ 
          type: "POST", 
          url: url, 
          data: data, 
          cache: false, 
          async: false, // 同步 
          timeout: 1000, // todo 超时的话,只能认为该分片未上传过 
          dataType: "json" 
        }).then(function(data, textStatus, jqXHR) { 
          if(data.rtn == 0 && data.obj == 1) { 
            task.reject(); // 分片存在,则跳过上传 
          } else { 
            task.resolve(); 
          } 
        }); 
        this.owner.options.formData.fileMd5 = fileMd5; 
        this.owner.options.formData.chunkSize = chunkSize; 
        return task.promise(); 
      } 
    }); 
 
    // 实例化 
    uploader = WebUploader.create({ 
      pick: { 
        id: '#filePicker', 
        label: '点击选择文件' 
      }, 
      formData: { 
        uid: 123 
      }, 
      dnd: '#dndArea', //指定文件拖拽的区域 
      paste: '#uploader', //指定监听paste事件的容器,如果不指定,不启用此功能。此功能为通过粘贴来添加截屏的图片。建议设置为document.body. 
      swf: '../plugins/webuploader/Uploader.swf', 
      chunked: true, 
      chunkSize: chunkSize, 
      chunkRetry: false, 
      threads: 1, 
      server: uploadUrl, 
      // runtimeOrder: 'flash', 
 
      // accept: { 
      //   title: 'Images', 
      //   extensions: 'gif,jpg,jpeg,bmp,png', 
      //   mimeTypes: 'image/*' 
      // }, 
      // 禁掉全局的拖拽功能。这样不会出现图片拖进页面的时候,把图片打开。 
      disableGlobalDnd: true, 
      fileNumLimit: 300 //限制多文件上传的个数 
      //fileSizeLimit: 200 * 1024 * 1024, // 限制所有文件的大小 200 M 
      //fileSingleSizeLimit: 50 * 1024 * 1024 // 限制单个文件的大小 50 M 
    });

后端

import java.io.File; 
import java.io.IOException; 
 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.beans.factory.annotation.Value; 
import org.springframework.stereotype.Service; 
import org.springframework.web.multipart.MultipartFile; 
 
import com.bear.upload.util.FileUtil; 
import com.bear.upload.util.RETURN; 
import com.bear.upload.vo.CheckMd5FileVO; 
import com.bear.upload.vo.UploadVO; 
 
@Service 
public class ChunkUploadService { 
 
  private static Logger LOG = LoggerFactory.getLogger(ChunkUploadService.class); 
 
  @Value("${file.upload.path}") 
  private String UPLOAD_PATH; 
 
  private static final String Delimiter = "-"; 
 
  /** 
   * 上传之前校验(整个文件、分片) 
   * 
   * @param md5FileVO 
   * @return 
   */ 
  public Object check(CheckMd5FileVO md5FileVO) { 
    Integer type = md5FileVO.getType(); 
    Long chunk = md5FileVO.getChunk(); 
    String fileName = md5FileVO.getFileName(); 
    Long fileSize = md5FileVO.getFileSize(); 
    if (type == 0) {// 未分片校验 
      String destfilePath = UPLOAD_PATH + File.separator + fileName; 
      File destFile = new File(destfilePath); 
      if (destFile.exists() && destFile.length() == fileSize) { 
        return RETURN.success("文件已存在,跳过", 1); 
      } else { 
        return RETURN.success("文件不存在", 0); 
      } 
    } else {// 分片校验 
      String fileMd5 = md5FileVO.getFileMd5(); 
      String destFileDir = UPLOAD_PATH + File.separator + fileMd5; 
      String destFileName = chunk + Delimiter + fileName; 
      String destFilePath = destFileDir + File.separator + destFileName; 
      File destFile = new File(destFilePath); 
      if (destFile.exists() && destFile.length() == fileSize) { 
        return RETURN.success("分片已存在,跳过", 1); 
      } else { 
        return RETURN.success("分片不存在", 0); 
      } 
    } 
  } 
 
  /** 
   * 文件上传 
   * 
   * @param file 
   * @param uploadVO 
   * @param appVersion 
   * @return 
   */ 
  public Object upload(MultipartFile file, UploadVO uploadVO) { 
    Long chunk = uploadVO.getChunk(); 
    if (chunk == null) {// 没有分片 
      return UnChunkUpload(file, uploadVO); 
    } else {// 分片 
      return ChunkUpload(file, uploadVO); 
    } 
  } 
 
  /** 
   * 分片上传 
   * 
   * @param file 
   * @param uploadVO 
   * @param appVersion 
   * @return 
   */ 
  public Object ChunkUpload(MultipartFile file, UploadVO uploadVO) { 
    String fileName = uploadVO.getName(); 
    String fileMd5 = uploadVO.getFileMd5(); 
    Long chunk = uploadVO.getChunk();// 当前片 
    Long chunks = uploadVO.getChunks();// 总共多少片 
 
    // 分片目录创建 
    String chunkDirPath = UPLOAD_PATH + File.separator + fileMd5; 
    File chunkDir = new File(chunkDirPath); 
    if (!chunkDir.exists()) { 
      chunkDir.mkdirs(); 
    } 
    // 分片文件上传 
    String chunkFileName = chunk + Delimiter + fileName; 
    String chunkFilePath = chunkDir + File.separator + chunkFileName; 
    File chunkFile = new File(chunkFilePath); 
    try { 
      file.transferTo(chunkFile); 
    } catch (Exception e) { 
      LOG.error("分片上传出错", e); 
      return RETURN.fail("分片上传出错", 1); 
    } 
    // 合并分片 
    Long chunkSize = uploadVO.getChunkSize(); 
    long seek = chunkSize * chunk; 
    String destFilePath = UPLOAD_PATH + File.separator + fileName; 
    File destFile = new File(destFilePath); 
    if (chunkFile.length() > 0) { 
      try { 
        FileUtil.randomAccessFile(chunkFile, destFile, seek); 
      } catch (IOException e) { 
        LOG.error("分片{}合并失败:{}", chunkFile.getName(), e.getMessage()); 
        return RETURN.fail("分片合并失败", 1); 
      } 
    } 
    if (chunk == chunks - 1) { 
      // 删除分片文件夹 
      FileUtil.deleteDirectory(chunkDirPath); 
 
      return RETURN.success("上传成功", 1); 
    } else { 
      return RETURN.fail("上传中...", 1); 
    } 
  } 
 
  /** 
   * 未分片上传 
   * 
   * @param file 
   * @param uploadVO 
   * @param appVersion 
   * @return 
   */ 
  public Object UnChunkUpload(MultipartFile file, UploadVO uploadVO) { 
    String fileName = uploadVO.getName(); 
    // String fileMd5 = uploadVO.getFileMd5(); 
    // 文件上传 
    File destFile = new File(UPLOAD_PATH + File.separator + fileName); 
    if (file != null && !file.isEmpty()) { 
      // 上传目录 
      File fileDir = new File(UPLOAD_PATH); 
      if (!fileDir.exists()) { 
        fileDir.mkdirs(); 
      } 
      if (destFile.exists()) { 
        destFile.delete(); 
      } 
      try { 
        file.transferTo(destFile); 
        return RETURN.success("上传成功", 0); 
      } catch (Exception e) { 
        LOG.error("文件上传出错", e); 
        return RETURN.fail("文件上传出错", 0); 
      } 
    } 
    return RETURN.fail("上传失败", 0); 
  } 
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js自带函数备忘 数组
Dec 29 Javascript
JS提交并解析后台返回的XML的代码
Nov 03 Javascript
javascript 表格排序和表头浮动效果(扩展SortTable)
Apr 07 Javascript
Javascript 构造函数,公有,私有特权和静态成员定义方法
Nov 30 Javascript
JQuery扩展插件Validate—6 radio、checkbox、select的验证
Sep 05 Javascript
BootStrap 超链接变按钮的实现方法
Sep 25 Javascript
javascript中闭包概念与用法深入理解
Dec 15 Javascript
详解vue-cli 构建项目 vue-cli请求后台接口 vue-cli使用axios、sass、swiper
May 28 Javascript
轻量级富文本编辑器wangEditor结合vue使用方法示例
Oct 10 Javascript
浅谈JavaScript面向对象--继承
Mar 20 Javascript
vue使用showdown并实现代码区域高亮的示例代码
Oct 17 Javascript
jQuery 选择方法及$(this)用法实例分析
May 19 jQuery
在Vue 中使用Typescript的示例代码
Sep 10 #Javascript
ES6使用export和import实现模块化的方法
Sep 10 #Javascript
Vuejs 实现简易 todoList 功能 与 组件实例代码
Sep 10 #Javascript
浅谈微信小程序flex布局基础
Sep 10 #Javascript
微信小程序文章详情页面实现代码
Sep 10 #Javascript
Bootbox将后台JSON数据填充Form表单的实例代码
Sep 10 #Javascript
JavaScript读写二进制数据的方法详解
Sep 09 #Javascript
You might like
php mssql 数据库分页SQL语句
2008/12/16 PHP
简单的php写入数据库类代码分享
2011/07/26 PHP
php缓冲 output_buffering的使用详解
2013/06/13 PHP
深入PHP中的HashTable结构详解
2013/06/13 PHP
如何实现php图片等比例缩放
2015/07/28 PHP
php中各种定义变量的方法小结
2017/10/18 PHP
PHP基于进程控制函数实现多线程
2020/12/09 PHP
百度Popup.js弹出框进化版 拖拽小框架发布 兼容IE6/7/8,Firefox,Chrome
2010/04/13 Javascript
基于jquery用于查询操作的实现代码
2010/05/10 Javascript
30个最好的jQuery 灯箱插件分享
2011/04/25 Javascript
从js向Action传中文参数出现乱码问题的解决方法
2013/12/29 Javascript
js用Date对象的setDate()函数对日期进行加减操作
2014/09/18 Javascript
探索Vue.js component内容实现
2016/11/03 Javascript
详解jQuery简单的表格应用
2016/12/16 Javascript
Nodejs之TCP服务端与客户端聊天程序详解
2017/07/07 NodeJs
使用electron将vue-cli项目打包成exe的方法
2018/09/29 Javascript
javascript设计模式 ? 迭代器模式原理与用法实例分析
2020/04/17 Javascript
React倒计时功能实现代码——解耦通用
2020/09/18 Javascript
Python爬虫框架Scrapy实战之批量抓取招聘信息
2015/08/07 Python
分析Python中设计模式之Decorator装饰器模式的要点
2016/03/02 Python
Django基础知识与基本应用入门教程
2018/07/20 Python
python 输入一个数n,求n个数求乘或求和的实例
2018/11/13 Python
使用django实现一个代码发布系统
2019/07/18 Python
python3 selenium自动化 frame表单嵌套的切换方法
2019/08/23 Python
python中的对数log函数表示及用法
2020/12/09 Python
python自动打开浏览器下载zip并提取内容写入excel
2021/01/04 Python
7款设计巧妙的css3飘带状3D立体效果的导航菜单和表单窗口
2013/02/04 HTML / CSS
HTML5中form如何关闭自动完成功能的方法
2018/07/02 HTML / CSS
世界最大的私人旅行指南出版商:孤独星球
2016/08/23 全球购物
山海经纬软件测试笔试题和面试题
2013/04/02 面试题
当当网软件测试笔试题
2015/11/24 面试题
医学专业毕业生个人求职信
2013/12/25 职场文书
如何打造一封优秀的留学推荐信
2014/01/25 职场文书
心理学专业大学生职业生涯规划范文
2014/02/19 职场文书
2016年教师党员创先争优承诺书
2016/03/24 职场文书
React forwardRef的使用方法及注意点
2021/06/13 Javascript