pom.xml中需要有指定springboot的版本
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.8.0</version>
</dependency>
使用了springboot自带的文件上传,没有使用commons-fileupload,所以这里不引入,引入commons-io是使用IOUtils工具类。
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
application.properties
#springboot2.X开启文件上传与大小限制
spring.servlet.multipart.enabled=true
#表示上传的单个文件的最大大小,默认为 1MB
spring.servlet.multipart.max-file-size=1024MB
#表示多文件上传时文件的总大小,默认为 10MB
spring.servlet.multipart.max-request-size=1024MB
#表示文件写入磁盘的阀值,默认为 0
spring.servlet.multipart.file-size-threshold=0
#表示上传文件的临时保存位置
#spring.servlet.multipart.location=E:\\test\\temp
#表示文件是否延迟解析,默认为 false
spring.servlet.multipart.resolve-lazily=false
一、上传页面
thymeleaf的单文件上传页面:signleupload.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>SpringBoot 单文件上传页面</title>
</head>
<body>
<form method="post" action="/fileupload/signleupload" enctype="multipart/form-data">
文件:<input type="file" name="file"><br>
姓名:<input type="text" name="name"/><br>
<input type="submit" value="上传"><br>
</form>
</body>
</html>
thymeleaf的多文件上传页面:mutliupload.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>SpringBoot 多文件上传页面</title>
</head>
<body>
<form method="post" action="/fileupload/mutliupload" enctype="multipart/form-data">
文件1:<input type="file" name="file"><br>
文件2:<input type="file" name="file"><br>
文件3:<input type="file" name="file"><br>
<input type="submit" value="上传"><br>
</form>
</body>
</html>
2、文件上传控制器
FileUploadController.java
package com.imddysc.monitor.controller;
import java.io.File;
import java.io.FileOutputStream;
import java.time.LocalDate;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
@Controller
@RequestMapping("/fileupload")
public class FileUploadController {
private static final Logger logger = LoggerFactory.getLogger(FileUploadController.class);
@Value("${upload.rootdir}")
private String uploaddir;
// /opt/upload
@RequestMapping("/signleupload")
public String signleUpload(HttpServletRequest request, @RequestParam("file") MultipartFile file) {
String result = "";
// 判断文件是否为空
if (!file.isEmpty()) {
try {
// 文件保存路径
String filePath = uploaddir + "/"+ LocalDate.now().toString() +"/"+ file.getOriginalFilename();
logger.info("filePath: " + filePath);
File localFile = new File(filePath);
if(!localFile.getParentFile().exists()) {
localFile.getParentFile().mkdirs();
localFile.createNewFile();
}
/** 第一种,通过byte[] file.getBytes(),FileUtils直接把bytes数组写入对应文件李 */
byte[] bytes1 = file.getBytes();
String filePath1 = uploaddir + "/"+ LocalDate.now().toString() +"/"+ file.getOriginalFilename()+".1";
logger.info("filePath1: " + filePath1);
logger.info("byte[]: " + new String(bytes1, "UTF-8"));
logger.info("filegetName: " + file.getName());
FileUtils.writeByteArrayToFile(new File(filePath1), bytes1);
logger.info("FileUtils.writeByteArrayToFile 已经执行!");
/** 第二种,通过IOUtils通过流拷贝到新的文件中去 */
String filePath2 = uploaddir + "/"+ LocalDate.now().toString() +"/"+ file.getOriginalFilename()+".2";
logger.info("filePath2: " + filePath2);
IOUtils.copy(file.getInputStream(),new FileOutputStream(filePath2));
logger.info("IOUtils.copy 已经执行!");
/** 第三种,转存文件,直接这样使用会报异常 */
file.transferTo(localFile);
result = "文件上传成功";
} catch (Exception e) {
result = "文件上传异常";
e.printStackTrace();
}
} else {
result = "文件为空";
}
return result;
}
@RequestMapping("/mutliupload")
public String mutliUpload(HttpServletRequest request, @RequestParam("file") MultipartFile[] files) {
String result = "";
StringBuilder stringBuilder = new StringBuilder();
for (MultipartFile file : files) {
try {
// 文件保存路径
String filePath = uploaddir + "/"+ LocalDate.now().toString() +"/"+ file.getOriginalFilename();
File localFile = new File(filePath);
if(!localFile.getParentFile().exists()) {
localFile.getParentFile().mkdirs();
}
/** 转存文件,需使用第1,2两种方式来,直接使用 transferTo会有问题 */
file.transferTo(localFile);
} catch (Exception e) {
stringBuilder.append(file.getOriginalFilename() + " 上传失败!");
e.printStackTrace();
}
}
if(StringUtils.isEmpty(stringBuilder.toString())) {
result = "上传成功!";
} else {
result = stringBuilder.toString();
}
return result;
}
@RequestMapping("/index.html")
public String index() {
return "fileupload/index";
}
@RequestMapping("/signleupload.html")
public String signleupload() {
return "fileupload/signleupload";
}
@RequestMapping("/mutliupload.html")
public String mutliupload() {
return "fileupload/mutliupload";
}
}
java.io.IOException: java.io.FileNotFoundException:
dest 是相对路径,指向 upload/doc20170816162034_001.jpg
file.transferTo 方法调用时,判断如果是相对路径,则使用temp目录,为父目录
因此,实际保存位置为 C:\Users\xxxx\AppData\Local\Temp\tomcat.372873030384525225.8080\work\Tomcat\localhost\ROOT\upload\doc20170816162034_001.jpg
所以改为:使用第1和第2种方式,可以保证文件上传,如果直接使用file.transferTo会有文件不存在的异常。
还由一个解决方法是file.transferTo()的目标文件可以先new File(xxxx/xxxx/xxx).getAbsolutePath();这样也是获取的觉得路径,windowns绝对路径C:\\xx ,D:\\xx 开头,linux绝对路径以 /xx/xxx/开头。
@Value("${file.upload.path}")
private String path = "upload/";
String fileName = file.getOriginalFilename();
File dest = new File(new File(path).getAbsolutePath()+ "/" + fileName);
file.transferTo(dest); // 保存文件
个人觉得如果是在确认目标文件后,可以直接使用IOUtils.copy进行流拷贝,即第二种方案,第一种只适合小文件,占内存,file.transferTo内部也是流拷贝。也不麻烦。
https://blog.csdn.net/SummerX_Z_Y/article/details/107807184
https://blog.csdn.net/qq_44343988/article/details/107826498
接收不到文件的写法
--html
var files = document.getElementById('myFile').files;
var formData = new FormData();
formData.append('file', files);
这样写,后台的
@RequestParam("file")MultipartFile[] file
file始终是获取不到文件的
正确写法
--html
for(i=0; i < files.length; i++){
formData.append('file', files[i]);
}
---下载---
response.addHeader("Content-Type", "application/octet-stream");
response.addHeader("Content-Disposition", "attachment; filename=\"" + new String(fileName.getBytes("UTF-8"), "ISO-8859-1") + "\".xlsx;filename*=UTF-8''" + new String(fileName.getBytes("UTF-8"), "ISO-8859-1"));
//1.设置文件ContentType类型,这样设置,会自动判断下载文件类型
response.setContentType("multipart/form-data");
//2.设置文件头:最后一个参数是设置下载文件名(假如我们叫a.pdf)
response.setHeader("Content-Disposition", "attachment;fileName="+"a.pdf");
application/force-download
@RequestMapping(value = "/weChatDown/{fileId}")
public ResponseEntity<byte[]> weChatFiledownload(@PathVariable("fileId") String fileId, HttpServletResponse response, HttpServletRequest request) throws Exception {
DsCmsFile dsCmsFile = fileService.get(fileId);
if (dsCmsFile != null) {
String filePath = dsCmsFile.getFileUrl();
String fileName = dsCmsFile.getFileName();
File file = new File(filePath);
long size = file.length();
//为了解决中文名称乱码问题 这里是设置文件下载后的名称
fileName = new String(fileName.getBytes("UTF-8"), "iso-8859-1");
response.reset();
response.setHeader("Accept-Ranges", "bytes");
//设置文件下载是以附件的形式下载
response.setHeader("Content-disposition", String.format("attachment; filename=\"%s\"", fileName));
response.addHeader("Content-Length", String.valueOf(size));
ServletOutputStream sos = response.getOutputStream();
FileInputStream in = new FileInputStream(file);
BufferedOutputStream outputStream = new BufferedOutputStream(sos);
byte[] b = new byte[1024];
int i = 0;
while ((i = in.read(b)) > 0) {
outputStream.write(b, 0, i);
}
outputStream.flush();
sos.close();
outputStream.close();
in.close();
}
return new ResponseEntity<>(HttpStatus.OK);
}