14.springboot文件上传
-
Spring MVC对java原生文件上传commons-fileupload做了简化,在Spring Boot中对此做了更进一步的简化,文件上传更为方便。
-
Java中的文件上传一共可以使用两个组件,一个是CommonsMultipartResolver,另一个是StandardServletMultipartResolver.
-
其中 CommonsMultipartResolver使用commons-fileupload来处理multipart 请求,需要对应的jar包。而StandardServletMultipartResolver则是基于Servlet 3.0来处理multipart 请求的,因此若使用StandardServletMultipartResolver,则不需要添加额外的jar包。Tomcat 7.0开始就支持Servlet 3.0 了,因此可以直接使用StandardServletMultipartResolver。而在Spring Boot 提供的文件上传自动化配置类MultipartAutoConfiguration中,默认也是采用StandardServletMultipartResolver,部分源码如下:
@Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
@ConditionalOnMissingBean(MultipartResolver.class)
public StandardServletMultipartResolver multipartResolver() {
StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();
multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());
return multipartResolver;
}
- 若没有MultipartResolver,那么默认采用的MultipartResolver就是StandardServletMultipartResolver。因此,在Spring Boot中上传文件甚至可以做到零配置。
14.1 单文件上传
- 首先创建一个Spring Boot项目。并添加web、thymeleaf 依赖。然后在resources目录下的templates目录中创建一个uploadpage.html文件,内容如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<html>
<head>
<title>Title</title>
</head>
<body>
<form th:action="@{/user/upload1}" enctype="multipart/form-data" method="post">
<input type="file" name="uploadFile" placeholder="选择文件">
<input type="submit" value="提交">
</form>
</body>
- 创建文件上传处理接口,需要使用到配置上传文件的临时目录和长期目录和一些上传文件参数在配置文件中,该代码如下:
package com.example.controller;
import com.example.pojo.User;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
/**
* @author CNCLUKZK
* @create 2022/8/10-14:59
*/
@Api(tags = "用户管理") //可以当作是这个组的名字。
@RestController
@RequestMapping("/user")
public class UserController {
//单件上传入参
@ApiOperation(value = "文件上传1",notes = "文件上传-单文件")
@ApiImplicitParams({
@ApiImplicitParam(name = "uploadFile", paramType="form", value = "上传文件", dataType="uploadFile", required = true)
})
@PostMapping(value = "/upload1", headers = "content-type=multipart/form-data")
public String upload(@RequestPart("uploadFile") MultipartFile uploadFile, HttpSession session, HttpServletRequest req){
String originalFilename = uploadFile.getOriginalFilename();
//若文件名为空则返回到上传页
if (!StringUtils.hasText(originalFilename)) {
return "originalFilename is error";
}
//上传路径保存设置
//String uploadPath = session.getServletContext().getRealPath("/uploadFile/");
System.out.println("fileSavePath====="+fileSavePath);
File file1 = new File(fileSavePath);
if (!file1.exists()) {
file1.mkdirs();
}
try {
uploadFile.transferTo(new File(file1,originalFilename));
} catch (IOException e) {
e.printStackTrace();
return "uploadFile is error!";
}
return req.getScheme()+"://"+req.getServerName()+":"+req.getServerPort()+"/workspace_idea01/uploadFile/"+originalFilename;
}
}
- 为啥注释掉String uploadPath = session.getServletContext().getRealPath(“/uploadFile/”);
上传图片到服务器根路径下的文件夹里,若重启服务器,图片又无法访问,这是因为每次重启服务器之后,都会在系统临时文件夹内,创建一个新的服务器,图片就保存在这里,若重启,又会产生一个新的服务器,此时访问的就是新服务器的图片资源,而图片根本就不在新服务器内。
另外就是传对于相同日期的文件的时候会出现无法上传文件。
系统的临时文件夹会定期清理,很有可能导致以前上传的文件丢失。
- 所以需要配置上传文件的临时目录和长期目录和一些上传文件参数,这就需要在application.properties配置了。
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
file-save-path: D:/workspace_idea01/uploadFile/
#是否开启文件上传支持,默认为true。
spring.servlet.multipart.enabled=true
#文件写入磁盘的阈值,默认为0。
spring.servlet.multipart.file-size-threshold=0
#上传文件的临时保存位置。
spring.servlet.multipart.location=D:/workspace_idea01/temp
#上传的单个文件的最大大小,默认为1MB。
spring.servlet.multipart.max-file-size=10MB
#多文件上传时文件的总大小,默认为10MB。
spring.servlet.multipart.max-request-size=10MB
#文件是否延迟解析,默认为false。
spring.servlet.multipart.resolve-lazily=false
- 然后在自定义web配置类中配置下资源映射路径,供真实访问
@Configuration
public class MyMvcConfiguration implements WebMvcConfigurer {
@Value("${file-save-path}")
private String fileSavePath;
/**
* 配置资源映射
* 意思是:如果访问的资源路径是以“/workspace_idea01/uploadFile/**”开头的,
* 就映射到本机的“D:/workspace_idea01/uploadFile/”这个文件夹内,去找你要的资源
* 注意:D:/workspace_idea01/uploadFile/ 后面的 “/”一定要带上
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/workspace_idea01/uploadFile/**").addResourceLocations("file:"+fileSavePath);
}
}
- 测试下访问http://127.0.0.1:8080/app/uploadPage,显示上传链接路径
- 访问下链接路径。
14.2 多文件上传
- 修改上传页面uploadpage.html的路径和上传控件
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<html>
<head>
<title>Title</title>
</head>
<body>
<form th:action="@{/user/upload2}" enctype="multipart/form-data" method="post">
<input type="file" name="uploadFile" placeholder="选择文件">
<input type="file" name="uploadFile" placeholder="选择文件2">
<input type="submit" value="提交">
</form>
</body>
- 修改文件上传接口,将上传的文件数组遍历传输到指定文件夹下
@ApiOperation(value = "文件上传2",notes = "文件上传-多文件")
@PostMapping("/upload2")
public ArrayList upload2(@ApiParam(name = "uploadFile",value = "上传文件",required = true) MultipartFile[] uploadFile, HttpSession session, HttpServletRequest req){
String originalFilename ="";
//若文件名为空则返回到上传页
if (!StringUtils.hasText(originalFilename)) {
System.out.println("originalFilename is error");
}
ArrayList<String> filePathList=new ArrayList();
System.out.println("fileSavePath====="+fileSavePath);
File file1 = new File(fileSavePath);
if (!file1.exists()) {
file1.mkdirs();
}
for (MultipartFile file: uploadFile) {
originalFilename = file.getOriginalFilename();
if (!StringUtils.hasText(originalFilename)) {
System.out.println("originalFilename is error");
}
try {
file.transferTo(new File(file1,originalFilename));
filePathList.add(req.getScheme()+"://"+req.getServerName()+":"+req.getServerPort()+"/workspace_idea01/uploadFile/"+originalFilename);
} catch (IOException e) {
e.printStackTrace();
System.out.println("uploadFile is error!");
}
}
return filePathList;
}
- 测试效果
- 访问其中的上传链接,显示文件或图片