使用html5特性--ajax上传文件
在html5以前,ajax上传文件算是一个比较麻烦的事,要是想显示一下上传进度就更不容易。遇到这种情况往往需要借助于第三方插件,比如jquery.fileupload.js。如今html5已经技术已经变成一个非常流行、非常新潮的技术了,各个浏览器厂商也实现了不少的html5规范,如今文件上传有了html5的支持已经变的相当容易了,我自己尝试了一下用javascript原生的api来实现ajax上传文件,为了页面不至于太丑,我使用了bootstrap的一些组件,先上效果图:
实现的功能介绍:
- ajax无刷新上传
- 客户端限制单文件大小为400MB
- 支持多个文件上传
- 进度条显示上传进度
引用的类库:
- servlet3.0(需要使用tomcat7及以上版本的web服务器)
- bootstrap v3.3.2
- jquery 1.11
页面:
<!DOCTYPE html> <html> <head> <title>使用html5特性进行ajax上传</title> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="this is my page"> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <script type="text/javascript" src="js/jquery-1.11.2.min.js"></script> <script type="text/javascript" src="js/bootstrap.min.js"></script> <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"> <style type="text/css"> body{ padding:20px; } </style> <script type="text/javascript"> function upload(){ if(!window.FormData){ $("#msg").html("你的浏览器不支持。"); $(".alert").show(); } //获得原生的form表单对象,等价于document.forms[0] var form = document.getElementById("uploadForm"); //单个文件超过400MB就不再上传 var hasError = false; $("input[type=‘file‘]", form).each(function(index,file){ if(file.files.length > 0){ if(file.files[0].size > 400*1024*1024){ $("#msg").html("单个文件不能超过400MB。"); $(".alert").show(); hasError = true; return; } } }); if(hasError){ return; } //构造FormData对象用于发送数据 var formData = new FormData(form); var xhr = new XMLHttpRequest(); xhr.open("post", form.action, true); //设置请求超时 xhr.upload.timeout = 2000; xhr.upload.ontimeout = function (event){ $("#msg").html("请求超时!"); $(".alert").show(); }; //添加progress事件 xhr.upload.addEventListener("progress",function(e){ $(".progress-bar").addClass("active"); var howMuch = e.loaded / e.total; var p = parseFloat((howMuch * 100).toFixed(2))+"%"; $(".progress-bar").css("width",p).html(p); }, false); //上传完成 xhr.upload.addEventListener("load", function(event){ $(".progress-bar").removeClass("active"); $("#msg").html("上传完成!"); $(".alert").show(); }, false); xhr.upload.addEventListener("error", function(event){ $(".progress-bar").removeClass("active"); $("#msg").html("上传出错!"); $(".alert").show(); }, false); xhr.upload.addEventListener("abort", function(event){ $(".progress-bar").removeClass("active"); $("#msg").html("您取消了本次上传。"); $(".alert").show(); }, false); xhr.send(formData); } //重置 function test(){ $("input[type=‘file‘]", document.forms[0]).each(function(index,file){ file.value = null; }); } </script> </head> <body> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">文件上传</h3> </div> <div class="panel-body"> <div class="alert alert-danger alert-dismissable" style="display:none;"> <button type="button" class="close" onclick="$(‘.alert‘).hide();" aria-hidden="true"> × </button> <span id="msg"> 错误!请进行一些更改。</span> </div> <form id="uploadForm" action="/ajaxUpload/fileUpload" method="post" enctype="multipart/form-data"> <div class="input-group"> <span class="input-group-addon" id="basic-addon1">文件一</span> <input name="file1" type="file" class="form-control" aria-describedby="basic-addon1"> </div> <p></p> <div class="input-group"> <span class="input-group-addon" id="basic-addon2">文件二</span> <input id="file2" name="file2" type="file" class="form-control" aria-describedby="basic-addon2"> </div> <p></p> <div class="input-group"> <span class="input-group-addon" id="basic-addon3">文件三</span> <input name="file3" type="file" class="form-control" aria-describedby="basic-addon3"> </div> <p></p> <div class="progress"> <div class="progress-bar progress-bar-danger progress-bar-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" style="width: 0%"> 0% </div> </div> </form> <div style="text-align: center;"> <button type="button" onclick="upload()" class="btn btn-primary" autocomplete="off"> 上传 </button> <button type="button" onclick="test()" class="btn btn-primary" autocomplete="off"> 重置 </button> </div> </div> </div> </body> </html>
后台处理上传请求的servlet:
1 package com.test.servlet; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.util.List; 6 7 import javax.servlet.ServletException; 8 import javax.servlet.http.HttpServlet; 9 import javax.servlet.http.HttpServletRequest; 10 import javax.servlet.http.HttpServletResponse; 11 import javax.servlet.http.Part; 12 13 import org.apache.catalina.core.ApplicationPart; 14 15 public class FileUploadServlet extends HttpServlet { 16 17 /** 18 * 19 */ 20 private static final long serialVersionUID = 4796039742918723240L; 21 22 @Override 23 protected void doGet(HttpServletRequest req, HttpServletResponse resp) 24 throws ServletException, IOException { 25 26 } 27 28 @Override 29 protected void doPost(HttpServletRequest req, HttpServletResponse resp) 30 throws ServletException, IOException { 31 req.setCharacterEncoding("utf-8"); 32 List<Part> parts = (List<Part>) req.getParts(); 33 for (Part part : parts) { 34 ApplicationPart p = (ApplicationPart) part; 35 if(p.getSize() != 0){ 36 String fileName = p.getSubmittedFileName(); 37 part.write("c:\\"+fileName); 38 } 39 } 40 } 41 }
web.xml :
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="3.0" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 6 http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> 7 <display-name></display-name> 8 <welcome-file-list> 9 <welcome-file>index.jsp</welcome-file> 10 </welcome-file-list> 11 <servlet> 12 <servlet-name>fileUploadServlet</servlet-name> 13 <servlet-class>com.test.servlet.FileUploadServlet</servlet-class> 14 <multipart-config /> 15 </servlet> 16 <servlet-mapping> 17 <servlet-name>fileUploadServlet</servlet-name> 18 <url-pattern>/fileUpload</url-pattern> 19 </servlet-mapping> 20 </web-app>
用到的html5新特性:
FormData对象是XMLHttpRequest Level 2中新增的一个对象,它不但可以传文本文件,还可以传送二进制文件。它可以如下方式来构造:
var formData = new FormData();
还可以直接将一个form对象传进去来构造(比如我上面的例子):
var formData = new FormData(document.forms[0]); //构造完成后还可以动态添加表单元素 formData.append("yang","yangguo");//添加更多....
是不是很方便?
下面来介绍下XMLHttpRequest Level 2的XMLHttpRequest对象的新特性:
- 可以使用FormData上传二进制文件
- 可以设置 HTTP 请求的时限
- 可以获取服务器端的二进制数据(这个是ajax下载了,我们这里主要介绍上传)
- 可以获得上传/下载的进度(轻松实现进度条)
- 可以请求不同域名下的数据(跨域请求)
需要注意的是,如果是上传文件,使用的对象是xhr.upload对象,下载使用的对象xhr,不管是上传还是下载,与进度有关的事件如下:
- load 事件:传输成功完成。
- abort 事件:传输被用户取消。
- error 事件:传输中出现错误。
- loadstart 事件:传输开始。
- loadEnd 事件:传输结束,但是不知道成功还是失败。
- progress 事件:在传输期间持续不断触发直到传输完成。
我们这里用到load事件,传输完成后给用户提示信息:传输完成,我们还监听progress事件,通过progress事件上的事件对象event来获得传输数据进度:
1 //事件对象e 2 e.loaded //表示当前传输了多少个字节 3 e.total //表示当前传输的这个文件总共有多少个字节 4 //那么通过两数相除可以得到传输的百分比,保留小数点后两位有效数字 5 var howMuch = e.loaded / e.total; 6 var p = parseFloat((howMuch * 100).toFixed(2))+"%";
那么得到百分比我们就更新进度条就可以了。
XMLHttpRequest 2.0也添加了File API,通过File接口可以获得上传文件的大小,通过这个我们可以限制单个文件的大小。通过下面方式获得文件大小:
fileElement.files[0].size //文件大小,fileElement是一个<input type=‘file‘/>的DOM对象 //fileElement.files是一个FileList对象,因为只有第一个所以取第一个,为什么是个list呢,可能是支持拖拽式的文件上传拖拽多个文件进行上传
File继承自Blob,Blob代表一个不可更改的二进制文件对象(原文:A Blob
object represents a file-like object of immutable, raw data),File继承自Blob的属性Blob.size
和Blob.type,其属性都是只读属性,File.size表示文件的总字节数,其自身属性还有:
- File.lastModifiedDate 文件的修改时间
- File.name input标签的name属性
我们使用size属性取得文件占用的字节数和400MB比较,大于400MB就不上传,提示文件过大。
另外还有还添加的还有FileReader来处理ajax传回的二进制数据,以后了再研究。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。