前言
文件上传对于互联网行业中是一个高频的场景,
Spring Boot 利用 MultipartFile 的特性来接收和处理上传的文件,
项目目录可以参考:[SpringBoot]项目初始化目录结构

项目目录
添加坐标到pom.xml:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<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>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
在resources目录下的 application.yml 中添加配置:
application:
#文件上传路径
profile: E:/temp/
#静态资源对外暴露的访问路径
staticAccessPath: /temp/**
spring:
thymeleaf:
cache: false
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
经过上面的配置,我们就可以专注的开始代码的编写了。
Thymeleaf模板后缀用的是.html,我们把他放到 templates 目录下
上传文件表单页 upload.html :
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<h1>单文件上传实例</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>
上传后的状态页 uploadStatus.html :
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body>
<h1>上传状态</h1>
<div th:if="${message}">
<h2 th:text="${message}"/>
<img th:src="${imgUrl}">
</div>
</body>
</html>
SpringBoot项目中只允许有一个main方法,这个方法放在启动类当中
在 UploadApplication启动类 中添加一个tomcatEmbedded()方法:
@SpringBootApplication
public class UploadApplication {
public static void main(String[] args) {
SpringApplication.run(UploadApplication.class, args);
}
//Tomcat large file upload connection reset
@Bean
public TomcatServletWebServerFactory tomcatEmbedded() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
tomcat.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> {
if ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol<?>)) {
//-1 means unlimited
((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);
}
});
return tomcat;
}
}
TomcatServletWebServerFactory() 方法主要是为了解决上传文件大于 10M (上面所设置)出现连接重置的问题,此异常内容 GlobalException 也捕获不到
全局异常捕获GlobalExceptionHandler:
@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的异常。并反馈给前端页面
控制层 UploadController :
@Controller
public class UploadController {
// 本地路径
@Value("${application.profile}")
private String profile ;
// 对外虚拟路径
@Value("${application.staticAccessPath}")
private String staticAccessPath ;
// 添加Thymeleaf模板的映射
@GetMapping("/")
public String index(){
return "upload";
}
@GetMapping("/upload")
public String getupload(RedirectAttributes redirect){
redirect.addFlashAttribute("message","No file!"+profile);
return "redirect:/uploadStatus";
}
@GetMapping("/uploadStatus")
public String uploadStatus(){
return "uploadStatus";
}
// 上传文件的post请求
@PostMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file , RedirectAttributes redirect){
if (file.isEmpty()){
redirect.addFlashAttribute("message","No file!");
return "redirect:uploadStatus";
}else {
try{
byte[] filebytes = file.getBytes();
// Path path = Paths.get("/upLoad/"+file.getName());
InputStream stream = file.getInputStream();
String newFileName = MD5.calcMD5(stream);
String type[] = file.getContentType().split("/");
Path path = Paths.get(profile +newFileName+"."+type[1]);
Files.write(path,filebytes);
redirect.addFlashAttribute("message","Up load successful! The file name is "+newFileName+"."+type[1]);
redirect.addFlashAttribute("imgUrl",staticAccessPath.replace("**",newFileName+"."+type[1]) );
}catch (IOException e){
e.printStackTrace();
}
}
return "redirect:uploadStatus";
}
}
一定要添加Thymeleaf模板的映射,否则会报404。
再添加一个配置,一个工具类
配置类AppConfigurer :用于映射本地文件到虚拟路径
@Configuration
public class AppConfigurer implements WebMvcConfigurer {
// 本地路径
@Value("${application.profile}")
private String profile ;
// 对外虚拟路径
@Value("${application.staticAccessPath}")
private String staticAccessPath ;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(staticAccessPath).addResourceLocations("file:"+profile);
}
}
MD5工具类参考:[SpringBoot]获取上传文件的MD5值
实现效果:

表单页

状态页