Spring Boot 中文件上传
- 一、MultipartFile
- 二、单文件上传案例
- 三、多文件上传案例
- [四、Servlet 规范](#四、Servlet 规范)
- [五、Servlet 规范实现文件上传](#五、Servlet 规范实现文件上传)
- 上传文件大家用的最多的就是 Apache Commons FileUpload,这个库使用非常广泛。Spring Boot3 版本中已经不能使用了。代替它的是 Spring Boot 中自己实现的文件上传。
- Spring Boot 上传文件现在变得非常简单。提供了封装好的处理上传文件的接口 MultipartReslover ,用于解析上传文件的请求,它的内部实现类 StandardServletMultipartResolver 。之前常用的 CommonsMultipartResolver 不能使用了。 CommonsMultipartResolver 是使用 Apache Commons File Upload 库时的处理类。
一、MultipartFile
-
StandardServletMultipartResolver 内部封装了读取 POST 请求的请求体中的数据,也就是文件内容。我们只需要在 Controller 的方法中加入形参 @ReqestParam("参数名") MultipartFile file 。MultipartFile 表示上传的文件,其提供了方便的方法保存文件到磁盘。
javapublic interface MultipartFile extends InputStreamSource { String getName();//返回参数的名称 @Nullable String getOriginalFilename();//获取上传文件的名称 @Nullable String getContentType();//返回文件的内容类型 boolean isEmpty();//判断是否为空,或者上传的文件是否有内容 long getSize();//返回文件大小 以字节为单位 byte[] getBytes() throws IOException;//将文件内容转化成一个byte[] 返回 InputStream getInputStream() throws IOException;//返回InputStream读取文件的内容 default Resource getResource() { return new MultipartFileResource(this); } //保存上传文件到目标Dest中 void transferTo(File dest) throws IOException, IllegalStateException; default void transferTo(Path dest) throws IOException, IllegalStateException { FileCopyUtils.copy(this.getInputStream(), Files.newOutputStream(dest)); } }
二、单文件上传案例
-
创建两个静态页面,一个用来上传文件(使用表单的方式),另一个用来显示文件上传成功。(注意:静态资源放在 static 目录下,否则访问不到资源 )
- 使用表单的方式上传文件必须满足的三个要求:
- ① enctype="multipart/form-data"
- ② method="post"
- ③ <input type="file" value="选择文件" name="uploadFile">
html<!-- 文件名:uploadfile.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>上传文件</title> </head> <body> <h3>上传文件</h3> <div> </div> <form action="uploadFile" enctype="multipart/form-data" method="post"> 选择需要上传的文件:<input type="file" value="选择文件" name="uploadFile"> <br> <input type="submit" value="上传文件"> </form> </body> </html>
html<!-- 文件名:upload_success.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>文件上传成功</title> </head> <body> <h3>文件上传成功</h3> </body> </html>
- 使用表单的方式上传文件必须满足的三个要求:
-
编写controller方法获取请求,然后保存文件。
java@Controller public class UploadFileController { @PostMapping("/uploadFile") public String uploadFile(@RequestParam("uploadFile") MultipartFile multipartFile) throws IOException { //首先判断上传的文件是否为空 if (!multipartFile.isEmpty()) { String suffix = ".unknown";//初始文件后缀为不知道 String name = multipartFile.getOriginalFilename();//获取上传的文件名 System.out.println(name); //获取文件的后缀 if (name != null && name.indexOf(".") > 0) { suffix = name.substring(name.indexOf(".")); } String dest = UUID.randomUUID() + suffix;//生成保存的文件名 multipartFile.transferTo(new File("G:/files/" + dest));//保存文件到指定位置 } //防止刷新,重复上传 return "redirect:/upload_success.html"; } }
-
编写错误页面
- 在 SpringBoot 中 /static/error/5xx.html 文件 ===> 如果出现 5xx 的错误自动跳转到整个页面。
- 在 SpringBoot 中 /static/error/4xx.html 文件 ===> 如果出现 4xx 的错误自动跳转到整个页面 。
html<!-- 文件名:5xx.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>出现了 5XX 错误!!!</h3> </body> </html>
html<!-- 文件名:4xx.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>出现了 4XX 错误!!!</h3> </body> </html>
-
设置上传文件的大小
- Spring Boot 默认单个文件最大支持1M,一次请求最大10M。改变默认值,需要修改 application.yml 配置文件。file-size-threshold 超过指定大小,直接写文件到磁盘,不在内存处理。
- Spring Boot 默认单个文件最大支持1M,一次请求最大10M。改变默认值,需要修改 application.yml 配置文件。file-size-threshold 超过指定大小,直接写文件到磁盘,不在内存处理。
-
不能只考虑SpingBoot每次请求的文件最大大小,还需要设置服务器每次请求的大小。
三、多文件上传案例
-
多文件上传,在接收文件参数部分有所改变 MultipartFile[] files。循环遍历数组解析每一个上传的文件。
-
前端通过 form 表单上传多文件。
html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>上传文件</title> </head> <body> <h3>上传文件</h3> <div> </div> <form action="uploadFile" enctype="multipart/form-data" method="post"> 选择需要上传的文件 1:<input type="file" value="选择文件" name="uploadFile"> <br> 选择需要上传的文件 2:<input type="file" value="选择文件" name="uploadFile"> <br> 选择需要上传的文件 3:<input type="file" value="选择文件" name="uploadFile"> <br> <input type="submit" value="上传文件"> </form> </body> </html>
四、Servlet 规范
-
Servlet3.0 规范中,定义了 Jakarta.servlet.http.Part 接口处理 mulitipart/form-data POST 请求中接收到的表单数据。有了 Part 对象,其 write() 方法将上传文件保存到服务器本地的磁盘中。
-
在 HttpServletRequest 接口中引入的新方法:
- getParts():返回 Part 对象的集合。
- getPart(字符串名称):检索具有给定名称的单个 Part 对象。
-
Spring Boot3 使用的 Servlet 规范是基于 5 的,所以上传文件使用的就是 Part 接口。
-
StandardServletMultipartResolver 对 Part 接口进行的封装,实现基于 Servlet 规范的文件上传。
javapublic interface Part { InputStream getInputStream() throws IOException;//获取输入流用于检索文件的内容 String getContentType();//获取文件内容类型 String getName();//获取file控件的name属性 String getSubmittedFileName();//获取上传文件名Servlet3.1 Tomcat8.0实现 long getSize();//获取上传文件的大小 void write(String fileName) throws IOException; //将文件内容写入指定的磁盘位置 void delete() throws IOException;//删除Part数据和临时目录数据,默认会删除 String getHeader(String name);//获取指定请求头 Collection<String> getHeaders(String name);//获取指定header名称的集合数据 Collection<String> getHeaderNames();//获取所有请求头的名称 }
五、Servlet 规范实现文件上传
java
@PostMapping("/files")
public String upload(HttpServletRequest request){
try {
for (Part part : request.getParts()) {
String fileName = extractFileName(part);
part.write(fileName);
}
} catch (IOException | ServletException e) {
throw new RuntimeException(e);
}
return "redirect:/upload_success.html";
}
private String extractFileName(Part part) {
String contentDis = part.getHeader("content-disposition");
String[] items = contentDis.split(";");
for (String s : items) {
if (s.trim().startsWith("filename")) {
return s.substring(s.indexOf("=") + 2, s.length()-1);
}
}
return "";
}
- 上传文件包含 header 头 content-disposition,类似如下的内容,可获取文件原始名称。
- form-data; name="dataFile";filename="header.png"
- application.yal 文件,可配置服务器存储文件位置,例如:
- spring.servlet.multipart.location=G:/files/