使用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傳回的二進制數據,以后了再研究。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM