利用FormData進行ajax上傳文件

我的實現方式:javascript

html代碼php

<form id="uploadForm" class="smart-form" novalidate="novalidate" method="post" action="">
    {% csrf_token %}
    <div class="row">
	<section style="padding-left:15px;padding-right:15px;">
             <label class="label">請選擇上傳的配置文件<span><font size="3px" color="#FF0000">*</font></span></label>
	     <div class="input input-file">
                 <span class="button"><input type="file" id="uoload" name="uoload" onchange="this.parentNode.nextSibling.value = this.value">Browse</span><input type="text" readonly="">
	     </div>
        </section>
    </div>
    <footer style="height:30px">
         <button class="btn btn-primary" type="submit"> 確認保存 </button>
    </footer>
</form>

js代碼:css

$(document).ready(function() {
    //alert($("#file").parent().get(0).tagName); 
    var uploadForm = $("#uploadForm").validate({

        // Rules for form validation
        rules : {
            uoload :{
                required : true
	    }
        },
        // Messages for form validation
        messages : {
            uoload :{
                required : '上傳文件不能爲空'
            }
        },
        submitHandler: function(form){
            //若是不加[0]:Argument 1 of FormData.constructor does not implement interface HTMLFormElem
            //$('form') returns a jQuery object, but we need to pass a HTML element to FormData. `[0]` does that for us. It is the same as calling $('form').get(0)
            var fd = new FormData($("#uploadForm")[0]);
            //能夠傳額外的參數
            fd.append("CustomField", "This is some extra data");
            $.ajax({
                url: "/build/configAdd/",
                type: "POST",
                data: fd,
                processData: false,  // 告訴jQuery不要去處理髮送的數據
                contentType: false,   // 告訴jQuery不要去設置Content-Type請求頭
                error: function(msg) {
                    closeMyDialog($("#setAddId"));
                    showSuccessMsg("添加配置失敗");
                },
                success: function(msg){
                    closeMyDialog($("#setAddId"));
                    showSuccessMsg(msg);
                }
            });
        },
        // Do not change code below
        //modified by yf 2016_06_17
        errorPlacement : function(error, element) {
	    if("SPAN" == element.parent().get(0).tagName){
	        error.insertAfter(element.parent().next());
	        error.css("color","#D56161");
	        error.css("font-size","11px");
	        error.css("line-height","15px");
	        error.css("font-style","normal");
	    }else{
	        error.insertAfter(element.parent());
	    }
        }
    });

})

後臺python代碼html

@required_login(redirect="/build/login/")
@csrf_exempt
def configAddHandler(request):
    if request.method == "GET":
        return render(request, 'auto_config/configAdd.html')
    elif request.method == "POST":
        buf = request.FILES.get('uoload', None)
        if buf:
            f = buf.read()
            print type(f)
            BASE_DIR = os.path.dirname(__file__)
            #保存上傳的excel,以作歷史查詢
            try:
                save_file(BASE_DIR, str(buf), f)
                return HttpResponse("上傳成功")
            except:
                return HttpResponse("上傳失敗")
        else:
            return HttpResponse("上傳失敗")
def mkdir(path):
    # 去除左右兩邊的空格u
    path=path.strip()
    # 去除尾部 \符號
    path=path.rstrip("\\")
    if not os.path.exists(path):
        os.makedirs(path)
    return path
#工具函數,保存上傳的文件
def save_file(path, file_name, data):
    if data == None:
        return mkdir(path)
    if(not path.endswith("/")):
        path=path+"/"
    fileObj=open(path+file_name, "wb")
    fileObj.write(data)
    fileObj.flush()
    fileObj.close()

如下是引用的別人和官方的文章java

########################################################################python

用到兩個對象web

第一個對象:FormDataajax

第二個對象:XMLHttpRequest瀏覽器

目前新版的Firefox 與 Chrome 等支持HTML5的瀏覽器完美的支持這兩個對象,但IE9還沒有支持 FormData 對象,還在用IE6 ? 只能仰天長嘆....服務器

有了這兩個對象,咱們能夠真正的實現Ajax方式上傳文件。

示例代碼:
 

<!DOCTYPE html>

<html>

