本文对如何实现使用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