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