springboot:使用Spring Boot上传文件

项目地址:https://github.com/snjl/springboot.upload.git

上传多个文件项目地址:https://github.com/snjl/springboot.uploads.git

使用Spring Boot最新版本1.5.9、jdk使用1.8、tomcat8.0。

pom包配置

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
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<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>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>

引入了spring-boot-starter-thymeleaf做页面模板引擎,写一些简单的上传示例。

启动类设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@SpringBootApplication
public class FileUploadWebApplication {

public static void main(String[] args) throws Exception {
SpringApplication.run(FileUploadWebApplication.class, args);
}

//Tomcat large file upload connection reset
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbedded() {
TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
tomcat.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> {
if ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol<?>)) {
//-1 means unlimited
((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);
}
});
return tomcat;
}

}

tomcatEmbedded这段代码是为了解决,上传文件大于10M出现连接重置的问题。此异常内容GlobalException也捕获不到。

编写前端页面

上传页面

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<h1>Spring Boot file upload example</h1>
<form method="POST" action="/upload" enctype="multipart/form-data">
<input type="file" name="file" /><br/><br/>
<input type="submit" value="Submit" />
</form>
</body>
</html>

非常简单的一个Post请求,一个选择框选择文件,一个提交按钮。

上传结果展示页面:

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body>
<h1>Spring Boot - Upload Status</h1>
<div th:if="${message}">
<h2 th:text="${message}"/>
</div>
</body>
</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
@GetMapping("/")
public String index() {
return "upload";
}
//上传业务处理
@PostMapping("/upload")
public String singleFileUpload(@RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) {
if (file.isEmpty()) {
redirectAttributes.addFlashAttribute("message", "Please select a file to upload");
return "redirect:uploadStatus";
}

try {
// Get the file and save it somewhere
byte[] bytes = file.getBytes();
Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
Files.write(path, bytes);

redirectAttributes.addFlashAttribute("message",
"You successfully uploaded '" + file.getOriginalFilename() + "'");

} catch (IOException e) {
e.printStackTrace();
}

return "redirect:/uploadStatus";
}

上面代码的意思就是,通过MultipartFile读取文件信息,如果文件为空跳转到结果页并给出提示;如果不为空读取文件流并写入到指定目录,最后将结果展示到页面。

MultipartFile是Spring上传文件的封装类,包含了文件的二进制流和文件属性等信息,在配置文件中也可对相关属性进行配置,基本的配置信息如下:

  • spring.http.multipart.enabled=true #默认支持文件上传.
  • spring.http.multipart.file-size-threshold=0 #支持文件写入磁盘.
  • spring.http.multipart.location= # 上传文件的临时目录
  • spring.http.multipart.max-file-size=1Mb # 最大支持文件大小
  • spring.http.multipart.max-request-size=10Mb # 最大支持请求大小

最常用的是最后两个配置内容,限制文件上传大小,上传时超过大小会抛出异常。

异常处理

1
2
3
4
5
6
7
8
9
@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(MultipartException.class)
public String handleError1(MultipartException e, RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("message", e.getCause().getMessage());
return "redirect:/uploadStatus";
}
}

设置一个@ControllerAdvice用来监控Multipart上传的文件大小是否受限,当出现此异常时在前端页面给出提示。利用@ControllerAdvice可以做很多东西,比如全局的统一异常处理等,感兴趣的同学可以下来了解。

使用ajax上传文件

加入函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@ResponseBody
@PostMapping("/ajax/upload") // //new annotation since 4.3
public String uploadByAjax(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return "error,the file is empty!";
}

try {
// Get the file and save it somewhere
byte[] bytes = file.getBytes();
Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
Files.write(path, bytes);

return "You successfully uploaded '" + file.getOriginalFilename() + "'";

} catch (IOException e) {
return "upload error!";
}
}

可以使用postman测试,使用form-data,key为file和enctype,其中enctype为multipart/form-data(也可以不设置)。

多文件上传

先将文件上传抽离出一个类,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
package com.neo.tools;

import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* @author 34924
*/
@Component
public class Upload {
private static String UPLOADED_FOLDER = "D:\\test\\";

public static String uploadFile( MultipartFile file) {
if (file.isEmpty()) {
return "error,the file is empty!";
}

try {
// Get the file and save it somewhere
byte[] bytes = file.getBytes();
Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
Files.write(path, bytes);

return "You successfully uploaded '" + file.getOriginalFilename() + "'";

} catch (IOException e) {
return "upload error!";
}
}

...
}

加上多文件上传:

1
2
3
4
5
6
7
8
9
10
11
12
13
public static String uploadFiles( MultipartFile [] files) {
String message = "success uploaded ";
for (MultipartFile file : files) {
try {
uploadFile(file);
} catch (Exception e) {
return "upload error!";
}
message = message + file.getOriginalFilename() + " ";
}
return message;

}


1
2
3
4
5
6
7
8
9
10
11
12
13
public static String uploadFiles( List<MultipartFile> files) {
String message = "success uploaded ";
for (MultipartFile file : files) {
try {
uploadFile(file);
} catch (Exception e) {
return "upload error!";
}
message = message + file.getOriginalFilename() + " ";
}
return message;

}

controller中改为:

1
2
3
4
5
6
7
@ResponseBody
@PostMapping("/ajax/uploads") // //new annotation since 4.3
public String uploadsByAjax(@RequestParam("file") MultipartFile []files) {
System.out.println("uploads");

return Upload.uploadFiles(files);
}


1
2
3
4
5
6
7
8
@ResponseBody
@PostMapping("/ajax/uploads") // //new annotation since 4.3
public String uploadsByAjax(HttpServletRequest request) {
List<MultipartFile> files = ((MultipartHttpServletRequest)request).getFiles("file");
System.out.println("uploads");

return Upload.uploadFiles(files);
}

均可实现多文件上传。

前端在input标签中添加属性multiple=”multiple”。

1
<input multiple="multiple" type="file" name="file" />

springboot:文件上传路径的几种设置方式

在配置文件中配置如下:

1
xcloud.uploadPath=D:\\test\\

编写上传路径配置类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

@Component
@ConfigurationProperties(prefix="xcloud")
public class UploadConfig {
//上传路径
@Value("${xcloud.uploadPath}")
private String uploadPath;

public String getUploadPath() {
return uploadPath;
}

public void setUploadPath(String uploadPath) {
this.uploadPath = uploadPath;
}
}

上传文件方法注入:

1
2
3
4
@Autowired
UploadConfig uploadConfig;
@Value("${media.save.urlprefix}")
private String urlprefix;

controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@ResponseBody
@PostMapping("/{savePath}/upload") // //new annotation since 4.3
public String uploadByAjax(@RequestParam("file") MultipartFile file, @PathVariable String savePath) {

if (file.isEmpty()) {
return "error,the file is empty!";
}

try {
// Get the file and save it somewhere
byte[] bytes = file.getBytes();
Path path = Paths.get(uploadConfig.getUploadPath() + savePath +"//" + file.getOriginalFilename());
System.out.println(path);
Files.write(path, bytes);

return "You successfully uploaded '" + file.getOriginalFilename() + "'";

} catch (IOException e) {
return "upload error!";
}
}

综上可以看出,可以使用固定的static String path来设置path,也可以在配置文件中配置,使用UploadConfig这样的配置类来取出配置路径,也可以综合上一种方式或者独立使用@PathVariable来获取需要的文件夹名,来进行路径生成。

-------------本文结束 感谢您的阅读-------------