webuploader分片上传(前后端分离)

功能描述

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

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

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

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

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

显示效果

关键代码

前端

[javascript] view plain copy

  1. WebUploader.Uploader.register({  
  2.             'name': 'webUploaderHookCommand',  
  3.             'before-send-file': 'beforeSendFile',  
  4.             "before-send": "beforeSend"  
  5.         }, {  
  6.             beforeSendFile: function(file) {  
  7.                 var task = new WebUploader.Deferred();  
  8.                 fileName = file.name;  
  9.                 fileSize = file.size;  
  10.                 (new WebUploader.Uploader()).md5File(file, 0, 10 * 1024 * 1024).progress(function(percentage) {}).then(function(val) {  
  11.                     fileMd5 = val;  
  12.                     var url = checkUrl;  
  13.                     var data = {  
  14.                         type: 0,  
  15.                         fileName: fileName,  
  16.                         fileMd5: fileMd5,  
  17.                         fileSize: fileSize  
  18.                     };  
  19.                     $.ajax({  
  20.                         type: "POST",  
  21.                         url: url,  
  22.                         data: data,  
  23.                         cache: false,  
  24.                         async: false, // 同步  
  25.                         timeout: 1000, // todo 超时的话,只能认为该分片未上传过  
  26.                         dataType: "json",  
  27.                         error: function(XMLHttpRequest, textStatus, errorThrown) {  
  28.                             file.statusText = 'server_error';  
  29.                             task.reject();  
  30.                         }  
  31.                     }).then(function(data, textStatus, jqXHR) {  
  32.                         if(data.rtn == 0) {  
  33.                             if(data.obj == 1) {  
  34.                                 file.statusText = 'file_existed';  
  35.                                 task.reject();  
  36.                             } else {  
  37.                                 task.resolve();  
  38.                             }  
  39.                         } else {  
  40.                             task.reject();  
  41.                         }  
  42.                     });  
  43.                 });  
  44.                 return task.promise();  
  45.             },  
  46.             beforeSend: function(block) {  
  47.                 var task = new WebUploader.Deferred();  
  48.                 var url = checkUrl;  
  49.                 var data = {  
  50.                     type: 1,  
  51.                     fileName: fileName,  
  52.                     fileMd5: fileMd5,  
  53.                     chunk: block.chunk,  
  54.                     fileSize: block.end - block.start  
  55.                 };  
  56.                 $.ajax({  
  57.                     type: "POST",  
  58.                     url: url,  
  59.                     data: data,  
  60.                     cache: false,  
  61.                     async: false, // 同步  
  62.                     timeout: 1000, // todo 超时的话,只能认为该分片未上传过  
  63.                     dataType: "json"  
  64.                 }).then(function(data, textStatus, jqXHR) {  
  65.                     if(data.rtn == 0 && data.obj == 1) {  
  66.                         task.reject(); // 分片存在,则跳过上传  
  67.                     } else {  
  68.                         task.resolve();  
  69.                     }  
  70.                 });  
  71.                 this.owner.options.formData.fileMd5 = fileMd5;  
  72.                 this.owner.options.formData.chunkSize = chunkSize;  
  73.                 return task.promise();  
  74.             }  
  75.         });  
  76.   
  77.         // 实例化  
  78.         uploader = WebUploader.create({  
  79.             pick: {  
  80.                 id: '#filePicker',  
  81.                 label: '点击选择文件'  
  82.             },  
  83.             formData: {  
  84.                 uid: 123  
  85.             },  
  86.             dnd: '#dndArea', //指定文件拖拽的区域  
  87.             paste: '#uploader', //指定监听paste事件的容器,如果不指定,不启用此功能。此功能为通过粘贴来添加截屏的图片。建议设置为document.body.  
  88.             swf: '../plugins/webuploader/Uploader.swf',  
  89.             chunked: true,  
  90.             chunkSize: chunkSize,  
  91.             chunkRetry: false,  
  92.             threads: 1,  
  93.             server: uploadUrl,  
  94.             // runtimeOrder: 'flash',  
  95.   
  96.             // accept: {  
  97.             //     title: 'Images',  
  98.             //     extensions: 'gif,jpg,jpeg,bmp,png',  
  99.             //     mimeTypes: 'image/*'  
  100.             // },  
  101.             // 禁掉全局的拖拽功能。这样不会出现图片拖进页面的时候,把图片打开。  
  102.             disableGlobalDnd: true,  
  103.             fileNumLimit: 300 //限制多文件上传的个数  
  104.             //fileSizeLimit: 200 * 1024 * 1024, // 限制所有文件的大小 200 M  
  105.             //fileSingleSizeLimit: 50 * 1024 * 1024 // 限制单个文件的大小 50 M  
  106.         });  

