文件上传,很常见的功能。
SpringBoot
配置
# 是否开启文件上传
spring.servlet.multipart.enabled=true
# 文件大小阈值,当大于这个阈值时将写入到磁盘(临时目录),否则存在内存中
spring.servlet.multipart.file-size-threshold=0B
# IO文件的临时目录
spring.servlet.multipart.location=
# 单个文件最大大小
spring.servlet.multipart.max-file-size=1MB
# 整个请求体最大大小
spring.servlet.multipart.max-request-size=10MB
# 是否延迟解析multipart请求
spring.servlet.multipart.resolve-lazily=false
Controller
使用MultipartFile
作为文件的接收参数,如果有多个同名的文件参数,那么可以使用数组或者List
。
import java.io.IOException;
import java.nio.file.Paths;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("/upload")
public class UploadController {
private static final Logger LOGGER = LoggerFactory.getLogger(UploadController.class);
@PostMapping
public Object test (@RequestParam("files") MultipartFile[] files) {
for (MultipartFile file : files) {
// 文件的原始名称
String originalFilename = file.getOriginalFilename();
// 文件的大小
long size = file.getSize();
// 文件的ContentType
String contentType = file.getContentType();
LOGGER.info("originalFilename={}, size={}, contentType={}", originalFilename, size, contentType);
try {
// 序列化到磁盘
file.transferTo(Paths.get("D:\\upload", originalFilename));
} catch (IllegalStateException | IOException e) {
e.printStackTrace();
}
}
return "ok";
}
}
浏览器上传
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>文件上传</title>
</head>
<body>
<input type="file"
accept="image/*"
multiple="multiple"
onchange="fileChange(event);"/>
</body>
<script type="text/javascript">
function fileChange(event) {
// 获取到FileList对象,它不是数组,可迭代
const files = event.target.files;
if (!files){
// 未选择文件
return ;
}
const formData = new FormData();
for (const file of files){
// 文件的名字
const name = file.name;
// 最后修改的时间戳
const lastModified = file.lastModified;
// 最后修改的本地时间
const lastModifiedDate = file.lastModifiedDate;
// 文件的绝对路径
const webkitRelativePath = file.webkitRelativePath;
// 文件的大小
const size = file.size;
// 文件的类型
const contentType = file.type;
// 添加文件到formData
formData.append('files', file);
}
const xhr = new XMLHttpRequest();
xhr.open('POST','/upload',true);
// 监听上传进度
if(xhr.upload){
xhr.upload.addEventListener('progress', event => {
let percent = (event.loaded / event.total) * 100;
percent = percent.toFixed(2);
console.log(`上传进度:${percent}`)
}, false);
}
xhr.send(formData);
xhr.onreadystatechange = event => {
if(event.target.readyState == 4 && event.target.status == 200){
// 获取服务器的响应
const responseBody = xhr.responseText;
console.log(`服务器响应:${responseBody}`);
}
}
}
</script>
</html>
<input/>
的属性
-
type
设置当前输入框是文件选择框 -
accept
允许选择的文件类型 -
multiple
允许一次选择多个文件 -
onchange
监听选择文件的变化
FormData不能直接append(FileList)
在上传多个文件的时候,也许你以为这样更省事儿
const files = event.target.files;
const formData = new FormData();
formData.append('files', files);
实际行不通,append
方法不支持FileList
参数,只能自己一个个的append
,否则FormData
不能正确的进行编码。
除了append
以外FormData
还有一个set
方法。
const formData = new FormData();
formData.set('files', files);
区别:set
是覆盖,append
是添加。