本文對如何實現使用Ajax提交"multipart/form"格式的表單數據,已經如何在圖片上傳之前,在瀏覽器上進行預覽。使用的主要相關技術HTML5的FILE API,XMLHttprequest Level2中對二進制文件上傳的支持(通過構建FormData對象進行支持)以及Servlet 3.0支持的Multiconfig注解來支持文件的上傳。在Servlet 3.0 規范之前通常使用第三方庫如commons-fileupload進行解決文件上傳。
- HTML5 中的 File 對象和FileReader對象
html5中標簽<input type="file" id="imageFile" name="imageFile" multiple>可以設置multiple屬性,可以選取多個文件,並且對HTML DOM模型提供支持,如var imageFile=document.getElementById("imageFile").files[0];document.getElementById("imageFile")返回的文件對象數組,這是由於支持multiple屬性,因此我們即使沒有設置這一屬性,也得通過獲取數組的第一個元素,才能獲取該文件表示的File對象啊。在Jquery中可以var image=$("#imageFile").get(0).files[0];或者var image=$("#imageFile")[0].files[0]來獲取對象。
這一File對象我們可以獲取其中的文件名,MIME類型,大小等等信息。
通過FileReader對象,可以對File對象進行讀取,顯示等等。FileReader的讀取操作為異步讀取,因此我們得通過設置相關的事件處理程序,才能對讀取的數據進行處理。
- 事件處理程序
onabort | 當讀取操作被中止時調用. |
onerror | 當讀取操作發生錯誤時調用. |
onload | 當讀取操作成功完成時調用. |
onloadend | 當讀取操作完成時調用,不管是成功還是失敗. 該處理程序在onload或者onerror之后調用. |
onloadstart | 當讀取操作將要開始之前調用. |
onprogress | 在讀取數據過程中周期性調用. |
- 方法概述
void abort() | 中止該讀取操作.在返回時,readyState屬性的值為DONE. |
void readAsArrayBuffer(in Blob blob) | 開始讀取指定的Blob對象或File對象中的內容.當讀取操作完成時,readyState屬性的值會成為DONE, 如果設置了onloadend事件處理程序,則調用.如果設置了onload事件處理程序,則在讀取成功后調用. 同時,result屬性中將包含一個ArrayBuffer對象以表示所讀取文件的內容. |
void readAsBinaryString(in Blob blob) | 開始讀取指定的Blob對象或File對象中的內容. 當讀取操作完成時,readyState屬性的值會成為DONE, 如果設置了onloadend事件處理程序,則調用之.同時,result屬性中將包含所讀取文件的原始二進制數據. |
void readAsDataURL(in Blob blob) | 開始讀取指定的Blob對象或File對象中的內容. 當讀取操作完成時,readyState屬性的值會成為DONE, 如果設置了onloadend事件處理程序,則調用之.同時,result屬性中將包含一個data: URL格式的字符串以表示所讀取文件的內容. |
void readAsText(in Blob blob, [optional] in DOMString encoding) | 開始讀取指定的Blob對象或File對象中的內容. 當讀取操作完成時,readyState屬性的值會成為DONE, 如果設置了onloadend事件處理程序,則調用之.同時,result屬性中將包含一個字符串以表示所讀取的文件內容.encoding 可選 |
- 實現圖片預覽功能代碼如下:由於需要在瀏覽器顯示圖像因此采用FileReader的 readAsDataURL接口。
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <script type="text/javascript" src="js/jquery-1.12.0.js"></script> <script type="text/javascript" src="js/bootstrap.js"></script> <link href="css/bootstrap.css" rel="stylesheet"> <title>Insert title here</title> <script> $(document).ready(function() { $("#imageFile").change(function() { var fileReader = new FileReader(); fileReader.onload = function(e) { $("#previewImage").append("<span class='center-block text-success'>圖像預覽</span><image class='img-thumbnail' style='max-width:400px;height:auto;' src="+e.target.result+"/>"); } var imageFile = this.files[0]; fileReader.readAsDataURL(imageFile); }); $("#send") .click( function() { var xhr=new XMLHttpRequest(); xhr.open("post","fileUpload"); xhr.onreadystatechange = function() { if (xhr.readyState == 4) { if(xhr.status == 200){ alert("圖片上傳成功"); }else{ alert("圖片上傳失敗") } } }; var imageFile = $("#imageFile")[0].files[0]; var username=$("#username").val(); var myForm = new FormData(); myForm.append("username",username); myForm.append("imageFile", imageFile); xhr.send(myForm); }); }); </script> </head> <body> <div class="container"> <div class="panel"> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">圖像上傳和預覽測試</h3> </div> <div class="panel-body"> <p id="previewImage"></p> <form action="fileUpload" enctype="multipart/form-data" method="post" class="form-inline"> <div class="form-group"> <label for="username">用戶名</label> </div> <div class="form-group"> <input type="text" id="username" name="username" /> </div> <div class="form-group"> <label for="imageFile">上傳圖片</label> </div> <div class="form-group"> <input type="file" id="imageFile" name="imageFile" accept="image/jpeg" /> </div> <button type="button" id="send" class="btn btn-primary">上傳</button> </form> </div> </div> </div> </div> </body> </html>
- 實現Ajax圖片上傳,對於form數據的提交有成熟的jquery插件jquery.form.js可以實現ajax提交,並且對不支持FormData對象的瀏覽器進行支持。本文的實現方法僅對支持HTML5中的FormData瀏覽器使用。
服務端代碼實現,在Servlet 3.0 規范中提供了@MultiConfig這一注解對需要處理"multipart/form"數據類型提交的Servlet進行支持,並且在通過HttServletRequest中的getParts()和getPart(String name)獲取上傳文件;Servlet 3.0之前則需要下載如commons-fileupload的第三方庫進行支持,本文使用這一注解,Tomcat 7及以上版本對Servlet 3.0支持。實現代碼如下:
@MultipartConfig(location="/", fileSizeThreshold=1024*102, maxFileSize=1024*1024*5, maxRequestSize=1024*1024*5*5) @WebServlet(urlPatterns={"/fileUpload"},loadOnStartup=1) public class FileUpload extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub request.setCharacterEncoding("UTF-8"); String fileName=request.getParameter("username")+new Date().getTime()+".jpg"; Part part=request.getPart("imageFile"); part.write(fileName); response.setContentType("application/json;charset=utf-8"); String s="{\"result\":\"success\"}"; response.getWriter().print(s); } }
- 客戶端的Ajax上傳實現如下,使用FormData進行構建,FormData中的append的方法可以添加二進制和文本數據。二進制數據直接通過獲取File對象既可,如:
var formData=new FormData(); formData.append("username",username);formData.append("image",image);
實現代碼如下:
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <script type="text/javascript" src="js/jquery-1.12.0.js"></script> <script type="text/javascript" src="js/bootstrap.js"></script> <link href="css/bootstrap.css" rel="stylesheet"> <title>Insert title here</title> <script> $(document).ready(function() { $("#imageFile").change(function() { var fileReader = new FileReader(); fileReader.onload = function(e) { $("#previewImage").append("<span class='center-block text-success'>圖像預覽</span><image class='img-thumbnail' style='max-width:400px;height:auto;' src="+e.target.result+"/>"); } var imageFile = this.files[0]; fileReader.readAsDataURL(imageFile); }); $("#send") .click( function() { var xhr=new XMLHttpRequest(); xhr.open("post","fileUpload"); xhr.onreadystatechange = function() { if (xhr.readyState == 4) { if(xhr.status == 200){ alert("圖片上傳成功"); }else{ alert("圖片上傳失敗") } } }; var imageFile = $("#imageFile")[0].files[0]; var username=$("#username").val(); var myForm = new FormData(); myForm.append("username",username); myForm.append("imageFile", imageFile); xhr.send(myForm); }); }); </script> </head> <body> <div class="container"> <div class="panel"> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">圖像上傳和預覽測試</h3> </div> <div class="panel-body"> <p id="previewImage"></p> <form action="fileUpload" enctype="multipart/form-data" method="post" class="form-inline"> <div class="form-group"> <label for="username">用戶名</label> </div> <div class="form-group"> <input type="text" id="username" name="username" /> </div> <div class="form-group"> <label for="imageFile">上傳圖片</label> </div> <div class="form-group"> <input type="file" id="imageFile" name="imageFile" accept="image/jpeg" /> </div> <button type="button" id="send" class="btn btn-primary">上傳</button> </form> </div> </div> </div> </div> </body> </html>
- 項目(在tomcat8 運行,如果在tomcat 7運行需要將web.xml文件中的dtd聲明替換為tomcat 7版本所需的聲明)相關源碼查看:https://github.com/jintaocai/testcode/tree/master/jsptest