点击上方蓝色字体,关注我们
上传文件是互联网中应用的场景之一,最典型的情况就是上传头像。文件上传主要是将文件通过IO流传输到服务器的某一个特定的文件夹下。
Why->MultipartFile?解析源码:
public interface MultipartFile extends InputStreamSource {
}
public class MockMultipartFile extends Object implements MultipartFile implements MultipartFile, Serializable {
}
public class CommonsMultipartFile implements MultipartFile, Serializable {
}
public interface MultipartFile extends InputStreamSource {
}
通过源码可以看出 MultipartFile是一个接口,这个接口的实现类有 CommonsMultipartFile,MockMultipartFile,MultipartFile继承InputStreamSource这个接口。
MultipartFile
--String getName() //返回表单中file文件参数name的名称。
--String getOriginalFilename() // 文件原名称
--String getContentType() //返回文件的内容类型。
--boolean isEmpty() // 返回上传的文件是否为空,即,在多部分表单中没有选择任何文件,或者所选文件没有内容。
--long getSize() // 以字节为单位返回文件的大小。
--byte[] getBytes() //将文件的内容作为字节数组返回。
--InputStream getInputStream() //返回一个InputStream以从中读取文件的内容。
--void transferTo(File dest) //将收到的文件传输到给定的目标文件。
参考官网地址
https://docs.spring.io/spring/docs/current/javadoc-
api/org/springframework/web/multipart/MultipartFile.html
开始搭建环境jdk1.8,引入了spring-boot-starter-thymeleaf做页面模板引擎。
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<optional>trueoptional>
dependency>
dependencies>
application.properties配置文件
#thymeleaf
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=LEGACYHTML5
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.content-type=text/html
# 禁用 thymeleaf 缓存
spring.thymeleaf.cache=false
# 上传文件总的最大值
spring.servlet.multipart.max-request-size=10MB
# 单个文件的最大值
spring.servlet.multipart.max-file-size=10MB
# 是否支持批量上传 (默认值 true)
spring.servlet.multipart.enabled=true
# 上传文件的临时目录 (一般情况下不用特意修改)
spring.servlet.multipart.location=
# 文件大小阈值,当大于这个阈值时将写入到磁盘,否则存在内存中,(默认值0 一般情况下不用特意修改)
spring.servlet.multipart.file-size-threshold=0
# 判断是否要延迟解析文件(相当于懒加载,一般情况下不用特意修改)
spring.servlet.multipart.resolve-lazily=false
常见问题:
1、表单method设置为post,并将enctype设置为multipart/form-data。
2、html中name值要和@RequestParam("file")中的值保持一致。
3、上传文件大小spring.http.multipart.max-file-size限制,如果上传的文件超过设置的值会出现这个错误。
这个错误是因为Spring文件上传重置问题,这个异常是捕获不到,需要Tomcat的默认连接器 maxSwallowSize 的参数。
<Connector port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443"maxSwallowSize="-1" />
并在上传前实现Javascript检查文件大小。
单文件上传
单文件上传html页面
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>单文件上传title>
head>
<body>
<p>单文件上传p>
<form method="POST" enctype="multipart/form-data" action="/upload" >
文件:<input type="file" name="file"/>
<input type="submit"/>
form>
<hr/>
body>
创建FileUploadController中的upload方法 (单文件上传)
@PostMapping("/upload")
@ResponseBody
public String upload(@RequestParam("file") MultipartFile file) {
//判断非空
if (file.isEmpty()) {
return "上传的文件不能为空";
}
try {
// 测试MultipartFile接口的各个方法
logger.info("[文件类型ContentType] - [{}]",file.getContentType());
logger.info("[文件组件名称Name] - [{}]",file.getName());
logger.info("[文件原名称OriginalFileName] - [{}]",file.getOriginalFilename());
logger.info("[文件大小] - [{}]",file.getSize());
logger.info(this.getClass().getName()+"图片路径:"+path);
File f = new File(path);
// 如果不存在该路径就创建
if (!f.exists()) {
f.mkdir();
}
File dir = new File(path + file.getOriginalFilename());
// 文件写入
file.transferTo(dir);
return "上传单个文件成功";
} catch (Exception e) {
e.printStackTrace();
return "上传单个文件失败";
}
}
注:这里除了transferTo方法,也可以用字节流的方式上传文件,但是字节流比较慢,所以还是建议用transferTo,下面这个方法是封装的一个用字节流写入文件的方法。
public void writeFile(MultipartFile file) {
try {
//获取输出流
OutputStream os = new FileOutputStream(path + file.getOriginalFilename());
//获取输入流 CommonsMultipartFile 中可以直接得到文件的流
InputStream is = file.getInputStream();
byte[] buffer = new byte[1024];
//判断输入流中的数据是否已经读完的标识
int length = 0;
//循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
while((length = is.read(buffer))!=-1){
//使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中
os.write(buffer, 0, length);
}
os.flush();
os.close();
is.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
操作步骤
单文件上传完成啦,接下来就是多文件上传和文件下载。
多文件上传
html页面
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>多文件上传title>
head>
<body>
<p>多文件上传p>
<form method="POST" enctype="multipart/form-data" action="/uploadBatch">
<p>文件1:<input type="file" name="file"/>p>
<p>文件2:<input type="file" name="file"/>p>
<p><input type="submit" value="上传"/>p>
form>
body>
html>
uploadBatch方法
@PostMapping("/uploadBatch")
@ResponseBody
public String uploadBatch(@RequestParam("files") MultipartFile[] files) {
logger.info("文件名称:"+ files );
if(files!=null&&files.length>0){
String filePath = "D:\\datafile\\";
for (MultipartFile mf : files) {
// 获取文件名称
String fileName = mf.getOriginalFilename();
// 获取文件后缀
String suffixName = fileName.substring(fileName.lastIndexOf("."));
// 重新生成文件名
fileName = UUID.randomUUID()+suffixName;
if (mf.isEmpty()) {
return "文件名称:"+ fileName +"上传失败,原因是文件为空!";
}
File dir = new File(filePath + fileName);
try {
// 写入文件
mf.transferTo(dir);
logger.info("文件名称:"+ fileName +"上传成功");
} catch (IOException e) {
logger.error(e.toString(), e);
return "文件名称:"+ fileName +"上传失败";
}
}
return "多文件上传成功";
}
return "上传文件不能为空";
}
操作步骤
常见问题
The field file exceeds its maximum permitted size of 1048576 bytes.
这个错误是由于springboot默认的文件大小是1MB造成的,当上传文件超过1MB时就会报错。解决这个报错可以在application.properties中设置上传参数,参数项是默认的,我们设置最大上传文件大小不超过10MB,再次上传会成功。
文件下载方法
@GetMapping("/downloadfile")
@ResponseBody
public String downloadFile(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
String fileName = "大话设计模式(带目录完整版).pdf";// 文件名
if (fileName != null) {
//设置文件路径
File file = new File("D:\\datafile\\大话设计模式(带目录完整版).pdf");
//File file = new File(realPath , fileName);
if (file.exists()) {
response.setContentType("multipart/form-data");
response.setHeader("Content-Disposition", "attachment; fileName="+ fileName +";filename*=utf-8''"+ URLEncoder.encode(fileName,"UTF-8"));
byte[] buffer = new byte[1024];
FileInputStream fis = null;
BufferedInputStream bis = null;
try {
fis = new FileInputStream(file);
bis = new BufferedInputStream(fis);
OutputStream os = response.getOutputStream();
int i = bis.read(buffer);
logger.info(""+i);
while (i != -1) {
os.write(buffer, 0, i);
i = bis.read(buffer);
}
return "下载成功";
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
return "文件不存在";
}
在下载文件时,中文文件名称会出现乱码问题,需要设置一下即可。
response.setHeader("Content-Disposition", "attachment; fileName="+ fileName +";filename*=utf-8''"+ URLEncoder.encode(fileName,"UTF-8"));
总结下载的html页面我就不复制啦,一个Spring Boot 上传和下载文件的简单 Demo 就完成了,感兴趣的同学可以将示例代码下载下来试试吧。
GitHub:
https://github.com/xiaonongOne/springboot-upload