<head>

    <title>Html5 Ajax 上傳文件</title>

    <script type="text/javascript">


        function UpladFile() {


            var fileObj = document.getElementByIdx_x_x("file").files[0]; // 獲取文件對象

            var FileController = "../file/save";                    // 接收上傳文件的後臺地址 

           

            // FormData 對象

            var form = new FormData();

            form.append("author", "hooyes");                        // 能夠增長表單數據

            form.append("file", fileObj);                           // 文件對象


            // XMLHttpRequest 對象

            var xhr = new XMLHttpRequest();

            xhr.open("post", FileController, true);

            xhr.onload = function () {

                alert("上傳完成!");

            };

            xhr.send(form);


        }

</script>

</head>

<body>

<input type="file" id="file" name="myfile" />

<input type="button" onclick="UpladFile()" value="上傳" />

</body>

</html>

 

 

很簡潔的代碼,即可以達到Ajax方式上傳文件,上面的代碼中使用<input type="file" />這種傳統的選擇文件的方法產生文件對象,HTML5還支持使用多種更靈活的方式,如拖拽文件到指定的元素上產生。

Ajax已成功上傳文件,但這時咱們會想到一個問題,如何顯示進度條?帶着這個問題,腦子會想到,Flash? 瀏覽器插件?。

NO,如今不須要這些東西了。

開始着手,先作一個進度條,進度條也很簡單,使用HTML5 新加的標籤:

<progress id="progressBar" value="0" max="100"> </progress>

這個在瀏覽器中便會呈現了一個進度條,如今咱們要作的就是在上傳的時候,實時的去改變它的Value值,而後進度顯示的問題便交給它了。

咱們的服務器端無需修改,只須要在JS中XHR對象加一個事件。

xhr.upload.addEventListener("progress", progressFunction, false)


progressFunction 被調用的時候會傳進一個事件對象,這個對象有兩個屬性,一個就是loaded 一個是total ,分別表明,已上傳的值,和總要上傳的值。

這正是咱們須要的,因此這個方法,能夠這樣寫:

 

function progressFunction(evt) {

            var progressBar = document.getElementByIdx_x_x("progressBar");

            if (evt.lengthComputable) {

                progressBar.max = evt.total;      

                progressBar.value = evt.loaded;

               

            }

        }

 

這樣即可以完成,上傳進度顯示了。

以下針對上面的第一個示例代碼,作一個調整:

示例代碼2,帶進度顯示:

<!DOCTYPE html>

<html>

<head>

    <title>Html5 Ajax 上傳文件</title>

    <script type="text/javascript">

        function UpladFile() {

            var fileObj = document.getElementByIdx_x_x("file").files[0]; // js 獲取文件對象

            var FileController = "../file/save";                    // 接收上傳文件的後臺地址 


            // FormData 對象

            var form = new FormData();

            form.append("author", "hooyes");                        // 能夠增長表單數據

            form.append("file", fileObj);                           // 文件對象


            // XMLHttpRequest 對象

            var xhr = new XMLHttpRequest();

            xhr.open("post", FileController, true);

            xhr.onload = function () {

               // alert("上傳完成!");

            };

            xhr.upload.addEventListener("progress", progressFunction, false);

            

            xhr.send(form);


        }

        function progressFunction(evt) {

            var progressBar = document.getElementByIdx_x_x("progressBar");

            var percentageDiv = document.getElementByIdx_x_x("percentage");

            if (evt.lengthComputable) {

                progressBar.max = evt.total;

                progressBar.value = evt.loaded;

                percentageDiv.innerHTML = Math.round(evt.loaded / evt.total * 100) + "%";

            }

        }  

    </script>

</head>

<body>

    <progress id="progressBar" value="0" max="100">

    </progress>

    <span id="percentage"></span>

    <br />

    <input type="file" id="file" name="myfile" />

    <input type="button" onclick="UpladFile()" value="上傳" />

</body>

</html>

 

