功能使用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