SpringBoot实现文件上传和下载
文件上传需要使用到 MultipartResolver接口。
Spring MVC 使用 MultipartResolver接口的实现类:CommonsMultipartResolver 。CommonsMultipartResolver类是基于Apache Commons FileUpload技术实现的。 所以,SpringMVC的文件上传需要依赖Apache Commons FileUpload的组件。传送门:SpringMVC实现文件上传和下载
SpringBoot 默认使用 MultipartResolver接口的实现类:StandardServletMultipartResolver。默认配置了单文件大小限制等。所以,不需要依赖Apache Commons FileUpload的组件,即可直接使用。
@Bean
public MultipartResolver multipartResolver() {
// 默认配不配都行,如果使用CommonsMultipartResolver,注入就行
// StandardServletMultipartResolver resolver = new StandardServletMultipartResolver();
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
return resolver;
}
新建一个SpringBoot项目,引入web依赖。使用默认的resolver。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
一、文件上传
1、单文件上传
MultipartFile 类封装了请求数据中的文件,此时这个文件存储在内存中或临时的磁盘文件中,需要将其转存到一个合适的位置,因为请求结束后临时存储将被清空。在 MultipartFile 接口中有如下方法:
- String getName(); // 获取参数的名称
- String getOriginalFilename(); // 获取文件的原名称
- String getContentType(); // 文件内容的类型
- boolean isEmpty(); // 文件是否为空
- long getSize(); // 文件大小
- byte[] getBytes(); // 将文件内容以字节数组的形式返回
- InputStream getInputStream(); // 将文件内容以输入流的形式返回
- void transferTo(File dest); // 将文件内容传输到指定文件中
@Controller
@RequestMapping("/file")
public class FileController {
@PostMapping("/upload")
@ResponseBody
public String upload(MultipartFile file) {
if(file.isEmpty()){
return "文件不能为可空!";
}
// 使用日期来分类管理上传的文件
String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
File folder = new File("D:/E/upload/" + format);
if (!folder.exists()) {
folder.mkdirs();
}
String oldName = file.getOriginalFilename();
String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
File newFile = new File(folder, newName);
try {
//保存文件,返回文件路径
file.transferTo(newFile);
return folder + newName;
} catch (IOException ioException) {
ioException.printStackTrace();
}
return "error";
}
}
2、多文件上传
1)可以和单文件上传一样,多定义几个MultipartFile对象:
@PostMapping("/uploads2")
@ResponseBody
public String uploads2(MultipartFile file1, MultipartFile file2) {
// 使用日期来分类管理上传的文件
String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
File folder = new File("D:/E/upload/" + format);
if (!folder.exists()) {
folder.mkdirs();
}
try {
String oldName = file1.getOriginalFilename();
String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
File newFile = new File(folder, newName);
//保存文件
file1.transferTo(newFile);
oldName = file2.getOriginalFilename();
newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
newFile = new File(folder, newName);
//保存文件
file2.transferTo(newFile);
return "success";
} catch (IOException ioException) {
ioException.printStackTrace();
}
return "error";
}
2)可以使用 MultipartFile[] 数组来接受:
@PostMapping("/uploads")
@ResponseBody
public String uploads(MultipartFile[] files) {
// 使用日期来分类管理上传的文件
String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
File folder = new File("D:/E/upload/" + format);
if (!folder.exists()) {
folder.mkdirs();
}
try {
for (MultipartFile file : files) {
if(file.isEmpty()){
System.out.println("文件不能为可空!");
continue;
}
String oldName = file.getOriginalFilename();
String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
File newFile = new File(folder, newName);
//保存文件
file.transferTo(newFile);
}
return "success";
} catch (IOException ioException) {
ioException.printStackTrace();
}
return "error";
}
我使用 postman测试了一下均成功。这里简单写一下前端的代码。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>文件上传和下载</title>
</head>
<body>
<form action='http://localhost:8080/file/upload' method='post' enctype='multipart/form-data'>
<input type='file' name='file'>
<button type='submit'>上传</button>
</form>
<a href="template/asd.jpg" download="aaname.jpg">下载</a>
</body>
</html>
3、修改 SpringBoot对文件限制的默认配置项
在 MultipartAutoConfiguration类中会看到创建的默认值,我们要自定义,添加bean配置,替换它的即可。
方式一:在 application.yaml 配置文件中自定义:
spring:
servlet:
multipart:
enabled: true #是否启用http上传处理
max-request-size: 100MB #最大请求文件的大小
max-file-size: 900KB #设置单个文件的大小
file-size-threshold: 15MB #当文件达到多少时进行磁盘写入(临时文件的存放目录)
location: D:/E/upload/temp #当磁盘写入时的临时文件的存放目录(目录不存在会自动创建,上传完毕会自动删除临时文件)
# resolve-lazily: false #当前文件和参数被访问时是否再解析成文件
方式二:在 配置类中自定义:
在@Configuration注解的配置类中,增加Bean配置。通过 MultipartConfigFactory类中的得到 MultipartConfigElement。
@Configuration
public class UploadConfig {
@Bean
MultipartConfigElement multipartConfigElement(){
MultipartConfigFactory factory = new MultipartConfigFactory();
factory.setLocation("D:/E/upload/temp");
factory.setFileSizeThreshold(DataSize.parse("15", DataUnit.MEGABYTES)); //15MB
factory.setMaxRequestSize(DataSize.parse("100", DataUnit.MEGABYTES)); //100MB
factory.setMaxFileSize(DataSize.parse("90", DataUnit.KILOBYTES)); //900KB
MultipartConfigElement element = factory.createMultipartConfig();
return element;
}
}
如果想使用 CommonsMultipartResolver ,添加bean配置即可:
@Bean
public MultipartResolver multipartResolver() {
// 默认配不配都行,如果使用CommonsMultipartResolver,注入就行
// StandardServletMultipartResolver resolver = new StandardServletMultipartResolver();
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setDefaultEncoding("UTF-8");
resolver.setMaxInMemorySize(900 * 1024); // 900KB
resolver.setMaxUploadSize(100 * 1024 * 1024);// 上传文件大小 100M
return resolver;
}
二、文件下载
1、固定模板文件下载
不需要后台处理,使用html的<a> 标签即可实现。
<a href="template/asd.jpg" download="aaname.jpg">下载</a>
2、后台处理文件下载
对文件的处理更加灵活,最后把文件二进制数据写到响应中即可。
注意:不同浏览器文件名乱码的问题。
这里使用了 org.apache.commons.io.FileUtils工具类来处理文件流的操作,所以添加它的依赖。你也可以自己写。
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
@GetMapping("/download")
@ResponseBody
public ResponseEntity<byte[]> download() throws Exception{
//下载文件,简单new个文件
String downloadFilePath = "D:/E/upload/2020-10-20/8d053ae3-5fcb-4a7a-ab68-6e69e706f84c.jpg";
File downloadFile = new File(downloadFilePath);
String downloadFilenName ="下载文件名123" + downloadFile.getName().substring(downloadFile.getName().lastIndexOf("."));
HttpHeaders headers = new HttpHeaders();
//下载显示的文件名,并解决中文名称乱码问题
String downloadFileName = new String(downloadFilenName.getBytes("UTF-8"),"iso-8859-1");
//通知浏览器以attachment(下载方式)打开
headers.setContentDispositionFormData("attachment", downloadFileName);
//applicatin/octet-stream: 二进制流数据(最常见的文件下载)
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
// 使用下org.apache.commons.io.FileUtils工具类
byte[] bytes = FileUtils.readFileToByteArray(downloadFile);
return new ResponseEntity<byte[]>(bytes, headers, HttpStatus.CREATED);
}
这里文件操作都在本地,项目中可能会使用文件服务器,比如:FTP服务器,阿里OSS云存储等。操作大同小异。
—— Stay Hungry. Stay Foolish. 求知若饥,虚心若愚。