SpringBoot(十八) 文件上传下载

在企业级项目开发过程中,上传文件是最常用到的功能。SpringBoot集成了SpringMVC,当然上传文件的方式跟SpringMVC没有什么出入。

构建项目

添加依赖

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<dependencies>
<!-- Web 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- 单元测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<!--thymeleaf模板引擎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>

配置文件

application.yml

1
2
3
4
spring:
thymeleaf:
# 关闭缓存
cache: false

关于webapp文件夹

由于我们使用的路径是
String uploadDir = request.getSession().getServletContext().getRealPath("/") + "upload/";
创建webapp才能看到效果。

创建webapp

上传文件时,如果创建webapp文件夹,上传的文件会在该目录下创建 upload 文件夹和上传的文件。

1
F:\JetBrains\IdeaProjects\SpringBoot\put\springboot2-18\src\main\webapp\upload/

不创建webapp

上传文件时,如果没有创建webapp文件夹,会将文件上传到临时tomcat 目录下并创建 upload 文件夹和上传的文件。

1
C:\Users\Ray\AppData\Local\Temp\tomcat-docbase.1694442458760825778.8080\upload/

上传单个文件

HTML

添加一个简单的form表单,并且修改enctype=”multipart/form-data”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传示例</title>
</head>
<body>
单个文件上传:
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit" value="上传"/>
</form>
</body>
</html>

Controller

添加初始化index.jsp页面方法以及上传文件的方法/upload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
* @author Ray
* @date 2018/8/4 0004
* 上传文件控制器
*/
@Controller
public class UploadController {

/**
* 跳转到index
*/
@GetMapping(value = "/index")
public String index(){
return "index";
}

/**
* 单个文件上传
*/
@PostMapping(value = "/upload")
@ResponseBody
public String upload(HttpServletRequest request, MultipartFile file){
try {
// 上传目录地址(相对路径)
String uploadDir = request.getSession().getServletContext().getRealPath("/") + "upload/";
// 上传目录地址(绝对路径)
// String uploadDir = "f:/test/";
// 输出地址 - 测试
System.out.println(uploadDir);
File dir = new File(uploadDir);
// 如果目录不存在,自动创建文件夹
if(!dir.exists()){
dir.mkdir();
}
// 上传文件名
String filename = file.getOriginalFilename();
// 服务器端保存的文件对象
File serverFile = new File(uploadDir + filename);
// 将上传的文件写入到服务器端文件内
file.transferTo(serverFile);
}catch (Exception e){
// 打印错误堆栈信息
e.printStackTrace();
return "上传失败";
}
return "上传成功";
}
}

我们使用MultipartFile 对象内置的方法transferTo() 就可以实现页面上传到request内的文件对象直接存储到指定文件File对象内,以此来完成上传文件的存储。

测试单文件上传



自定义文件名

一般情况下我们不会使用上传时文件的名字作为存储在服务器端的名字,一般都会采用UUID或者时间戳的形式来保存,下面我们修改下代码使用UUID来作为文件名称,修改代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
    /**
* 单个文件上传
*/
@PostMapping(value = "/upload")
@ResponseBody
public String upload(HttpServletRequest request, MultipartFile file){
try {
// 上传目录地址(相对路径)
String uploadDir = request.getSession().getServletContext().getRealPath("/") + "upload/";
// 上传目录地址(绝对路径)
// String uploadDir = "f:/test/";
// 输出地址 - 测试
System.out.println(uploadDir);
File dir = new File(uploadDir);
// 如果目录不存在,自动创建文件夹
if(!dir.exists()){
dir.mkdir();
}
// 上传文件名 - 原名
// String filename = file.getOriginalFilename();
// 文件后缀名
String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
// 上传文件名 - UUID
String filename = UUID.randomUUID() + suffix;
// 服务器端保存的文件对象
File serverFile = new File(uploadDir + filename);
// 将上传的文件写入到服务器端文件内
file.transferTo(serverFile);
}catch (Exception e){
// 打印错误堆栈信息
e.printStackTrace();
return "上传失败";
}
return "上传成功";
}

