ajax上传进度条
HTML5已经给出了上传时显示进度条的方案。
html5上传文件 XMLHttpRequest对象在html5中有了新的规范扩展( XMLHttpRequest Level 2 ),他包含了一些新的特性:
处理File, Blob 和 FormData对象上传下载时的字节流
上传下载时的处理进度事件
跨域请求
允许匿名请求
允许设置请求超时
html5的进度事件 根据html5的Progress Events 定义,进度事件中包含了以下信息
总传输大小
当前的已传输大小
上传文件大小是否已知 以上信息就可以计算出上传下载的进度。
实现 demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <!DOCTYPE html > <html > <head > <title > Upload Files using XMLHttpRequest - Minimal</title > </head > <body > <form id ="form1" enctype ="multipart/form-data" method ="post" action ="Upload.aspx" > <div class ="row" > <label for ="fileToUpload" > Select a File to Upload</label > <br /> <input type ="file" name ="fileToUpload" id ="fileToUpload" onchange ="fileSelected();" /> </div > <div id ="fileName" > </div > <div id ="fileSize" > </div > <div id ="fileType" > </div > <div class ="row" > <input type ="button" onclick ="uploadFile()" value ="Upload" /> </div > <div id ="progressNumber" > </div > </form > </body > </html >
<input type="file">标签的onchange事件绑定了js函数fileSelected() 每次用户通过浏览本地系统上的文件就会触发此事件。fileSelected()函数如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function fileSelected ( ) { var file = document .getElementById ('fileToUpload' ).files [0 ]; if (file) { var fileSize = 0 ; if (file.size > 1024 * 1024 ) fileSize = (Math .round (file.size * 100 / (1024 * 1024 )) / 100 ).toString () + 'MB' ; else fileSize = (Math .round (file.size * 100 / 1024 ) / 100 ).toString () + 'KB' ; document .getElementById ('fileName' ).innerHTML = 'Name: ' + file.name ; document .getElementById ('fileSize' ).innerHTML = 'Size: ' + fileSize; document .getElementById ('fileType' ).innerHTML = 'Type: ' + file.type ; } }
当有一个<input type="file"/>元素的变量引用,就能获得FileList的对象(html5中的定义 ),FileList对象包含了File对象的集合,每个File对象包含了如下属性:
name 文件的名称
type 文件的MIME type (全小写)
size文件的大小(byte单位)
有了这些信息就可以在前端做一些文件大小类型的限制判断。
当用户选择文件后,会通过点击上传按钮来上传文件,这里还要注意上传按钮onclick事件绑定了js函数uploadFile() 。uploadFile()函数如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 function uploadFile ( ) { var xhr = new XMLHttpRequest (); var fd = document .getElementById ('form1' ).getFormData (); xhr.upload .addEventListener ("progress" , uploadProgress, false ); xhr.addEventListener ("load" , uploadComplete, false ); xhr.addEventListener ("error" , uploadFailed, false ); xhr.addEventListener ("abort" , uploadCanceled, false ); xhr.open ("POST" , "UploadMinimal.aspx" ); xhr.send (fd); }
这里利用FormData对象来创建请求数据,使用XMLHttpRequest来发送请求,FormData实例是可以手动创建的
1 2 3 4 var fd = new FormData ();fd.append ("author" , "Shiv Kumar" ); fd.append ("name" , "Html 5 File API/FormData" ); fd.append ("fileToUpload" , document .getElementById ('fileToUpload' ).files [0 ]);
进度事件则是通过XMLHttpRequest的upload属性的addEventListener来设置的。
1 xhr.upload .addEventListener ("progress" , uploadProgress, false );
进度条事件处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 function uploadProgress (evt ) { if (evt.lengthComputable ) { var percentComplete = Math .round (evt.loaded * 100 / evt.total ); document .getElementById ('progressNumber' ).innerHTML = percentComplete.toString () + '%' ; } else { document .getElementById ('progressNumber' ).innerHTML = 'unable to compute' ; } } function uploadComplete (evt ) { alert (evt.target .responseText ); } function uploadFailed (evt ) { alert ("There was an error attempting to upload the file." ); } function uploadCanceled (evt ) { alert ("The upload has been canceled by the user or the browser dropped the connection." ); }
完整代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 <!DOCTYPE html > <html > <head > <title > Upload Files using XMLHttpRequest - Minimal</title > <script type ="text/javascript" > function fileSelected ( ) { var file = document .getElementById ('fileToUpload' ).files [0 ]; if (file) { var fileSize = 0 ; if (file.size > 1024 * 1024 ) fileSize = (Math .round (file.size * 100 / (1024 * 1024 )) / 100 ).toString () + 'MB' ; else fileSize = (Math .round (file.size * 100 / 1024 ) / 100 ).toString () + 'KB' ; document .getElementById ('fileName' ).innerHTML = 'Name: ' + file.name ; document .getElementById ('fileSize' ).innerHTML = 'Size: ' + fileSize; document .getElementById ('fileType' ).innerHTML = 'Type: ' + file.type ; } } function uploadFile ( ) { var fd = new FormData (); fd.append ("fileToUpload" , document .getElementById ('fileToUpload' ).files [0 ]); var xhr = new XMLHttpRequest (); xhr.upload .addEventListener ("progress" , uploadProgress, false ); xhr.addEventListener ("load" , uploadComplete, false ); xhr.addEventListener ("error" , uploadFailed, false ); xhr.addEventListener ("abort" , uploadCanceled, false ); xhr.open ("POST" , "UploadMinimal.aspx" ); xhr.send (fd); } function uploadProgress (evt ) { if (evt.lengthComputable ) { var percentComplete = Math .round (evt.loaded * 100 / evt.total ); document .getElementById ('progressNumber' ).innerHTML = percentComplete.toString () + '%' ; } else { document .getElementById ('progressNumber' ).innerHTML = 'unable to compute' ; } } function uploadComplete (evt ) { alert (evt.target .responseText ); } function uploadFailed (evt ) { alert ("There was an error attempting to upload the file." ); } function uploadCanceled (evt ) { alert ("The upload has been canceled by the user or the browser dropped the connection." ); } </script > </head > <body > <form id ="form1" enctype ="multipart/form-data" method ="post" action ="Upload.aspx" > <div class ="row" > <label for ="fileToUpload" > Select a File to Upload</label > <br /> <input type ="file" name ="fileToUpload" id ="fileToUpload" onchange ="fileSelected();" /> </div > <div id ="fileName" > </div > <div id ="fileSize" > </div > <div id ="fileType" > </div > <div class ="row" > <input type ="button" onclick ="uploadFile()" value ="Upload" /> </div > <div id ="progressNumber" > </div > </form > </body > </html >
下载demo 另外附上下载的demo: 前端页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 <input type ="text" id ="fileDownloadPath" style ="width: 1024px ;" /> <br > <button id ="uploadAsync" onclick ="downloadFileS()" > 异步下载</button > <button id ="uploadSync" onclick ="downloadFileA()" > 同步下载</button > <input type ="text" id ="processBar" > <br > <input type ="text" id ="tips" readonly > <script > function downloadFileS ( ) { var downloadInput = document .getElementById ('fileDownloadPath' ); var downloadPath = downloadInput.value ; if (downloadPath == null || downloadPath == '' ){ setTips ("请填写文件路径" ); return ; } var xhr = new XMLHttpRequest (); xhr.open ('GET' , "download?f=" + downloadPath, true ); xhr.onprogress = downloadProgress; xhr.responseType = "blob" ; xhr.onerror = function (e ) { setTips ("下载出错" ); }; xhr.onreadystatechange = function ( ) { if (xhr.readyState === 4 && xhr.status === 200 ) { console .log ("ready" ) var name = xhr.getResponseHeader ("Content-disposition" ); var filename = name.substring (20 ,name.length ); filename = filename.replace (/\"/g , "" ); var blob = new Blob ([xhr.response ], {type : 'application/x-msdownload' }); var u = URL .createObjectURL (blob); var link = document .createElement ('a' ); link.href = u; link.download = filename; link.click (); } }; xhr.send (); } function setTips (message ) { var tips = document .getElementById ('tips' ); tips.value = message; } function downloadFileA ( ) { var downloadInput = document .getElementById ('fileDownloadPath' ); var downloadPath = downloadInput.value ; if (downloadPath == null || downloadPath == '' ){ setTips ("请填写文件路径" ); return ; } window .location .href = "download?f=" + downloadPath; } function downloadProgress (evt ) { if (evt.lengthComputable ) { var percentComplete = Math .round ((evt.loaded ) * 100 / evt.total ); setTips (name + " 下载进度:" + percentComplete +" %" ); } } </script >
java服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 @GetMapping("/download") @ResponseBody public String download (@RequestParam(value = "f") String f,HttpServletResponse response, HttpServletRequest request) { if (!f.startsWith("/" )){ f = "/" + f; } String filePath = fileService.getRoot() + f; File destFile = new File (filePath); if (!destFile.exists() || !destFile.isFile()){ return "error" ; } response.setContentType("application/x-msdownload" ); response.setCharacterEncoding("UTF-8" ); String name = destFile.getName(); String postfix = name.substring(name.lastIndexOf("." )); if (request.getHeader("User-Agent" ).toLowerCase().indexOf("safari" ) >= 0 ) { response.setHeader("Content-Disposition" , "attachment;filename=\"" + new String (name.getBytes(Charset.forName("UTF-8" )), Charset.forName("ISO-8859-1" )) +"\"" ); } else { try { response.setHeader("Content-Disposition" , "attachment; filename=\"" + URLEncoder.encode(name, "utf-8" ) + "\"; filename*=utf-8''" + URLEncoder.encode(name, "utf-8" )); }catch (Exception e){ } } try { FileInputStream fis = new FileInputStream (destFile); BufferedOutputStream bos = new BufferedOutputStream (response.getOutputStream()); byte [] buffer = new byte [2048 ]; int readlength = 0 ; while ((readlength = fis.read(buffer)) != -1 ){ bos.write(buffer,0 ,readlength); } try { fis.close(); } catch (IOException e) { } try { bos.flush(); bos.close(); } catch (IOException e) { } }catch (Exception e){ return "exception: " + e.getMessage(); } return "success" ; }
参考 http://www.matlus.com/html5-file-upload-with-progress/