我的实现方式: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
对象,你可使用一系列的键值对来模拟一个完整的表单,而后使用XMLHttpRequest
发送这个"表单".
你能够先建立一个空的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"的字段名,而后使用XMLHttpRequest
的send()
方法把这些数据发送了出去."webmasterfile"字段的值不是一个字符串,仍是一个Blob
对象.
能够用一个已有的<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
来发送二进制文件.首先在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添加了一个新的接口
全部主流浏览器的较新版本都已经支持这个对象了,好比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); } }); }