测试


可以看到我们新创建的文件名称就是采用了随机UUID的形式命名的,还有一种使用时间戳,一般都是微毫秒作为文件名,这里不做解释了,(微毫秒获取方式:System.nanoTime() )。

上传多个文件

上面单个文件已经是可以上传成功了,那么我们来讲解下多个文件上传。

修改HTML界面

对index.html 简单修改,添加一个多文件上传的表单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传示例</title>
</head>
<body>
单个文件上传:
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit" value="上传"/>
</form>

<hr>

多个文件上传:
<form action="/uploads" method="post" enctype="multipart/form-data">
文件1 : <input type="file" name="files" /><br/>
文件2 : <input type="file" name="files" /><br/>
文件3 : <input type="file" name="files" /><br/>
<input type="submit" value="上传"/>
</form>
</body>
</html>

修改控制器

在UploadController控制器,添加 /uploads 方法,并提取单个上传文件的方法为公共方法

提取公共方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    /**
* 提取上传方法为公共方法
*/
private void executeUpload(String uploadDir, MultipartFile file) throws IOException {
// 上传文件名 - 原名
// String filename = file.getOriginalFilename();
// 文件后缀名
String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
// 上传文件名 - UUID
String filename = UUID.randomUUID() + suffix;
// 服务器端保存的文件对象
File serverFile = new File(uploadDir + filename);
// 将上传的文件写入到服务器端文件内
file.transferTo(serverFile);
}

多个文件上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* 多个文件上传
*/
@PostMapping(value = "/uploads")
@ResponseBody
public String uploads(HttpServletRequest request, MultipartFile[] files){
try{
// 上传目录地址
String uploadDir = request.getSession().getServletContext().getRealPath("/") + "upload/";
// 输出地址 - 测试
System.out.println(uploadDir);
System.out.println("共" + files.length + "个文件");
File dir = new File(uploadDir);
// 如果目录不存在,自动创建文件夹
if(!dir.exists()){
dir.mkdir();
}
// 遍历文件数组执行上传
for (int i = 0; i < files.length; i++){
if(files[i] != null){
// 调用上传方法
executeUpload(uploadDir, files[i]);
}
}
}catch (Exception e){
// 打印错误堆栈信息
e.printStackTrace();
return "上传失败";
}
return "上传成功";
}

测试单文件上传


修改上传限制


SpringBoot上传文件时限制了我们上传文件大小为:1MB
那我们需要上传超过配置的文件时修改怎么做呢?

修改配置文件

1
2
3
4
5
6
7
8
9
10
11
spring:
thymeleaf:
# 关闭缓存
cache: false

servlet:
multipart:
# 单个文件最大
max-file-size: 5MB
# 设置总上传数据总大小
max-request-size: 10MB

修改了上传文件的最大限制容量为5Mb,最大的请求容量为10Mb。

下载单个文件

修改HTML界面

html 页面包含一个下载按钮

1
2
3
4
单个文件下载:
<form action="/downloadFile">
<input type="submit" value="下载">
</form>

修改控制器

下载系统中指定文件 f:/test/2.jpg

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 下载文件
*/
@GetMapping(value = "/downloadFile")
public void downloadFile(HttpServletResponse response) throws IOException {
// 文件所在的路径
File file = new File("f:/test/2.jpg");
// 使用response 获取字节输出
OutputStream outputStream = response.getOutputStream();
// 进行文件下载
response.setContentType("application/x-download");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Disposition", "attachment;filename=" + new String(("下载名称").getBytes("gbk"), "iso8859-1") + ".jpg");
// outputStream 写入到输出流
outputStream.write(FileCopyUtils.copyToByteArray(file));
// 刷新流
outputStream.flush();
// 关闭流
outputStream.close();
}

