web文件上传的几种方式
- 纯form表单提交
- 前端代码
- 后台代码
- 测试
- 运行后台springboot项目,打开前端form表单html
- 填写参数,选择文件,提交
- 踩的坑
- 使用FormData对象封装表单中的数据 XMLHttpRequest对象提交请求
- 前端代码
- 后台代码
- 注意事项
- 测试
- 使用google打开html页面
- 结果
- 后台运行结果
- 这种方式可行,就是注意需要处理跨域。参考:[https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects#Submitting_forms_and_uploading_files_via_AJAX_without_FormData_objects](https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects#Submitting_forms_and_uploading_files_via_AJAX_without_FormData_objects)
- 使用FormData对象封装表单中的数据 使用ajax提交请求
- 前端代码
- 后台代码
- 注意
- 使用FormoData 上传二进制文件 blob类型文件
- 前端代码
- 后台
- 测试
- 注意
- ==关于跨域的说明==
- 使用纯ajax提交文件数据
- ==web开发神器网站==
纯form表单提交
前端代码
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>上传文件</title>
</head>
<body>
<h1>纯form表单提交</h1>
<form action="http://192.168.8.175:8088/upload" enctype="multipart/form-data" method="post">
<label>参数1:</label>
<input type="text" name="firstParam" value="" size="12" maxlength="32" /><br />
<label>参数2:</label>
<input type="text" name="secondParam" value="" size="12" maxlength="32" /><br />
<label>File to stash:</label>
<input type="file" name="file" required />
<input type="submit" value="提交" />
</form>
<!--<input type="file" οnchange="fileChange()" /> -->
<script type="text/javascript">
</script>
</body>
</html>
== 注意事项 :==
后台代码
使用springboot搭建工程,编写接收文件上传的接口:
package com.xl.test.pluploader.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
@Controller
public class UploaderController {
@PostMapping(value = "upload")
@ResponseBody
public String upload(@RequestParam("file") MultipartFile file,String firstParam,String secondParam) throws Exception {
// doSomething
/*
* 这里写业务逻辑 :如对文件file的处理,保存文件等。。。
*/
String fileName = file.getOriginalFilename();
System.out.println(".....fileName= " + fileName);
long fileSzie = file.getSize();
System.out.println(".....fileSzie= " + fileSzie);
byte[] fileBts = file.getBytes();
System.out.println(".....fileBts= " + fileBts);
System.out.println(".....firstParam= " + firstParam);
System.out.println(".....secondParam= " + secondParam);
return "测试完成";
}
}
== 注意事项:==
测试
运行后台springboot项目,打开前端form表单html
填写参数,选择文件,提交
踩的坑
本来纯form表单上传的方式是最简单的,但是却花了最长的时间,原因是在写的过程中,在表单中开始忘记了添加enctype=“multipart/form-data”,然后报错:
org.springframework.web.multipart.MultipartException: Current request is not a multipart request
添加了enctype="multipart/form-data"
,还报这个错,奇怪了。。。耗时中。。。
很久之后才想起,清除浏览器缓存!,然后没问题了。
纯Form表单提交有个问题是:
上次文件完成之后无法接受后台服务器返回的数据,解决这个问题可以使用FormData对象封装数据,然后使用AJAX提交或者使用XMLHttpRequest对象提交。
使用FormData对象封装表单中的数据 XMLHttpRequest对象提交请求
前端代码
编写html
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>上传文件</title>
</head>
<body>
<h1>FormData封装数据 XMLHttpRequest提交请求数据</h1>
<form enctype="multipart/form-data" method="post" name="fileinfo">
<label>参数1:</label>
<input type="text" name="firstParam" size="12" maxlength="32" /><br />
<label>文件上传:</label>
<input type="file" name="file" required />
<input type="submit" value="提交" />
</form>
<div></div>
<script type="text/javascript">
var form = document.forms.namedItem("fileinfo");
form.addEventListener('submit', function(ev) {
var oOutput = document.querySelector("div"),
oData = new FormData(form);
// 也可通过append方法添加数据,FormData的类似方法可参考https://developer.mozilla.org/en-US/docs/Web/API/FormData
oData.append("secondParam", "这是第二个参数");
var oReq = new XMLHttpRequest();
oReq.open("POST", "http://localhost:8080/upload", true);
oReq.onload = function(oEvent) {
if (oReq.status == 200) {
// 其中类似responseText的属性可参考https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
alert(oReq.responseText);
// doSomething...
} else {
// doSomething...
}
};
oReq.send(oData);
ev.preventDefault();
}, false);
</script>
</body>
</html>
后台代码
package com.xl.uploadfile.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
@Controller
public class UploadController {
@PostMapping(value = "upload")
@ResponseBody
@CrossOrigin // 处理跨域
public String upload(@RequestParam("file") MultipartFile file, String firstParam, String secondParam)
throws Exception {
// public String test () {
// doSomething
/*
* 这里写业务逻辑 :如对文件file的处理,保存文件等。。。
*/
String fileName = file.getOriginalFilename();
System.out.println(".....fileName= " + fileName);
long fileSzie = file.getSize();
System.out.println(".....fileSzie= " + fileSzie);
byte[] fileBts = file.getBytes();
System.out.println(".....fileBts= " + fileBts);
System.out.println(".....firstParam= " + firstParam);
System.out.println(".....secondParam= " + secondParam);
return "测试完成";
}
}
注意事项
XMLHttpRequest对象提交请求时,涉及到跨域,所以后台使用@CrossOrigin
做了跨域请求处理。
测试
使用google打开html页面
输入数据,提交请求
结果
“测试完成” 是后台return "测试完成";
返回给页面的,html页面使用XMLHttpRequest对象的responseText属性接受。
后台运行结果
这种方式可行,就是注意需要处理跨域。参考:https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects#Submitting_forms_and_uploading_files_via_AJAX_without_FormData_objects
使用FormData对象封装表单中的数据 使用ajax提交请求
前端代码
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script src="jquery-3.5.1.min.js"></script>
<title>上传文件</title>
</head>
<body>
<h1>FormData封装数据 Ajax提交请求数据</h1>
<form id="formid" enctype="multipart/form-data" method="post" name="fileinfo">
<label>参数1:</label>
<input type="text" name="firstParam" size="12" maxlength="32" /><br />
<label>文件上传:</label>
<input type="file" name="file" required />
<input type="submit" value="提交0" />
</form>
<div></div>
<script type="text/javascript">
//监听表单提交,变为异步提交表单
$("#formid").on("submit", function(event){
var form = this;//this代表的就是当前提交表单的DOM对象
//用H5的FormData对象对表单数据进行构造
var formData = new FormData(form);//FormData构造器接收的是一个form的DOM对象
$.ajax({
url: "http://localhost:8080/upload",
type: "POST",
data: formData,
dataType: "JSON",
async: true,
//要想用jquery的ajax来提交FormData数据,
//则必须要把这两项设为false
processData: false,
contentType: false,
error: function(xhr,status,error){
alert("请求出错!");
},
success: function(result){
alert(result.msg);
}
});
//阻止表单的提交事件
return false;
});
</script>
</body>
</html>
后台代码
package com.xl.uploadfile.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
@Controller
public class UploadController {
@PostMapping(value = "upload")
@ResponseBody
@CrossOrigin
public String upload(@RequestParam("file") MultipartFile file, String firstParam, String secondParam)
throws Exception {
// public String test () {
// doSomething
/*
* 这里写业务逻辑 :如对文件file的处理,保存文件等。。。
*/
String fileName = file.getOriginalFilename();
System.out.println(".....fileName= " + fileName);
long fileSzie = file.getSize();
System.out.println(".....fileSzie= " + fileSzie);
byte[] fileBts = file.getBytes();
System.out.println(".....fileBts= " + fileBts);
System.out.println(".....firstParam= " + firstParam);
System.out.println(".....secondParam= " + secondParam);
return "{\"msg\": \"测试完成 \"}";
}
}
注意
- 需要引入jquery,这里使用的是`
- 后台同样需要处理跨域,
使用 @CrossOrigin
使用FormoData 上传二进制文件 blob类型文件
前端代码
编写一个html
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>使用FormoData 上传二进制文件 blob类型文件</title>
<h3>使用FormoData 上传二进制文件 blob类型文件</h3>
<form enctype="multipart/form-data" method="post" name="fileinfo">
<label>参数1:</label>
<input type="text" name="firstParam" value="" size="12" maxlength="32" /><br />
<!--<label>File to stash:</label>
<input type="file" name="file" required /> -->
<input type="submit" value="提交" />
</form>
<div></div>
<input type="file" onchange="fileChange()" />
<script type="text/javascript">
var blob = null;
var form = document.forms.namedItem("fileinfo");
form.addEventListener('submit', function(ev) {
var oOutput = document.querySelector("div"),
oData = new FormData(form); // 将表单中的数据封装到FormData对象中
oData.append("secondParam", "第二个参数内容"); //也可以通过FormData的append()方法添加参数。append()方法用法可参考https://developer.mozilla.org/en-US/docs/Web/API/FormData/append
oData.append("file", blob, "springboot.pdf"); // 将blob类型的文件封装到FormData对象中
var oReq = new XMLHttpRequest();
oReq.open("POST", "http://localhost:8088/upload", true);
oReq.onload = function(oEvent) {
if (oReq.status == 200) {
alert(oReq.responseText);
/*oOutput.innerHTML = "Uploaded!"; */
// doSomething...
} else {
// doSomething...
}
};
oReq.send(oData); // 使用XMLHttpRequest提交数据
ev.preventDefault();
}, false);
function fileChange() { // 将上传的文件转为 blob类型, 实际开发可根据具体业务 获取blob类型的文件数据
/*let e = e || window.event; */
var e = e || window.event;
let file = e.target.files[0];
let reader = new FileReader();
let rs = reader.readAsArrayBuffer(file);
/* let blob = null; */
reader.onload = (e) => {
if (typeof e.target.result === 'object') {
blob = new Blob([e.target.result])
} else {
blob = e.target.result
}
console.log(Object.prototype.toString.call(blob));
}
}
</script>
</body>
</html>
后台
package com.xl.test.pluploader.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
@Controller
public class UploaderController {
@PostMapping(value = "upload")
@ResponseBody
@CrossOrigin
public String upload(@RequestParam("file") MultipartFile file,String firstParam,String secondParam) throws Exception {
// doSomething
/*
* 这里写业务逻辑 :如对文件file的处理,保存文件等。。。
*/
String fileName = file.getOriginalFilename();
System.out.println(".....fileName= " + fileName);
long fileSzie = file.getSize();
System.out.println(".....fileSzie= " + fileSzie);
byte[] fileBts = file.getBytes();
System.out.println(".....fileBts= " + fileBts);
System.out.println(".....firstParam= " + firstParam);
System.out.println(".....secondParam= " + secondParam);
return "测试完成";
}
}
测试
注意
后台同样需要跨域处理
关于跨域的说明
MND官方说明:
Cross-site XMLHttpRequest
Modern browsers support cross-site requests by implementing the Cross-Origin Resource Sharing (CORS) standard. As long as the server is configured to allow requests from your web application's origin, XMLHttpRequest will work. Otherwise, an INVALID_ACCESS_ERR exception is thrown.
野鸡翻译:
由于现代浏览器都实现了Cross-Origin Resource Sharing (CORS) 标准,所以这些浏览器都是支持跨域的。只要你的服务器配置了允许跨域请求,XMLHttpRequest对象就能正常工作,否则,浏览器就会抛出INVALID_ACCESS_ERR异常。
使用纯ajax提交文件数据
前端代码
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Sending forms with pure AJAX – MDN</title>
<script type="text/javascript">
"use strict";
/*\
|*|
|*| :: XMLHttpRequest.prototype.sendAsBinary() Polyfill ::
|*|
|*| https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#sendAsBinary()
\*/
if (!XMLHttpRequest.prototype.sendAsBinary) {
XMLHttpRequest.prototype.sendAsBinary = function(sData) {
var nBytes = sData.length, ui8Data = new Uint8Array(nBytes);
for (var nIdx = 0; nIdx < nBytes; nIdx++) {
ui8Data[nIdx] = sData.charCodeAt(nIdx) & 0xff;
}
/* send as ArrayBufferView...: */
this.send(ui8Data);
/* ...or as ArrayBuffer (legacy)...: this.send(ui8Data.buffer); */
};
}
/*\
|*|
|*| :: AJAX Form Submit Framework ::
|*|
|*| https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest
|*|
|*| This framework is released under the GNU Public License, version 3 or later.
|*| https://www.gnu.org/licenses/gpl-3.0-standalone.html
|*|
|*| Syntax:
|*|
|*| AJAXSubmit(HTMLFormElement);
\*/
var AJAXSubmit = (function () {
function ajaxSuccess () {
/* console.log("AJAXSubmit - Success!"); */
console.log(this.responseText);
/* you can get the serialized data through the "submittedData" custom property: */
/* console.log(JSON.stringify(this.submittedData)); */
}
function submitData (oData) {
/* the AJAX request... */
var oAjaxReq = new XMLHttpRequest();
oAjaxReq.submittedData = oData;
oAjaxReq.onload = ajaxSuccess;
if (oData.technique === 0) {
/* method is GET */
oAjaxReq.open("get", oData.receiver.replace(/(?:\?.*)?$/,
oData.segments.length > 0 ? "?" + oData.segments.join("&") : ""), true);
oAjaxReq.send(null);
} else {
/* method is POST */
oAjaxReq.open("post", oData.receiver, true);
if (oData.technique === 3) {
/* enctype is multipart/form-data */
var sBoundary = "---------------------------" + Date.now().toString(16);
oAjaxReq.setRequestHeader("Content-Type", "multipart\/form-data; boundary=" + sBoundary);
oAjaxReq.sendAsBinary("--" + sBoundary + "\r\n" +
oData.segments.join("--" + sBoundary + "\r\n") + "--" + sBoundary + "--\r\n");
} else {
/* enctype is application/x-www-form-urlencoded or text/plain */
oAjaxReq.setRequestHeader("Content-Type", oData.contentType);
oAjaxReq.send(oData.segments.join(oData.technique === 2 ? "\r\n" : "&"));
}
}
}
function processStatus (oData) {
if (oData.status > 0) { return; }
/* the form is now totally serialized! do something before sending it to the server... */
/* doSomething(oData); */
/* console.log("AJAXSubmit - The form is now serialized. Submitting..."); */
submitData (oData);
}
function pushSegment (oFREvt) {
this.owner.segments[this.segmentIdx] += oFREvt.target.result + "\r\n";
this.owner.status--;
processStatus(this.owner);
}
function plainEscape (sText) {
/* How should I treat a text/plain form encoding?
What characters are not allowed? this is what I suppose...: */
/* "4\3\7 - Einstein said E=mc2" ----> "4\\3\\7\ -\ Einstein\ said\ E\=mc2" */
return sText.replace(/[\s\=\\]/g, "\\$&");
}
function SubmitRequest (oTarget) {
var nFile, sFieldType, oField, oSegmReq, oFile, bIsPost = oTarget.method.toLowerCase() === "post";
/* console.log("AJAXSubmit - Serializing form..."); */
this.contentType = bIsPost && oTarget.enctype ? oTarget.enctype : "application\/x-www-form-urlencoded";
this.technique = bIsPost ?
this.contentType === "multipart\/form-data" ? 3 : this.contentType === "text\/plain" ? 2 : 1 : 0;
this.receiver = oTarget.action;
this.status = 0;
this.segments = [];
var fFilter = this.technique === 2 ? plainEscape : escape;
for (var nItem = 0; nItem < oTarget.elements.length; nItem++) {
oField = oTarget.elements[nItem];
if (!oField.hasAttribute("name")) { continue; }
sFieldType = oField.nodeName.toUpperCase() === "INPUT" ? oField.getAttribute("type").toUpperCase() : "TEXT";
if (sFieldType === "FILE" && oField.files.length > 0) {
if (this.technique === 3) {
/* enctype is multipart/form-data */
for (nFile = 0; nFile < oField.files.length; nFile++) {
oFile = oField.files[nFile];
oSegmReq = new FileReader();
/* (custom properties:) */
oSegmReq.segmentIdx = this.segments.length;
oSegmReq.owner = this;
/* (end of custom properties) */
oSegmReq.onload = pushSegment;
this.segments.push("Content-Disposition: form-data; name=\"" +
oField.name + "\"; filename=\"" + oFile.name +
"\"\r\nContent-Type: " + oFile.type + "\r\n\r\n");
this.status++;
oSegmReq.readAsBinaryString(oFile);
}
} else {
/* enctype is application/x-www-form-urlencoded or text/plain or
method is GET: files will not be sent! */
for (nFile = 0; nFile < oField.files.length;
this.segments.push(fFilter(oField.name) + "=" + fFilter(oField.files[nFile++].name)));
}
} else if ((sFieldType !== "RADIO" && sFieldType !== "CHECKBOX") || oField.checked) {
/* NOTE: this will submit _all_ submit buttons. Detecting the correct one is non-trivial. */
/* field type is not FILE or is FILE but is empty */
this.segments.push(
this.technique === 3 ? /* enctype is multipart/form-data */
"Content-Disposition: form-data; name=\"" + oField.name + "\"\r\n\r\n" + oField.value + "\r\n"
: /* enctype is application/x-www-form-urlencoded or text/plain or method is GET */
fFilter(oField.name) + "=" + fFilter(oField.value)
);
}
}
processStatus(this);
}
return function (oFormElement) {
if (!oFormElement.action) { return; }
new SubmitRequest(oFormElement);
};
})();
</script>
</head>
<body>
<h1>Sending forms with pure AJAX 分以下几种情况</h1>
<h2>Using the GET method</h2> // 1、 GET方式请求
<form action="register.php" method="get" onsubmit="AJAXSubmit(this); return false;">
<fieldset>
<legend>Registration example</legend>
<p>
First name: <input type="text" name="firstname" /><br />
Last name: <input type="text" name="lastname" />
</p>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
</form>
<h2>Using the POST method</h2> //2 、 POST方式请求
<h3>Enctype: application/x-www-form-urlencoded (default)</h3>
<form action="register.php" method="post" onsubmit="AJAXSubmit(this); return false;">
<fieldset>
<legend>Registration example</legend>
<p>
First name: <input type="text" name="firstname" /><br />
Last name: <input type="text" name="lastname" />
</p>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
</form>
<h3>Enctype: text/plain</h3> // 3、编码类型为text/plain
<form action="register.php" method="post" enctype="text/plain"
onsubmit="AJAXSubmit(this); return false;">
<fieldset>
<legend>Registration example</legend>
<p>
Your name: <input type="text" name="user" />
</p>
<p>
Your message:<br />
<textarea name="message" cols="40" rows="8"></textarea>
</p>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
</form>
<h3>Enctype: multipart/form-data</h3> // 4、编码类型为multipart/form-data :上传文件
<form action="register.php" method="post" enctype="multipart/form-data"
onsubmit="AJAXSubmit(this); return false;">
<fieldset>
<legend>Upload example</legend>
<p>
First name: <input type="text" name="firstname" /><br />
Last name: <input type="text" name="lastname" /><br />
Sex:
<input id="sex_male" type="radio" name="sex" value="male" />
<label for="sex_male">Male</label>
<input id="sex_female" type="radio" name="sex" value="female" />
<label for="sex_female">Female</label><br />
Password: <input type="password" name="secret" /><br />
What do you prefer:
<select name="image_type">
<option>Books</option>
<option>Cinema</option>
<option>TV</option>
</select>
</p>
<p>
Post your photos:
<input type="file" multiple name="photos[]">
</p>
<p>
<input id="vehicle_bike" type="checkbox" name="vehicle[]" value="Bike" />
<label for="vehicle_bike">I have a bike</label><br />
<input id="vehicle_car" type="checkbox" name="vehicle[]" value="Car" />
<label for="vehicle_car">I have a car</label>
</p>
<p>
Describe yourself:<br />
<textarea name="description" cols="50" rows="8"></textarea>
</p>
<p>
<input type="submit" value="Submit" />
</p>
</fieldset>
</form>
</body>
</html>
web开发神器网站