后端

[java] view plain copy

  1. import java.io.File;  
  2. import java.io.IOException;  
  3.   
  4. import org.slf4j.Logger;  
  5. import org.slf4j.LoggerFactory;  
  6. import org.springframework.beans.factory.annotation.Value;  
  7. import org.springframework.stereotype.Service;  
  8. import org.springframework.web.multipart.MultipartFile;  
  9.   
  10. import com.bear.upload.util.FileUtil;  
  11. import com.bear.upload.util.RETURN;  
  12. import com.bear.upload.vo.CheckMd5FileVO;  
  13. import com.bear.upload.vo.UploadVO;  
  14.   
  15. @Service  
  16. public class ChunkUploadService {  
  17.   
  18.     private static Logger LOG = LoggerFactory.getLogger(ChunkUploadService.class);  
  19.   
  20.     @Value("${file.upload.path}")  
  21.     private String UPLOAD_PATH;  
  22.   
  23.     private static final String Delimiter = "-";  
  24.   
  25.     /** 
  26.      * 上传之前校验(整个文件、分片) 
  27.      *  
  28.      * @param md5FileVO 
  29.      * @return 
  30.      */  
  31.     public Object check(CheckMd5FileVO md5FileVO) {  
  32.         Integer type = md5FileVO.getType();  
  33.         Long chunk = md5FileVO.getChunk();  
  34.         String fileName = md5FileVO.getFileName();  
  35.         Long fileSize = md5FileVO.getFileSize();  
  36.         if (type == 0) {// 未分片校验  
  37.             String destfilePath = UPLOAD_PATH + File.separator + fileName;  
  38.             File destFile = new File(destfilePath);  
  39.             if (destFile.exists() && destFile.length() == fileSize) {  
  40.                 return RETURN.success("文件已存在,跳过", 1);  
  41.             } else {  
  42.                 return RETURN.success("文件不存在", 0);  
  43.             }  
  44.         } else {// 分片校验  
  45.             String fileMd5 = md5FileVO.getFileMd5();  
  46.             String destFileDir = UPLOAD_PATH + File.separator + fileMd5;  
  47.             String destFileName = chunk + Delimiter + fileName;  
  48.             String destFilePath = destFileDir + File.separator + destFileName;  
  49.             File destFile = new File(destFilePath);  
  50.             if (destFile.exists() && destFile.length() == fileSize) {  
  51.                 return RETURN.success("分片已存在,跳过", 1);  
  52.             } else {  
  53.                 return RETURN.success("分片不存在", 0);  
  54.             }  
  55.         }  
  56.     }  
  57.   
  58.     /** 
  59.      * 文件上传 
  60.      *  
  61.      * @param file 
  62.      * @param uploadVO 
  63.      * @param appVersion 
  64.      * @return 
  65.      */  
  66.     public Object upload(MultipartFile file, UploadVO uploadVO) {  
  67.         Long chunk = uploadVO.getChunk();  
  68.         if (chunk == null) {// 没有分片  
  69.             return UnChunkUpload(file, uploadVO);  
  70.         } else {// 分片  
  71.             return ChunkUpload(file, uploadVO);  
  72.         }  
  73.     }  
  74.   
  75.     /** 
  76.      * 分片上传 
  77.      *  
  78.      * @param file 
  79.      * @param uploadVO 
  80.      * @param appVersion 
  81.      * @return 
  82.      */  
  83.     public Object ChunkUpload(MultipartFile file, UploadVO uploadVO) {  
  84.         String fileName = uploadVO.getName();  
  85.         String fileMd5 = uploadVO.getFileMd5();  
  86.         Long chunk = uploadVO.getChunk();// 当前片  
  87.         Long chunks = uploadVO.getChunks();// 总共多少片  
  88.   
  89.         // 分片目录创建  
  90.         String chunkDirPath = UPLOAD_PATH + File.separator + fileMd5;  
  91.         File chunkDir = new File(chunkDirPath);  
  92.         if (!chunkDir.exists()) {  
  93.             chunkDir.mkdirs();  
  94.         }  
  95.         // 分片文件上传  
  96.         String chunkFileName = chunk + Delimiter + fileName;  
  97.         String chunkFilePath = chunkDir + File.separator + chunkFileName;  
  98.         File chunkFile = new File(chunkFilePath);  
  99.         try {  
  100.             file.transferTo(chunkFile);  
  101.         } catch (Exception e) {  
  102.             LOG.error("分片上传出错", e);  
  103.             return RETURN.fail("分片上传出错", 1);  
  104.         }  
  105.         // 合并分片  
  106.         Long chunkSize = uploadVO.getChunkSize();  
  107.         long seek = chunkSize * chunk;  
  108.         String destFilePath = UPLOAD_PATH + File.separator + fileName;  
  109.         File destFile = new File(destFilePath);  
  110.         if (chunkFile.length() > 0) {  
  111.             try {  
  112.                 FileUtil.randomAccessFile(chunkFile, destFile, seek);  
  113.             } catch (IOException e) {  
  114.                 LOG.error("分片{}合并失败:{}", chunkFile.getName(), e.getMessage());  
  115.                 return RETURN.fail("分片合并失败", 1);  
  116.             }  
  117.         }  
  118.         if (chunk == chunks - 1) {  
  119.             // 删除分片文件夹  
  120.             FileUtil.deleteDirectory(chunkDirPath);  
  121.   
  122.             return RETURN.success("上传成功", 1);  
  123.         } else {  
  124.             return RETURN.fail("上传中...", 1);  
  125.         }  
  126.     }  
  127.   
  128.     /** 
  129.      * 未分片上传 
  130.      *  
  131.      * @param file 
  132.      * @param uploadVO 
  133.      * @param appVersion 
  134.      * @return 
  135.      */  
  136.     public Object UnChunkUpload(MultipartFile file, UploadVO uploadVO) {  
  137.         String fileName = uploadVO.getName();  
  138.         // String fileMd5 = uploadVO.getFileMd5();  
  139.         // 文件上传  
  140.         File destFile = new File(UPLOAD_PATH + File.separator + fileName);  
  141.         if (file != null && !file.isEmpty()) {  
  142.             // 上传目录  
  143.             File fileDir = new File(UPLOAD_PATH);  
  144.             if (!fileDir.exists()) {  
  145.                 fileDir.mkdirs();  
  146.             }  
  147.             if (destFile.exists()) {  
  148.                 destFile.delete();  
  149.             }  
  150.             try {  
  151.                 file.transferTo(destFile);  
  152.                 return RETURN.success("上传成功", 0);  
  153.             } catch (Exception e) {  
  154.                 LOG.error("文件上传出错", e);  
  155.                 return RETURN.fail("文件上传出错", 0);  
  156.             }  
  157.         }  
  158.         return RETURN.fail("上传失败", 0);  
  159.     }  
  160. }  

猜你喜欢

转载自blog.csdn.net/bzerah/article/details/86688080
今日推荐