SpringBoot之文件上传
文件上传
文件上传和下载是JAVA WEB
中常见的一种操作,文件上传主要是将文件通过IO流传输到服务器的某一个特定的文件夹下
;刚开始工作那会一个上传文件常常花费小半天的时间,繁琐的代码量以及XML配置
让我是痛不欲生;值得庆幸的是有了Spring Boot
短短的几句代码就能实现文件上传与本地写入操作….
导入依赖
在 pom.xml
中添加上 spring-boot-starter-web
和 spring-boot-starter-thymeleaf
的依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<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-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> |
配置文件
默认情况下 Spring Boot
无需做任何配置也能实现文件上传的功能,但有可能因默认配置不符而导致文件上传失败问题,所以了解相关配置信息更有助于我们对问题的定位和修复;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 禁用 thymeleaf 缓存 spring.thymeleaf.cache=false # 是否支持批量上传 (默认值 true) spring.servlet.multipart.enabled=true # 上传文件的临时目录 (一般情况下不用特意修改) spring.servlet.multipart.location= # 上传文件最大为 1M (默认值 1M 根据自身业务自行控制即可) spring.servlet.multipart.max-file-size=1048576 # 上传请求最大为 10M(默认值10M 根据自身业务自行控制即可) spring.servlet.multipart.max-request-size=10485760 # 文件大小阈值,当大于这个阈值时将写入到磁盘,否则存在内存中,(默认值0 一般情况下不用特意修改) spring.servlet.multipart.file-size-threshold=0 # 判断是否要延迟解析文件(相当于懒加载,一般情况下不用特意修改) spring.servlet.multipart.resolve-lazily=false |
如默认只允许1M
以下的文件,当超出该范围则会抛出下述错误
1 2 |
org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (20738021) exceeds the configured maximum (10485760) |
具体代码
上传页面
在 src/main/resources
目录下新建 static
目录和 templates
目录。在 templates
中新建一个 index.html
的模板文件;此处实现 单文件上传
、多文件上传
、BASE64编码
三种上传方式,其中 BASE64
的方式在对Android/IOS/H5
等方面还是不错的…
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 |
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>文件上传</title> </head> <body> <h2>单一文件上传示例</h2> <div> <form method="POST" enctype="multipart/form-data" action="/uploads/upload1"> <p> 文件1:<input type="file" name="file"/> <input type="submit" value="上传"/> </p> </form> </div> <hr/> <h2>批量文件上传示例</h2> <div> <form method="POST" enctype="multipart/form-data" action="/uploads/upload2"> <p> 文件1:<input type="file" name="file"/> </p> <p> 文件2:<input type="file" name="file"/> </p> <p> <input type="submit" value="上传"/> </p> </form> </div> <hr/> <h2>Base64文件上传</h2> <div> <form method="POST" action="/uploads/upload3"> <p> BASE64编码:<textarea name="base64" rows="10" cols="80"></textarea> <input type="submit" value="上传"/> </p> </form> </div> </body> </html> |
控制层
创建一个FileUploadController
,其中@GetMapping
的方法用来跳转index.html
页面,而@PostMapping
相关方法则是对应的 单文件上传
、多文件上传
、BASE64编码
三种处理方式。
@RequestParam("file")
此处的"file"
对应的就是html 中 name="file" 的 input 标签
,而将文件真正写入的还是借助的commons-io
中的FileUtils.copyInputStreamToFile(inputStream,file)
package cn.ywstore.qy.modules.admin.controller; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; import org.springframework.util.Base64Utils; import org.springframework.util.FileCopyUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @Controller @Slf4j @RequestMapping("/admin/login") public class UploadsController { @GetMapping("/uploads") public String uploads(){ return "uploads"; } @PostMapping("/upload1") @ResponseBody public Map<String, String> upload1(@RequestParam("file") MultipartFile file) throws IOException { log.info("[文件类型] - [{}]", file.getContentType()); log.info("[文件名称] - [{}]", file.getOriginalFilename()); log.info("[文件大小] - [{}]", file.getSize()); // TODO 将文件写入到指定目录(具体开发中有可能是将文件写入到云存储/或者指定目录通过 Nginx 进行 gzip 压缩和反向代理,此处只是为了演示故将地址写成本地电脑指定目录) // 文件输出地址 LocalDate localDate=LocalDate.now(); DateTimeFormatter dateTimeFormatter=DateTimeFormatter.ofPattern("yyyyMM"); String catalog=localDate.format(dateTimeFormatter)+"/"; String filePath = "e:/java/"+catalog ; new File(filePath).mkdirs(); String filename = file.getOriginalFilename();//获取文件名称 String suffixname = filename.substring(filename.lastIndexOf("."));//后缀 filename = System.currentTimeMillis() + suffixname;//文件上传后重命名数据库存储 file.transferTo(new File(filePath + filename)); Map<String, String> result = new HashMap<>(16); result.put("contentType", file.getContentType()); result.put("fileName", catalog+filename); result.put("fileSize", file.getSize() + ""); return result; } @PostMapping("/upload2") @ResponseBody public List<Map<String, String>> upload2(@RequestParam("file") MultipartFile[] files) throws IOException { if (files == null || files.length == 0) { return null; } List<Map<String, String>> results = new ArrayList<>(); for (MultipartFile file : files) { // TODO Spring Mvc 提供的写入方式 file.transferTo(new File("H:\\java\\" + file.getOriginalFilename())); Map<String, String> map = new HashMap<>(16); map.put("contentType", file.getContentType()); map.put("fileName", file.getOriginalFilename()); map.put("fileSize", file.getSize() + ""); results.add(map); } return results; } @PostMapping("/upload3") @ResponseBody public void upload2(String base64) throws IOException { // TODO BASE64 方式的 格式和名字需要自己控制(如 png 图片编码后前缀就会是 data:image/png;base64,) final File tempFile = new File("F:\\app\\chapter16\\test.jpg"); // TODO 防止有的传了 data:image/png;base64, 有的没传的情况 String[] d = base64.split("base64,"); final byte[] bytes = Base64Utils.decodeFromString(d.length > 1 ? d[1] : d[0]); FileCopyUtils.copy(bytes, tempFile); } }