使用html5特性--ajax上传文件

在html5以前,ajax上传文件算是一个比较麻烦的事,要是想显示一下上传进度就更不容易。遇到这种情况往往需要借助于第三方插件,比如jquery.fileupload.js。如今html5已经技术已经变成一个非常流行、非常新潮的技术了,各个浏览器厂商也实现了不少的html5规范,如今文件上传有了html5的支持已经变的相当容易了,我自己尝试了一下用javascript原生的api来实现ajax上传文件,为了页面不至于太丑,我使用了bootstrap的一些组件,先上效果图:

技术分享 

技术分享

实现的功能介绍:

  1. ajax无刷新上传
  2. 客户端限制单文件大小为400MB
  3. 支持多个文件上传
  4. 进度条显示上传进度

引用的类库:

  1. servlet3.0(需要使用tomcat7及以上版本的web服务器)
  2. bootstrap v3.3.2
  3. 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">
              &times;
           </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对象的新特性:

  1. 可以使用FormData上传二进制文件
  2. 可以设置 HTTP 请求的时限
  3. 可以获取服务器端的二进制数据(这个是ajax下载了,我们这里主要介绍上传)
  4. 可以获得上传/下载的进度(轻松实现进度条)
  5. 可以请求不同域名下的数据(跨域请求)

需要注意的是,如果是上传文件,使用的对象是xhr.upload对象,下载使用的对象xhr,不管是上传还是下载,与进度有关的事件如下:

  1.  load 事件:传输成功完成。
  2. abort 事件:传输被用户取消。
  3. error 事件:传输中出现错误。
  4. loadstart 事件:传输开始。
  5. loadEnd 事件:传输结束,但是不知道成功还是失败。
  6. 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表示文件的总字节数,其自身属性还有:

  1. File.lastModifiedDate 文件的修改时间
  2. File.name input标签的name属性

我们使用size属性取得文件占用的字节数和400MB比较,大于400MB就不上传,提示文件过大。

另外还有还添加的还有FileReader来处理ajax传回的二进制数据,以后了再研究。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。