FormData 是什么?附多文件上传案例

2022/4/29 6:13:15

本文主要是介绍FormData 是什么?附多文件上传案例,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

前言

前端上传数据时,必定会用 FormData 进行封装。FormData 是一种 key-value 的集合。发送数据时要考虑 FormData 中的数据都是什么格式的数据,即设置 content-type。

表单上传过程

这是一个表单的案例:

<form id="form" action="http://localhost:8080/upload/user/info" method="post">
	<input id="uname" type="text" name="uname" />
	<input id="pwd" type="password" name="pwd" />
	<input type="submit" value="Submit!" />
</form>

用户只需要点击最后一个 input,就可以提交所有表单里面的数据到服务器。这里什么 JS 代码都没有写,到底是如何做到的呢?

查阅 MDN 文档,实际上前端发送数据使用的是 XMLHttpRequest。表单数据通过 XMLHttpRequest.send() 请求特定 URL。XMLHttpRequest 在 AJAX 编程中被大量使用。XMLHttpRequest.send() 函数可以发送的数据类型有以下几种:

XMLHttpRequest.send();
XMLHttpRequest.send(ArrayBuffer data);
XMLHttpRequest.send(ArrayBufferView data);
XMLHttpRequest.send(Blob data);
XMLHttpRequest.send(Document data);
XMLHttpRequest.send(DOMString? data);
XMLHttpRequest.send(FormData data);

表单使用这个函数发送数据的,那又是哪一个参数类型的函数呢?其实就是最后一个函数。继续往下看,FormData 是什么?

FormData

FormData 是用来表示表单数据的键值对集合。表单其实就是一个 Map 集合,但是,直接用 Map 作为 XMLHttpRequest.send() 的发送数据是不合适的。因为,发送之前要做很多封装工作。所以,就出现一个新的概念——FormData。

FormData 可以被当做是一个 Map 来对待,它也有和 Map 类似的函数,例如:get、entries。

作用

有了 FormData,我们可以自定义发送表单数据,可以添加表单没有设置的一项数据。使用 AXIOS 或 AJAX,可以轻松地、自由地把表单数据发送出去。

set()

FormData 提供一个 set(name, value) 函数。它可以添加数据到 FormData 中。而 name 相当于一个表单中属性名为 name 的 input,value 就是用户在 input 中输入的数据。

<input id="uname" type="text" name="uname" />

这个 input 标签用 FormData 表示就是:

let formData = new FormData();
formData.set('hobbies', ['football', 'animation', 'cycling']);
formData.get('hobbies');

image

append()

append(name, value) 也可以添加数据到 FormData 中。

formData.append('hobbies', ['football', 'animation', 'cycling']);
formData.get('hobbies');

image

append() 和 set()

append 和 set 都可以添加数据到 FormData 中。但是实际使用中有着很大的区别,下面将通过实验来证明。

(一)set

formData.set('hobbies', 'football');
console.log(`第一次 value:${formData.getAll('hobbies')}`);
formData.set('hobbies', 'animation');
console.log(`第二次 value:${formData.getAll('hobbies')}`);

image

(二)append

formData.append('hobbies', 'football');
console.log(`第一次 value:${formData.getAll('hobbies')}`);
formData.append('hobbies', 'animation');
console.log(`第二次 value:${formData.getAll('hobbies')}`);

image

通过实验证明,如果第二次添加的 key 与第一次的 key 是相同的,set 会覆盖第一次 value 中的数据;append 会追加到 value 之后。

案例:多文件上传

前端

多文件上传的前端使用 Vue3 框架。首先,引入 Vue3 和 Axios。

<script src="https://unpkg.com/vue@next"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

因为 FormData 就是用来描述一个表单的,所以,在 html 中甚至都不需要 form 标签。

<div id="app">
	<input @change="selected($event)" type="file" multiple />
	<button @click="submit">提交</button>
</div>

下面是完整的 Vue3 代码:

Vue.createApp({
	data() {
		return {
			files: []
		};
	},
	methods: {
		selected(e) {
			this.files = e.target.files;
		},
		submit() {
			let formData = new FormData();
			for (let index in this.files) {
				formData.append(`files`, this.files[index]);
			}
			axios.post('http://localhost:8080/upload/files', formData, {
				headers: {
					'content-type': 'multipart/form-data'
				}
			});
		}
	}
}).mount('#app');

(1)当用户选择了文件之后,input 会触发 change 事件,Vue3 使用$event接收事件的数据。(2)当用户点击提交按钮之后,首先构造一个 FormData 对象。然后把所有的文件对象存放到 FormData 中,因为是多文件,可以用 append 添加一个 key 为 files 的;value 为数组类型的键值对数据。(3)通过 axios.post() 提交数据给后端处理,并且指定 content-type 是 multipart/form-data 格式。

后端

@RequestMapping(value = "/upload/files", consumes = "multipart/form-data")
public void uploadFiles(@RequestBody MultipartFile[] files) {
	System.out.println(files[0].getOriginalFilename());
	System.out.println(files[1].getOriginalFilename());
}

前端发送过来的数据是一个数组,一个元素对应一个 MultipartFile。files 一定要和前端 FormData.append() 当中的 name 对应。

打印结果:

content-type

application/x-www-form-urlencoded

表单的默认的 content-type 是 application/x-www-form-urlencoded;charset=UTF-8。对于这样的 content-type,接口只能通过 @RequestParam 来接收这些数据。

@RequestMapping(value = "/upload/user/info", method = RequestMethod.POST, consumes = "application/x-www-form-urlencoded;charset=UTF-8")
public void uploadUserInfo(@RequestParam(name = "uname") String uname, @RequestParam(name = "pwd") String pwd) {
	System.out.println("uname: " + uname + ", pwd: " + pwd);
}

multipart/form-data



这篇关于FormData 是什么?附多文件上传案例的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程