完整示例

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传下载示例</title>
</head>
<body>
单个文件上传:
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit" value="上传"/>
</form>

<hr>

多个文件上传:
<form action="/uploads" method="post" enctype="multipart/form-data">
文件1 : <input type="file" name="files" /><br/>
文件2 : <input type="file" name="files" /><br/>
文件3 : <input type="file" name="files" /><br/>
<input type="submit" value="上传"/>
</form>


<hr>

单个文件下载:
<form action="/downloadFile">
<input type="submit" value="下载">
</form>
</body>
</html>

Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/**
* @author Ray
* @date 2018/8/4 0004
* 上传文件控制器
*/
@Controller
public class UploadController {

/**
* 跳转到index
*/
@GetMapping(value = "/index")
public String index(){
return "index";
}

/**
* 单个文件上传
*/
@PostMapping(value = "/upload")
@ResponseBody
public String upload(HttpServletRequest request, MultipartFile file){
try {
// 上传目录地址(相对路径)
String uploadDir = request.getSession().getServletContext().getRealPath("/") + "upload/";
// 上传目录地址(绝对路径)
// String uploadDir = "f:/test/";
// 输出地址 - 测试
System.out.println(uploadDir);
File dir = new File(uploadDir);
// 如果目录不存在,自动创建文件夹
if(!dir.exists()){
dir.mkdir();
}
//调用上传方法
executeUpload(uploadDir, file);
}catch (Exception e){
// 打印错误堆栈信息
e.printStackTrace();
return "上传失败";
}
return "上传成功";
}

/**
* 多个文件上传
*/
@PostMapping(value = "/uploads")
@ResponseBody
public String uploads(HttpServletRequest request, MultipartFile[] files){
try{
// 上传目录地址
String uploadDir = request.getSession().getServletContext().getRealPath("/") + "upload/";
// 输出地址 - 测试
System.out.println(uploadDir);
System.out.println("共" + files.length + "个文件");
File dir = new File(uploadDir);
// 如果目录不存在,自动创建文件夹
if(!dir.exists()){
dir.mkdir();
}
// 遍历文件数组执行上传
for (int i = 0; i < files.length; i++){
if(files[i] != null){
// 调用上传方法
executeUpload(uploadDir, files[i]);
}
}
}catch (Exception e){
// 打印错误堆栈信息
e.printStackTrace();
return "上传失败";
}
return "上传成功";
}

/**
* 提取上传方法为公共方法
*/
private void executeUpload(String uploadDir, MultipartFile file) throws IOException {
// 上传文件名 - 原名
// String filename = file.getOriginalFilename();
// 文件后缀名
String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
// 上传文件名 - UUID
String filename = UUID.randomUUID() + suffix;
// 服务器端保存的文件对象
File serverFile = new File(uploadDir + filename);
// 将上传的文件写入到服务器端文件内
file.transferTo(serverFile);
}


/**
* 下载文件
*/
@GetMapping(value = "/downloadFile")
public void downloadFile(HttpServletResponse response) throws IOException {
// 文件所在的路径
File file = new File("f:/test/2.jpg");
// 使用response 获取字节输出
OutputStream outputStream = response.getOutputStream();
// 进行文件下载
response.setContentType("application/x-download");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Disposition", "attachment;filename=" + new String(("下载名称").getBytes("gbk"), "iso8859-1") + ".jpg");
// outputStream 写入到输出流
outputStream.write(FileCopyUtils.copyToByteArray(file));
// 刷新流
outputStream.flush();
// 关闭流
outputStream.close();
}
}

appliction.yml

1
2
3
4
5
6
7
8
9
10
11
spring:
thymeleaf:
# 关闭缓存
cache: false

servlet:
multipart:
# 单个文件最大
max-file-size: 5MB
# 设置总上传数据总大小
max-request-size: 10MB
-------------- 本文结束  感谢您的阅读 --------------