在这篇文章中,我们将看到如何使用Spring Boot实现单个或多个文件的上传。
在POST请求中,有三种类型。
URL-encoded
的参数在这篇文章中,我将更多地集中在第三种类型上。如果一个帖子请求的主体内容使用特定的边界或分隔符分割,那么它将被称为多部分请求。这个定界符将标志着单个参数的开始和结束。
例如,看一下下面这个表单。
如果这个表单被提交,那么服务器就会收到下面这种形式的HTTP请求。
POST /v3/ed8d9ae2-7d0d-4411-8b8c-66106d8a2721 HTTP/1.1
Host: run.mocky.io
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Cache-Control: no-cache
Postman-Token: 55480fab-4fc3-26e2-fde0-19cc88f8d73e
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="hello"
world
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="hotel"
trivago
------WebKitFormBoundary7MA4YWxkTrZu0gW--
Code language: HTTP (http)
现在试着把请求中的确切数值和上面的截图配合起来。这里首先要注意的是Content-Type
头。它将请求标记为多部分,每个参数之间的边界是----WebKitFormBoundary7MA4YWxkTrZu0gW
。当服务器收到这个信息时,它可以很容易地分割请求的主体,并得到每个参数的名称和它们的适当值。
通过这种设置,如果一个参数本身是一个文件,我们可以简单地在边界内进行编码。如果我在上面的请求中加入一个文件参数,那么请求正文就会是这样的。
POST /v3/ed8d9ae2-7d0d-4411-8b8c-66106d8a2721 HTTP/1.1
Host: run.mocky.io
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Cache-Control: no-cache
Postman-Token: e139ea1a-1f88-ae45-72c6-867ab4a12209
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="hello"
world
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="hotel"
trivago
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="myfile"; filename="hello-world.txt"
Content-Type: text/plain
Hello world from a file
------WebKitFormBoundary7MA4YWxkTrZu0gW--
Code language: HTTP (http)
请注意,在请求中出现了一个新的部分,同时在正文中加入了文件的内容。有了这些知识,我们来写一些代码。
假设我们的请求中有一个参数,我们想在我们的控制器方法中使用。例如,一个请求包含一个名为count
的参数,它是一个整数。所以控制器方法的参数将是@RequestParam("count") Integer count
。在这个例子中,Integer是存储参数计数的合适类型。
同样地,Spring MVC提供了一个MultipartFile
来保存文件的内容。因此,这里是我的简单例子,以一个文件作为参数。
@RequestMapping(value = "/file-upload", method = RequestMethod.POST)
@ResponseBody
public String uploadFile(@RequestParam("myFile") MultipartFile multipartFile) throws IOException {
multipartFile.transferTo(new File("C:\\data\\test\\" + multipartFile.getOriginalFilename()));
return "success";
}
Code language: Java (java)
在这个例子中,参数名称本身是myFile
。另外,我把文件内容写到我的本地磁盘。至于你想对MultipartFile
对象做什么,这取决于你。如果你有兴趣,这些是MultipartFile的可用方法部分。
helpful 方法来自MultipartFile类
这很容易。只需添加另一个参数,用不同的@RequestParam
。
@RequestMapping(value = "/two-file-upload", method = RequestMethod.POST)
@ResponseBody
public String uploadTwoFile(@RequestParam("myFile") MultipartFile multipartFile,
@RequestParam("myOtherFile") MultipartFile otherMultipartFile) throws IOException {
multipartFile.transferTo(new File("C:\\data\\test\\" + multipartFile.getOriginalFilename()));
otherMultipartFile.transferTo(new File("C:\\data\\test\\" + otherMultipartFile.getOriginalFilename()));
return "success";
}
Code language: Java (java)
Spring MVC将不同值的同一个参数处理成一个数组或集合。这对MultipartFile参数也是如此。如果你必须上传相当多的文件,而不对每个文件参数名进行硬编码,这就是你要做的。
@RequestMapping(value = "/multiple-file-upload", method = RequestMethod.POST)
@ResponseBody
public String uploadMultipleFiles(@RequestParam("myFiles") MultipartFile[] multipartFiles) throws IOException {
for (MultipartFile multipartFile : multipartFiles) {
multipartFile.transferTo(new File("C:\\data\\test\\" + multipartFile.getOriginalFilename()));
}
return "success";
}
Code language: Java (java)
是的,你可以限制上传到你系统中的最大文件大小。对于这一点,我们甚至不需要写任何一段代码。下面的属性将让客户上传大小低于5KB的文件。
spring.servlet.multipart.max-file-size=5KB
Code language: Properties (properties)
任何超过5KB的文件的请求将得到一个500内部服务器错误,并有一个org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException
,如下所示。
2020-11-14 00:31:14.227 ERROR 16596 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.multipart.MaxUploadSizeExceededException: Maximum upload size exceeded; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException: The field myFiles exceeds its maximum permitted size of 5120 bytes.] with root cause
org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException: The field myFiles exceeds its maximum permitted size of 5120 bytes.
at org.apache.tomcat.util.http.fileupload.impl.FileItemStreamImpl$1.raiseError(FileItemStreamImpl.java:114) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.tomcat.util.http.fileupload.util.LimitedInputStream.checkLimit(LimitedInputStream.java:76) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at org.apache.tomcat.util.http.fileupload.util.LimitedInputStream.read(LimitedInputStream.java:135) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
at java.io.FilterInputStream.read(FilterInputStream.java:107) ~[na:1.8.0_221]
Code language: Java (java)
请注意,这个配置的默认值是1MB。
尽管这通常是个坏主意,你可以通过设置max-file-size为-1,将上传大小设置为无限。
spring.servlet.multipart.max-file-size=-1
spring.servlet.multipart.max-request-size=-1
Code language: Properties (properties)
如果你还在使用spring boot 1.x版本,你应该对这些属性使用spring.http而不是spring.servlet。
Spring MVC会立即解析所有的MultipartFile。如果被解析的文件可能会也可能不会被进一步使用,那么最好只在文件确实被使用时才推迟解析。这样我们可以节省CPU的使用。对于这种行为,你需要在应用程序属性中添加以下配置。
spring.servlet.multipart.resolve-lazily=true
Code language: Properties (properties)
上述所有例子的源代码都可以在下面的GitHub链接中找到。如果你想对这个话题进行补充或有任何问题,请随时在下面留言。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://springhow.com/spring-boot-file-upload-with-examples/
内容来源于网络,如有侵权,请联系作者删除!