後臺接收文件的程序能夠是任何語言(C#,PHP,Python 等)編寫的,上述例子使用C#

很簡單,無需爲這個進度條作任何改動。

 

var flist = Request.Files;


            for (int i = 0; i < flist.Count; i++)

            {

                string FilePath = "E:\\hooyes\\Files\\";

                var c = flist[i];

                FilePath = Path.Combine(FilePath, c.FileName);

                c.SaveAs(FilePath);

            }

以上引用自:http://blog.sina.com.cn/s/blog_5d64f7e3010127ns.html

########################################################################

使用FormData對象

利用FormData對象,你可使用一系列的鍵值對來模擬一個完整的表單,而後使用XMLHttpRequest發送這個"表單".

建立一個FormData對象

你能夠先建立一個空的FormData對象,而後使用append()方法向該對象裏添加字段,以下:

var oMyForm = new FormData(); 

oMyForm.append("username", "Groucho"); 
oMyForm.append("accountnum", 123456); // 數字123456被當即轉換成字符串"123456" 

// fileInputElement中已經包含了用戶所選擇的文件 
oMyForm.append("userfile", fileInputElement.files[0]); 

var oFileBody = '<a id="a"><b id="b">hey!</b></a>'; // Blob對象包含的文件內容 
var oBlob = new Blob([oFileBody], { type: "text/xml"}); 

oMyForm.append("webmasterfile", oBlob); 

var oReq = new XMLHttpRequest(); 
oReq.open("POST", "http://foo.com/submitform.php"); 
oReq.send(oMyForm);

注: 字段"userfile"和"webmasterfile"的值都包含了一個文件.經過 FormData.append()方法賦給字段"accountnum"的數字被自動轉換爲字符(字段的值能夠是一個Blob對象,一個File對象,或者一個字符串,剩下其餘類型的值都會被自動轉換成字符串).

在該例子中,咱們建立了一個名爲oMyForm的FormData對象,該對象中包含了名爲"username", "accountnum", "userfile" 以及 "webmasterfile"的字段名,而後使用XMLHttpRequestsend()方法把這些數據發送了出去."webmasterfile"字段的值不是一個字符串,仍是一個Blob對象.

使用HTML表單來初始化一個FormData對象

能夠用一個已有的<form>元素來初始化FormData對象,只須要把這個form元素做爲參數傳入FormData構造函數便可:

var newFormData = new FormData(someFormElement);

例如:

var formElement = document.getElementById("myFormElement"); 
var oReq = new XMLHttpRequest(); 
oReq.open("POST", "submitform.php"); 
oReq.send(new FormData(formElement));

你還能夠在已有表單數據的基礎上,繼續添加新的鍵值對,以下:

var formElement = document.getElementById("myFormElement"); 
formData = new FormData(formElement); 
formData.append("serialnumber", serialNumber++); 
oReq.send(formData);

你能夠經過這種方式添加一些不想讓用戶編輯的固定字段,而後再發送.

使用FormData對象發送文件

你還可使用FormData來發送二進制文件.首先在HTML中要有一個包含了文件輸入框的form元素:

<form enctype="multipart/form-data" method="post" name="fileinfo"> 
    <label>Your email address:</label> 
    <input type="email" autocomplete="on" autofocus name="userid" placeholder="email" required size="32" maxlength="64" /><br /> 
    <label>Custom file label:</label> 
    <input type="text" name="filelabel" size="12" maxlength="32" /><br /> 
    <label>File to stash:</label> 
    <input type="file" name="file" required /> 
</form> 
<div id="output"></div> 
<a href="javascript:sendForm()">Stash the file!</a>

而後你就可使用下面的代碼來異步的上傳用戶所選擇的文件:

function sendForm() { 
    var oOutput = document.getElementById("output"); 
    var oData = new FormData(document.forms.namedItem("fileinfo")); 
    oData.append("CustomField", "This is some extra data"); 
    var oReq = new XMLHttpRequest(); oReq.open("POST", "stash.php", true); 
    oReq.onload = function(oEvent) { 
        if (oReq.status == 200) { 
            oOutput.innerHTML = "Uploaded!"; 
        } else { 
            oOutput.innerHTML = "Error " + oReq.status + " occurred uploading your file.<br \/>"; 
        } 
    }; 
    oReq.send(oData); 
}

你還能夠不借助HTML表單,直接向FormData對象中添加一個File對象或者一個Blob對象:

data.append("myfile", myBlob);

若是FormData對象中的某個字段值是一個Blob對象,則在發送http請求時,表明該Blob對象所包含文件的文件名的"Content-Disposition"請求頭的值在不一樣的瀏覽器下有所不一樣,Firefox使用了固定的字符串"blob,"而Chrome使用了一個隨機字符串.

你還可使用jQuery來發送FormData,但必需要正確的設置相關選項:

var fd = new FormData(document.getElementById("fileinfo")); 
fd.append("CustomField", "This is some extra data"); 
$.ajax({ 
    url: "stash.php", 
    type: "POST", 
    data: fd, 
    processData: false,// 告訴jQuery不要去處理髮送的數據 
    contentType: false // 告訴jQuery不要去設置Content-Type請求頭 
});

以上引用MDA,地址:https://developer.mozilla.org/zh-CN/docs/Web/Guide/Using_FormData_Objects

#########################################################################

經過傳統的form表單提交的方式上傳文件:

Html代碼

<form id= "uploadForm" action= "http://localhost:8080/cfJAX_RS/rest/file/upload" method= "post" enctype ="multipart/form-data"> 

    <h1 >測試經過Rest接口上傳文件 </h1>  

    <p >指定文件名: <input type ="text" name="filename" /></p>  

    <p >上傳文件: <input type ="file" name="file" /></p>  

    <p >關鍵字1: <input type ="text" name="keyword" /></p>  

    <p >關鍵字2: <input type ="text" name="keyword" /></p>  

    <p >關鍵字3: <input type ="text" name="keyword" /></p>  

    <input type ="submit" value="上傳"/> 

</form>

 

 

不過傳統的form表單提交會致使頁面刷新,可是在有些狀況下,咱們不但願頁面被刷新,這種時候咱們都是使用Ajax的方式進行請求的:
 

$.ajax({  

    url : "http://localhost:8080/STS/rest/user",  

    type : "POST",  

    data : $( '#postForm').serialize(),  

    success : function(data) {  

        $( '#serverResponse').html(data);  

    },  

    error : function(data) {  

        $( '#serverResponse').html(data.status + " : " + data.statusText + " : " + data.responseText);  

    }  

});

 

如上,經過$('#postForm').serialize()能夠對form表單進行序列化,從而將form表單中的全部參數傳遞到服務端。

 

可是上述方式,只能傳遞通常的參數,上傳文件的文件流是沒法被序列化並傳遞的。

不過現在主流瀏覽器都開始支持一個叫作FormData的對象,有了這個FormData,咱們就能夠輕鬆地使用Ajax方式進行文件上傳了。

 

 

關於FormData及其用法


FormData是什麼呢?咱們來看看Mozilla上的介紹。

XMLHttpRequest Level 2添加了一個新的接口FormData.利用FormData對象,咱們能夠經過JavaScript用一些鍵值對來模擬一系列表單控件,咱們還可使用XMLHttpRequest的send()方法來異步的提交這個"表單".比起普通的ajax,使用FormData的最大優勢就是咱們能夠異步上傳一個二進制文件. 

 

全部主流瀏覽器的較新版本都已經支持這個對象了,好比Chrome 7+、Firefox 4+、IE 10+、Opera 12+、Safari 5+。

 

參見:https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/FormData

 

 

這裏只展現一個經過from表單來初始化FormData的方式

<form enctype="multipart/form-data" method="post" name="fileinfo">

Js代碼
 

var oData = new FormData(document.forms.namedItem("fileinfo" ));  

oData.append( "CustomField", "This is some extra data" );  

var oReq = new XMLHttpRequest();  

oReq.open( "POST", "stash.php" , true );  

oReq.onload = function(oEvent) {  

    if (oReq.status == 200) {  

        oOutput.innerHTML = "Uploaded!" ;

    } else {  

        oOutput.innerHTML = "Error " + oReq.status + " occurred uploading your file.<br \/>";  

    }  

};  

oReq.send(oData);

 

參見:https://developer.mozilla.org/zh-CN/docs/Web/Guide/Using_FormData_Objects

 

 

使用FormData,進行Ajax請求並上傳文件


這裏使用JQuery,可是老版本的JQuery好比1.2是不支持的,最好使用2.0或更新版本:
 

<form id= "uploadForm">  

      <p >指定文件名: <input type="text" name="filename" value= ""/></p >  

      <p >上傳文件: <input type="file" name="file"/></ p>  

      <input type="button" value="上傳" onclick="doUpload()" />  

</form>

 

Js代碼

function doUpload() {  

     var formData = new FormData($( "#uploadForm" )[0]);  

     $.ajax({  

          url: 'http://localhost:8080/cfJAX_RS/rest/file/upload' ,  

          type: 'POST',  

          data: formData,  

          async: false,  

          cache: false,  

          contentType: false,  

          processData: false,  

          success: function (returndata) {  

              alert(returndata);  

          },  

          error: function (returndata) {  

              alert(returndata);  

          }  

     });  

}

以上引用自:http://yunzhu.iteye.com/blog/2177923

相關文章
相關標籤/搜索