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 相关文章推荐
Use Word to Search for Files
Jun 15 Javascript
jquery 表单进行客户端验证demo
Aug 24 Javascript
JS执行删除前的判断代码
Feb 18 Javascript
js获取指定日期周数以及星期几的小例子
Jun 27 Javascript
jquery取子节点及当前节点属性值的方法
Sep 09 Javascript
jquery 实现返回顶部功能
Nov 17 Javascript
javascript中slice(),splice(),split(),substring(),substr()使用方法
Mar 13 Javascript
在JavaScript应用中实现延迟加载的方法
Jun 25 Javascript
基于jquery实现人物头像跟随鼠标转动
Aug 23 Javascript
vue修改vue项目运行端口号的方法
Aug 04 Javascript
Vue用v-for给循环标签自身属性添加属性值的方法
Oct 18 Javascript
JavaScript数组、json对象、eval()函数用法实例分析
Feb 21 Javascript
在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
MySQL相关说明
2007/01/15 PHP
php curl 伪造IP来源的实例代码
2012/11/01 PHP
php中Array2xml类实现数组转化成XML实例
2014/12/08 PHP
PHP register_shutdown_function()函数的使用示例
2015/06/23 PHP
PHP实现提取多维数组指定一列的方法总结
2019/12/04 PHP
jquery 插件学习(五)
2012/08/06 Javascript
jQuery实现隔行背景色变色
2014/11/24 Javascript
PHPMyAdmin导入时提示文件大小超出PHP限制的解决方法
2015/03/30 Javascript
Javascript设计模式理论与编程实战之简单工厂模式
2015/11/03 Javascript
JavaScript+html5 canvas绘制缤纷多彩的三角形效果完整实例
2016/01/26 Javascript
JavaScript代码性能优化总结篇
2016/05/15 Javascript
jQuery mobile的header和footer在点击屏幕的时候消失的解决办法
2016/07/01 Javascript
JS高仿抛物线加入购物车特效实现代码
2017/02/20 Javascript
vue.js学习之UI组件开发教程
2017/07/03 Javascript
webpack构建react多页面应用详解
2017/09/15 Javascript
BACKBONE.JS 简单入门范例
2017/10/17 Javascript
vue 基于element-ui 分页组件封装的实例代码
2018/12/10 Javascript
koa大型web项目中使用路由装饰器的方法示例
2019/04/02 Javascript
angular4+百分比进度显示插件用法示例
2019/05/05 Javascript
解决layer弹出层中表单不起作用的问题
2019/09/09 Javascript
Jquery属性的获取/设置及样式添加/删除操作技巧分析
2019/12/23 jQuery
[01:06]DOTA2小知识课堂 Ep.02 吹风竟可解梦境缠绕
2019/12/05 DOTA
TensorFlow 实战之实现卷积神经网络的实例讲解
2018/02/26 Python
Python中垃圾回收和del语句详解
2018/11/15 Python
python操作小程序云数据库实现简单的增删改查功能
2019/06/06 Python
django 环境变量配置过程详解
2019/08/06 Python
Python中random模块常用方法的使用教程
2020/10/04 Python
利用CSS3实现动态的二级三级菜单效果实例源码
2017/01/04 HTML / CSS
澳大利亚的奢侈品牌:Oroton
2016/08/26 全球购物
毕业生精彩的自我评价分享
2013/10/06 职场文书
演讲稿开场白
2014/01/13 职场文书
给幼儿园老师的表扬信
2014/01/19 职场文书
护士演讲稿优秀范文
2014/04/30 职场文书
庆祝教师节活动总结
2015/03/23 职场文书
2016年国庆节宣传标语
2015/11/25 职场文书
Mysql中mvcc各场景理解应用
2022/08/05 MySQL