上传多部分文件时出现FileNotFoundException错误-Spring Boot

13

我正在尝试通过Spring Boot应用程序的多部分上传来上传文件。在上传文件时,Jetty会抛出FileNotFound异常。

以下是模型结构:

private String identifier;
private MultipartFile file;

以下是配置:

@Bean
public MultipartConfigElement multipartConfigElement() {
    MultipartConfigFactory factory = new MultipartConfigFactory();
    factory.setMaxFileSize("500MB");
    factory.setMaxRequestSize("500MB");
    return factory.createMultipartConfig();
}

@Bean
public CommonsMultipartResolver multipartResolver() {
    return new CommonsMultipartResolver();
}

以下调用会抛出异常:

model.getFile().getInputStream()

以下是堆栈跟踪:

java.io.FileNotFoundException: /tmp/MultiPart7953817223010764667 (No such file or directory)
    at java.io.FileInputStream.open(Native Method)
    at java.io.FileInputStream.<init>(FileInputStream.java:146)
    at org.eclipse.jetty.util.MultiPartInputStream$MultiPart.getInputStream(MultiPartInputStream.java:218)
    at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile.getInputStream(StandardMultipartHttpServletRequest.java:253)
//user classes

这个问题是间歇性的,我无法通过连续尝试重现它。同样的文件第二次上传成功。

你有什么想法我在这里做错了吗?

提前致谢。


你尝试使用不同的 tmp 目录了吗?看起来好像有些东西在 Spring 写出文件和尝试检索它之间清除了该文件。 - Vivin Paliath
我还没有在应用程序中配置临时目录。它只是使用默认的目录。让我尝试使用不同的目录。 - Darshan Mehta
“Darshan Mehta” 那么?问题有更新了吗?配置临时目录有帮助吗? - vk23
19
我最终解决了问题。我的问题在于我使用了@Async方法来处理MultipartFile,但有时候传入的请求在文件实际处理之前就被销毁了。我的解决方法是将文件完全读入内存,然后开始异步处理。 - vk23
1
@vk23 这也是我的问题!我想文档应该更加关注使用多部分文件的这个方面。 - Frankie Drake
显示剩余4条评论
2个回答

13

可能有多个原因,sprintboot默认将Multipart文件存储在某个系统目录中。一旦使用file.getInputStream()消耗文件,再次这样做会导致此情况发生。因为一旦输入流被读取,spring自动清除保存的文件,导致"文件未找到"异常。另一个原因是在处理Multipart文件时使用了@Async。


1
另一个原因是在处理多部分文件时使用@Async。为什么呢? - thevoyager
请查看此答案 https://dev59.com/YFoV5IYBdhLWcg3wL8aw - Svirin
对我而言,有效的方法是在异步处理之前将MultipartFile转换为字节数组。MultipartFile.getBytes()虽然不适用于大文件。另一个解决方案是将文件复制到绝对路径,而不是依赖于Tomcat临时文件,因为它会自动删除得太快。 - web.learner

3

我找到了一个相当简单的方法。 我使用了 TaskExecutor(多线程方法)。 注意到 Tomcat 服务器的临时文件正在被删除。 因此,我创建了一个 DTO,并从 List<MultipartFile> 中提取所需的重要数据:-

List<FileDataDTO> files = new ArrayList<>();
        attachments.forEach(attach -> {
            try
            {
                FileDataDTO file = new FileDataDTO();
                file.setFileData(attach.getBytes());
                file.setOriginalName(attach.getOriginalFilename());
                file.setContentType(attach.getContentType());
                files.add(file);
            }
            catch (Exception e)
            {
                logger.error(Constant.EXCEPTION, e);
            }
        });

接着调用了我的任务执行器方法。数据在新线程中按预期反映出来。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接