在项目中碰到了一个报错:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet request; nested exception is java.io.IOException: The temporary upload location [/tmp/tomcat.4565031138659477751.9888/work
/Tomcat/localhost/${项目名}] is not valid
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.handleParseFailure(StandardMultipartHttpServletRequest.java:122)
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:113)
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.<init>(StandardMultipartHttpServletRequest.java:86)
at org.springframework.web.multipart.support.StandardServletMultipartResolver.resolveMultipart(StandardServletMultipartResolver.java:91)
at org.springframework.web.servlet.DispatcherServlet.checkMultipart(DispatcherServlet.java:1128)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:960)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:877)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
......
原因
SpringBoot项目启动后会在/tmp
目录下生成一个目录:tomcat.************.8080
,其中结尾的8080是项目tomcat的端口号,使用Multipart(form-data)的方式上传文件时,会在这个目录下面创建临时文件。
由于Linux系统会定期对tmp
下的文件夹进行清除,文件夹在长时间(默认10天)没有使用的情况下,就会被系统自动删除掉。/tmp
目录的清理规则主要取决于/usr/lib/tmpfiles.d/tmp.conf
文件的设定,默认的配置内容为:1
2
3# Clear tmp directories separately, to make them easier to override
v /tmp 1777 root root 10d # 清理/tmp下10天前的目录和文件
v /var/tmp 1777 root root 30d # 清理/var/tmp下30天前的目录和文件
根据上面的分析,如果上传文件的功能长时间没有使用,导致临时目录被删掉,则会抛出前面的那个异常了。
解决办法
方案一
直接重启项目, 会重新生成一个上面所说的临时文件夹。
方案二
在配置文件中配置tomcat的临时目录:1
server.tomcat.basedir=/home/temp
该目录是用来存放Tomcat的日志、Dump等文件的临时文件夹,默认没有指定则会使用/tmp
目录。
如果server.tomcat.basedir
指定的目录不存在,项目启动的时候会自动创建。
方案三
在配置文件中配置multipart文件上传的临时目录:1
spring.servlet.multipart.location=/home/temp
spring.servlet.multipart.location
这个配置在旧版本的SpringBoot里是叫spring.http.multipart.location
。
对于multipart文件上传的临时目录,这个设置的优先级要高于server.tomcat.basedir
,即如果spring.servlet.multipart.location
有配置则以spring.servlet.multipart.location
配置的目录为准,没有配置则会取server.tomcat.basedir
配置的目录。
注意:spring.servlet.multipart.location
配置的目录需要手动创建。
方案四
使用注解的方式配置:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class MultipartConfig {
/**
* 文件上传配置
* <p>
* 配置项:临时路径
*/
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory configFactory = new MultipartConfigFactory();
String path = System.getProperty("user.dir") + "/tmp/multipart";
File file = new File(path);
if (!file.exists()) {
file.mkdirs();
}
configFactory.setLocation(path);
return configFactory.createMultipartConfig();
}
}
这个和方案三的原理是一样的,不同之处是不需要手动去创建文件夹,因为代码里加了一个判断。
Servlet3.0后spring上传文件的机制
Spring 在处理上传文件的时候,会将当前文件的大小跟 fileSizeThreshold
(默认为0)这个值比较,如果大于fileSizeThreshold
则将文件保存在临时文件夹中,否则直接将文件放入内存中。 所以在上传文件过程中会对临时路径进行验证,如果临时路径不是文件夹或者不存在都将抛出异常。location临时路径可以通过spring.servlet.multipart.location
指定。当不指定的时候会默认取servlet上下文临时存储目录:javax.servlet.context.tempdir
,当servlet上下文临时存储目录不指定时会被赋值为tomcat的基本工作目录,tomcat基本工作目录可以由server.tomcat.basedir
指定(linux 系统默认为在tmp
目录下)。