5.2 SpringBoot实现断点续传功能 > 我的程序猿之路:第四十二章


 

功能使用webuploader组件分片下载文件 文档地址: http://fex.baidu.com/webuploader/document.html

 http://fex.baidu.com/webuploader/download.html中下载

用到的是:

              Uploader.swf

              webuploader.css

              webuploader.min.js

我的目录

 

 

需要jar包:

        commons-fileupload-1.3.3.jar

        commons-io-2.5.jar

    导入jar包方法:Shift+Ctrl+Alt+s

 

    按步骤导入   jar包。。。

 

 

webUploader.java

 1 package com.example.demo3.upLoader;  2 
 3 import org.apache.commons.fileupload.FileItem;  4 import org.apache.commons.fileupload.FileUploadException;  5 import org.apache.commons.fileupload.disk.DiskFileItemFactory;  6 import org.apache.commons.fileupload.servlet.ServletFileUpload;  7 import org.apache.commons.io.FileUtils;  8 import org.springframework.stereotype.Controller;  9 import org.springframework.web.bind.annotation.RequestMapping;  10 
 11 import javax.servlet.ServletException;  12 import javax.servlet.http.HttpServletRequest;  13 import javax.servlet.http.HttpServletResponse;  14 import java.io.File;  15 import java.io.FileInputStream;  16 import java.io.FileOutputStream;  17 import java.io.IOException;  18 import java.util.HashMap;  19 import java.util.List;  20 
 21 @RequestMapping("uploader.do")  22 @Controller  23 public class WebUpLoaderController {  24     private static final long serialVersionUID = 1L;  25     @RequestMapping("loader")  26     public void douploader(HttpServletRequest request, HttpServletResponse response)  27             throws Exception {  28         String fileName = request.getParameter("fileName");  29         String fileMd5 = request.getParameter("fileMd5");  30         String chunk = request.getParameter("chunk");  31         String chunkSize = request.getParameter("chunkSize");  32         String guid = request.getParameter("guid");  33 
 34         String path = ("C:/upload/uploads");  35         File checkFile = new File(path+"/"+guid+"/"+chunk);  36 
 37         response.setContentType("text/html;charset=utf-8");  38 
 39         //检查文件是否存在,且大小是否一致
 40         if(checkFile.exists() && checkFile.length()==Integer.parseInt(chunkSize)){  41             //上传过
 42 
 43                 response.getWriter().write("{\"ifExist\":1}");  44 
 45         }else{  46             //没有上传过
 47 
 48                 response.getWriter().write("{\"ifExist\":0}");  49 
 50  }  51 
 52  }  53     @RequestMapping("loader2")  54     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  55 
 56          String path = "C:\\upload\\uploads";  57          String guid = request.getParameter("guid");  58          String fileName = request.getParameter("fileName");  59         /**
 60  * 进行文件合并  61          */
 62         File file = new File(path+"/"+guid);  63         new File("C:\\upload\\upload"+"/"+guid).mkdirs();  64         /**
 65  * 进行文件合并  66          */
 67         File newFile = new File("C:\\upload\\upload"+"/"+guid+"/"+fileName);  68         FileOutputStream outputStream = new FileOutputStream(newFile, true);//文件追加写入
 69         byte[] byt = new byte[10*1024*1024];  70         int len;  71         FileInputStream temp = null;//分片文件
 72         File[] childs = new File(path+"/"+guid).listFiles();  73         boolean boo = false;  74         if(childs!=null) {  75             for (int i = 0; i < childs.length; i++) {  76                 temp = new FileInputStream(childs[i]);  77                 while ((len = temp.read(byt)) != -1) {  78                     //System.out.println(len);
 79                     outputStream.write(byt, 0, len);  80  }  81  temp.close();  82                 boo=true;  83  }  84  }  85         /**
 86  * 当所有追加写入都写完 才可以关闭流  87          */
 88  outputStream.close();  89         if(temp!=null){  90  temp.close();  91  }  92         if(boo) {  93             delFolder(path + "/" + guid);  94  }  95 
 96  }  97     @RequestMapping("loader1")  98     protected void doupload(HttpServletRequest request, HttpServletResponse response)  99             throws ServletException, IOException { 100         String path = "C:\\upload\\uploads"; 101         //DiskFileItemFactory factory = new DiskFileItemFactory(); 102         // 2、创建一个文件上传解析器
103         ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory()); 104 
105         // 设置单个文件的最大上传值
106         upload.setFileSizeMax(15*1024*1024L); 107         // 设置整个request的最大值
108         upload.setSizeMax(15*1024*1024L); 109         // 解决上传文件名的中文乱码
110         upload.setHeaderEncoding("UTF-8"); 111         // fileUpload.setProgressListener(listener); 112         // 3、判断提交上来的数据是否是上传表单的数据
113         if (!ServletFileUpload.isMultipartContent(request)) { 114             return; 115  } 116         // 4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
117         List<FileItem> list = null; 118         try { 119 
120             list = upload.parseRequest(request); 121             // 获得文件: 122             // MultipartFile file = multipartRequest.getFile(" file ");
123         } catch (FileUploadException e) { 124  e.printStackTrace(); 125  } 126 
127         HashMap<String, String> map = new HashMap<String, String>(); 128 
129         for (FileItem item : list) { 130             if (item.isFormField()) { 131                 String name = item.getFieldName(); 132                 // 解决普通输入项的数据的中文乱码问题
133                 String value = item.getString("UTF-8"); 134 
135                 map.put(name, value);// 放入map集合
136             } else { 137                 /**
138  * 文件上传 139                  */
140 
141                 File fileParent = new File(path + "/" + map.get("guid"));//以guid创建临时文件夹
142                 if (!fileParent.exists()) { 143  fileParent.mkdir(); 144  } 145 
146 
147                 String filename = item.getName(); 148                 if (filename == null || filename.trim().equals("")) { 149                     continue; 150  } 151                 // 注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如: 152                 // c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt 153                 // 处理获取到的上传文件的文件名的路径部分,只保留文件名部分
154                 filename = filename.substring(filename.lastIndexOf("\\") + 1); 155 
156                 //创建文件
157  File file; 158                 if (map.get("chunks") != null) { 159                     file = new File(fileParent, map.get("chunk")); 160                 } else { 161                     file = new File(fileParent, "0"); 162  } 163 
164                 //copy
165  FileUtils.copyInputStreamToFile(item.getInputStream(), file); 166  item.getInputStream().close(); 167  } 168  } 169  } 170     /*** 171  * 删除文件夹 172      */
173     public  static void delFolder(String paths) { 174         try { 175             delAllFile(paths); // 删除完里面所有内容
176             String filePath = paths; 177             filePath = filePath.toString(); 178             File myFilePath = new File(filePath); 179             myFilePath.delete(); // 删除空文件夹
180         } catch (Exception e) { 181  e.printStackTrace(); 182  } 183  } 184     /*** 185  * 删除指定文件夹下所有文件 186  * @return
187      */
188     public static  boolean delAllFile(String paths) { 189         boolean flag = false; 190         //判断这个路径名是否存在
191         File file = new File(paths); 192         if (!file.exists()) { 193             return flag; 194  } 195         //是否是一个目录
196         if (!file.isDirectory()) { 197             return flag; 198  } 199         //返回由此抽象路径名所表示的目录中的文件和目录的名称所组成字符串数组。
200         String[] tempList = file.list(); 201         File temp = null; 202         for (int i = 0; i < tempList.length; i++) { 203             //paths是否以File.separator结束 方便不同平台下使用
204             if (paths.endsWith(File.separator)) { 205                 //取一个 删除一个 ...
206                 temp = new File(file + tempList[i]); 207             } else { 208                 //取一个 删除一个 ...
209                 temp = new File(file + File.separator + tempList[i]); 210  } 211             //是否是一个标准文件。
212             if (temp.isFile()) { 213                 //是的话删除
214  temp.delete(); 215                 flag = true; 216  } 217             //是否是一个目录,如果是的话先删除(delAllFile)目录下的文件,然后再删除空文件夹
218             if (temp.isDirectory()) { 219                 delAllFile(paths + "/" + tempList[i]);// 先删除文件夹里面的文件
220                 delFolder(paths + "/" + tempList[i]);// 再删除空文件夹
221                 flag = true; 222  } 223  } 224         return flag; 225  } 226 }

 

     webUploader.html

 1 <!DOCTYPE html>
 2 <html lang="en" xmlns:th="http://www.thymeleaf.org">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Upload Page</title>
 6     <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
 7     <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
 8 
 9     <script type="text/javascript" src="/upload/jquery-1.7.2.js"></script>
 10     <script type="text/javascript" src="/upload/webuploader.min.js"></script>
 11     <link href="/upload/webuploader.css" type="css/text" />
 12     <script type="text/javascript" src="/upload/jquery-2.0.0.min.js"></script>
 13     <script type="text/javascript" src="/upload/jquery-ui.js"></script>
 14     <link href="/upload/bootstrap.min.css" rel="stylesheet" media="screen">
 15     <script type="text/javascript" src="/upload/bootstrap.min.js"></script>
 16 
 17 </head>
 18 
 19 <body>
 20   <div style="margin: 22px 22px 22px 1px;">
 21       <div id="picker" class="form-control-focus">选择文件</div><br/>
 22       <p>允许上传文件类型:<b>.zip .dmp .rar .js .css .xml .7z .ico .pdf .ppt .pptx .xap .xpi .swf .apk .cdf .gif .tar .gz .sh .bmp .jpg</b><br />
 23       一次上传文件大小限制不小于:<b>50</b>MB</p>
 24 
 25       <table id="thelist" class="table table-bordered;uploader-list">
 26           <thead>
 27           <tr>
 28               <th>文件名</th>
 29               <th>文件大小</th>
 30               <th>状态</th>
 31               <th>操作</th>
 32           </tr>
 33           </thead>
 34       </table>
 35 
 36   </div>
 37   <button id="btnSync" type="button" class="btn btn-warning">开始同步</button>
 38 
 39 
 40 
 41 
 42 
 43   <script>
 44       var fileMd5;  //文件唯一标识
 45 
 46       /******************下面的参数是自定义的*************************/
 47       var fileName;//文件名称
 48       var oldJindu;//如果该文件之前上传过 已经上传的进度是多少
 49       var count=0;//当前正在上传的文件在数组中的下标,一次上传多个文件时使用
 50       var filesArr=new Array();//文件数组:每当有文件被添加进队列的时候 就push到数组中
 51       var map={};//key存储文件id,value存储该文件上传过的进度
 52  WebUploader.Uploader.register({  53               "before-send-file":"beforeSendFile",//整个文件上传前
 54               "before-send":"beforeSend",  //每个分片上传前
 55               "after-send-file":"afterSendFile",  //分片上传完毕
 56  },  57  {  58               //时间点1:所有分块进行上传之前调用此函数
 59  beforeSendFile:function(file){  60               // alert('----');
 61                   var deferred = WebUploader.Deferred();  62                   //1、计算文件的唯一标记fileMd5,用于断点续传 如果.md5File(file)方法里只写一个file参数则计算MD5值会很慢 所以加了后面的参数:10*1024*1024
 63                   (new WebUploader.Uploader()).md5File(file,0,10*1024*1024).progress(function(percentage){  64                       $('.'+file.id ).find('p.state').text('正在读取文件信息...');  65  })  66  .then(function(val){  67                           $('.'+file.id ).find("p.state").text("成功获取文件信息...");  68                           fileMd5=val;  69                           uploader.options.formData.guid = fileMd5;  70                           console.log("fileMd5:"+fileMd5);  71                           //获取文件信息后进入下一步
 72  deferred.resolve();  73  });  74 
 75                   fileName=file.name; //为自定义参数文件名赋值
 76                   return deferred.promise();  77  },  78               //时间点2:如果有分块上传,则每个分块上传之前调用此函数
 79  beforeSend:function(block){  80              // alert('-******-');
 81                   var deferred = WebUploader.Deferred();  82  $.ajax({  83                       type:"POST",  84                       url:"/uploader.do/loader",  //ajax验证每一个分片
 85  data:{  86  fileName : fileName,  87                           fileMd5:fileMd5,  //文件唯一标记
 88                           chunk:block.chunk,  //当前分块下标
 89                           chunkSize:block.end-block.start,//当前分块大小
 90  guid: uploader.options.formData.guid  91  },  92                       cache: false,  93                       async: false,  // 与js同步
 94                       timeout: 1000,  95                       dataType:"json",  96  success:function(response){  97                           console.log(block.chunk+"--"+response.ifExist);  98                           if(response.ifExist){  99                               //分块存在,跳过
100  deferred.reject(); 101                           }else{ 102                             // alert("ss11") 103                               //分块不存在或不完整,重新发送该分块内容
104  deferred.resolve(); 105  } 106  } 107  }); 108 
109                   this.owner.options.formData.fileMd5 = fileMd5; 110  deferred.resolve(); 111                   return deferred.promise(); 112  }, 113               //时间点3:所有分块上传成功后调用此函数
114  afterSendFile:function(){ 115                 // alert('-***2222**-'); 116                   //如果分块上传成功,则通知后台合并分块
117  $.ajax({ 118                       type:"POST", 119                       url:"${ctx}/mergeOrCheckChunks.do?param=mergeChunks",  //ajax将所有片段合并成整体
120  data:{ 121  fileName : fileName, 122  fileMd5:fileMd5, 123  }, 124  success:function(data){ 125                           count++; //每上传完成一个文件 count+1
126                           ;                      if(count<=filesArr.length-1){ 127                               uploader.upload(filesArr[count].id);//上传文件列表中的下一个文件
128  } 129                           //合并成功之后的操作
130  } 131  }) 132  } 133  }); 134       var uploader = WebUploader.create({ 135 
136           // swf文件路径
137           swf : 'upload/Uploader.swf', 138           // 文件接收服务端。
139           server : '/uploader.do/loader1', 140           // 选择文件的按钮。可选。 141           // 内部根据当前运行是创建,可能是input元素,也可能是flash.
142           pick : '#picker', 143           chunked: true,  //分片处理
144           chunkSize: 10 * 1024 * 1024, //每片5M
145           threads:3,//上传并发数。允许同时最大上传进程数。 146           // 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!
147           resize : false
148  }); 149 
150  function removeSection(e) { 151        // alert("当前第几行:"+e.parentElement.parentElement.rowIndex) 152           //alert("del:":+e.parentElement.parentElement.removeNode(true)) 153           //var a = e.parentElement.parentElement.rowIndex; 154           //var table=document.getElementById("thelist"); 155           //var objt = $(obj);.remove(); 156           // uploader.removeFile( file );
157           var tr=e.parentNode.parentNode; 158  tr.parentNode.removeChild(tr); 159           //e.parentNode.removeChild(e.parentElement.parentElement.rowIndex); 160           //table.deleteRow(e.parentElement.parentElement.rowIndex); 161           //alert(table) 162           //var len=table.rows.length; 163           //alert(len) 164           // alert("ss"+e.id+"==="+e.name) 165           // $(e).parents(e.id).remove(); 166           // $('[data-spy="scroll"]').each(function () { 167           // var $spy = $(this).scrollspy('refresh') 168           // });
169  } 170       // 当有文件被添加进队列的时候
171       uploader.on('fileQueued', function(file) { 172           // alert(file.size)
173           var fileName = file.name 174           if (fileName.indexOf('#') >= 0) { 175               alert('文件名中不能有井号'); 176               return false; 177  } 178           if (fileName.indexOf('+') >= 0) { 179               alert('文件名中不能有加号'); 180               return false; 181  } 182           if (fileName.indexOf(' ') >= 0) { 183               alert('文件名中不能有空格'); 184               return false; 185  } 186           var reg = /(\.zip|\.dmp|\.rar|\.js|\.css|\.xml|\.7z|\.ico|\.pdf|\.ppt|\.pptx|\.xap|\.xpi|\.swf|\.apk|\.cdf|\.gif|\.tar|\.gz|\.sh|\.bmp|\.jpg)$/ig; 187           if (!reg.test(fileName)) { 188               var supportType = reg.toString().replace(/\/|\(|\)|\\|/ig, ''); 189               supportType = supportType.substring(0, supportType.length - 3); 190               supportType = supportType.replace(/\|/g, ' '); 191               alert('不支持该上传文件类型!\n支持的文件类型:' + supportType); 192            // return false;
193  } 194           if (file.size < 50*1024*1024) 195  { 196               alert('上传文件大小不能小于' + 50 + 'MB'); 197             // return false;
198  } 199         // alert(123);
200           $("#thelist").append( 201               '<tr class="'+ file.id +'">'
202               +'<td ><h4 class="info">' + file.name + '</h4></td>'
203               +'<td><font face="宋体" size=3 color="red">'+ file.size +' </font>'+'字节'+'</td>'
204               +'<td id="' + file.id + '"><p class="state">等待上传...</p></td>'//onclick="removeSection(this);"
205               +'<td><input type="button" class="remove-this" name="sss" id="'+ file.id +'"  value="删除" class="btn btn-default"/></td>'
206               +'</tr>'); 207  }); 208 
209       uploader.on('uploadProgress', function(file,percentage) { 210 
211           var $li = $('#' + file.id), 212               $percent = $li.find('.progress .progress-bar'); 213 
214           // 避免重复创建
215           if (!$percent.length) { 216               $percent = $('<div id="' + file.id + '" class="progress progress-striped active">' +
217                   '<div class="progress-bar" style="height:20px; role="progressbar" style="width: 0%">' +
218                   '</div>' +
219                   '</div>').appendTo($li).find('.progress-bar'); 220  } 221 
222           $('.'+file.id ).find('p.state').text('上传中'); 223           $percent.css('width', percentage * 100 + '%'); 224  }); 225 
226       uploader.on('uploadSuccess', function(file) { 227           $('.' + file.id).find('p.state').text('已上传'); 228           $.post("/uploader.do/loader2", { "guid": uploader.options.formData.guid,fileName:file.name}, 229  function(data){ 230               }, "json"); 231  }); 232 
233       uploader.on('uploadError', function(file) { 234           $('.' + file.id).find('p.state').text('上传出错'); 235  }); 236 
237       uploader.on('uploadComplete', function(file) { 238           $('.' + file.id).find('.progress').fadeOut(); 239  }); 240 
241       uploader.on( 'beforeFileQueued', function( file ) { 242 
243        // alert(file.size);
244 
245  }); 246 
247       $("#btnSync").on('click', function() { 248           if ($(this).hasClass('disabled')) { 249               return false; 250  } 251           console.log("get fileMd5:"+fileMd5); 252 
253  uploader.upload(); 254 
255  }); 256   </script>
257 </body>
258 </html>

 

application.propertise

#文件分片上传关闭multipart,不然的话request被预编译,文件解析器解析请求为空
spring.servlet.multipart.enabled=false

 

 

 

 

遇到的问题:

list = upload.parseRequest(request);(74行) list为空
我用Meclipse可以,idea就不行了,很纳闷。
网上找了很多,知道request被预编译,但是说法大多数struts配置影响的还有一些其他方法,
看来下,卧槽,那么复杂,我这么lazy,算了,再找找其他的。
最后在一片博文找到了方法,在application.propertise中
关闭multipart,问题解决
spring.servlet.multipart.enabled=false


 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM