利用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

相关文章
相关标签/搜索