SpringBoot:SpringBoot异步上传文件报错

一、前言

  项目中有个接口的功能是这样的,客户端先上传文件之后,服务端需要对文件进行一些校验,以及记录文件信息之后再把文件上传到公有云服务器,最后把一些传递给其他系统。因为文件比较大,使用同步调用的时候,客户端在等待的时间有点久,所以想着把接口改成异步调用,让服务端异步操作完了之后再发送成功的消息

  实现方式其实很简单,就是把需要的操作方法改为异步方法,使用@Async注解。

但是运行之后确出现了

java.io.FileNotFoundException: /data/tomcat/yytx/work/Catalina/localhost/ROOT/upload_8ed3adae_e26f_49be_a005_9b0ad7f6be31_00000005.tmp (No such file or directory)

可以看到是这个临时文件不存在

二、问题排查

  方法一:我的文件是放在了System.getProperty(“java.io.tmpdir”),tomcat的这个临时目录下面,然后在上传,起初怀疑是临时目录会被删除导致的,所以我自定义了一个目录,用来存放文件,在文件操作完成之后再删除。但是改完之后,还是有问题。

   方法二:排查方法,增加一些打印日志,upload_8ed3adae_e26f_49be_a005_9b0ad7f6be31_00000005.tmp (No such file or directory)看报错是文件没找到,那么重点观察MultipartFile文件上传之后的每一步情况

结论:Controller接口异步调用之后,再接口返回的时候,就会关闭MultipartFile文件

三、问题分析

MultipartFile生命周期了解

1. 创建与初始化

  当客户端(如浏览器)通过HTTP POST请求上传文件时,Spring MVC的DispatcherServlet会拦截这个请求。根据请求中的Content-Type(通常是multipart/form-data),Spring MVC会识别出这是一个包含文件上传的请求。Spring MVC使用其内置的MultipartResolver(如CommonsMultipartResolver或StandardServletMultipartResolver)来解析请求体,并将文件数据封装成MultipartFile对象。

  MultipartFile对象在此时被创建并初始化,包含了文件的内容、名称、类型、大小等信息。

2. 传递给Controller

  在Spring MVC的请求处理流程中,MultipartFile对象会被作为参数传递给Controller层中处理文件上传的方法。这个过程是通过Spring的MVC参数绑定机制实现的,即Spring会根据请求中的数据和方法的参数类型进行匹配,并将请求中的数据绑定到方法的参数上。

3. 处理与存储

  在Controller层的方法中,开发者可以对MultipartFile对象进行进一步的处理,如验证文件类型、大小等
如果需要,开发者可以将文件保存到服务器的磁盘上,或者将文件内容转换为其他格式进行存储(如保存到数据库)。
在这个过程中,MultipartFile对象作为处理文件上传的媒介,其生命周期与请求处理流程同步。

4. 请求处理完成

  当Controller层的方法处理完文件上传请求后,会返回一个响应给客户端。此时,与请求相关的资源(包括MultipartFile对象)可能会被Spring MVC的底层框架(如Servlet容器)清理,以释放内存或资源。

  但是,需要注意的是,MultipartFile对象本身并不直接管理文件在服务器上的存储。如果开发者已经将文件保存到了磁盘或数据库中,那么这些文件将独立于MultipartFile对象存在。

5. 生命周期结束
  MultipartFile对象的生命周期在Controller层的方法执行完毕后结束。但是,由于MultipartFile对象并不直接管理文件存储,因此文件的实际生命周期取决于开发者如何处理和存储这些文件。

  如果开发者在异步任务中继续使用MultipartFile对象(尽管这通常不是推荐的做法),则需要确保在异步任务执行完毕前,MultipartFile对象所引用的文件数据仍然可用。

  这通常意味着需要在异步任务开始之前将文件数据保存到某个持久化存储中,并在异步任务中使用这个存储路径来访问文件。

四、解决方法

  在异步方法之前,将MultipartFile对象落盘或者把Inputstream提前获取。


使用transferTo

// 文件先保存到本地
Path filePath = Paths.get(filePath, fileName);
// 如果目标文件夹不存在,则创建它
if (!Files.exists(filePath.getParent())) {
	Files.createDirectories(localFilePath.getParent());
}

file.transferTo(filePath.toFile());

  • 21
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Boot提供了名为MultipartFile的接口来支持异步表单上传文件。要在Spring Boot中实现异步表单上传文件,可以按照以下步骤进行操作: 1. 在Spring Boot应用程序的依赖项中引入相应的MultipartFile依赖项。如使用Maven,可以在pom.xml文件中添加以下依赖项: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> ``` 2. 在控制器类中创建一个方法,用于处理上传文件的请求。可以使用`@PostMapping`注解将该方法映射到相应的URL请求。例如: ```java @PostMapping("/upload") public CompletableFuture<String> uploadFile(@RequestParam("file") MultipartFile file) { // 处理文件上传逻辑 // 返回上传结果 } ``` 3. 在上传文件的方法中,可以使用异步处理来实现异步文件上传。可以使用`CompletableFuture`类来处理异步任务。例如: ```java @PostMapping("/upload") public CompletableFuture<String> uploadFile(@RequestParam("file") MultipartFile file) { return CompletableFuture.supplyAsync(() -> { // 处理文件上传逻辑 // 返回上传结果 }); } ``` 4. 在处理文件上传的逻辑中,可以使用`MultipartFile`接口提供的方法来访问和处理上传的文件。例如: ```java @PostMapping("/upload") public CompletableFuture<String> uploadFile(@RequestParam("file") MultipartFile file) { return CompletableFuture.supplyAsync(() -> { // 获取上传文件的原始文件名 String fileName = file.getOriginalFilename(); // 获取上传文件的字节数组 byte[] fileBytes = file.getBytes(); // 进行上传文件的业务逻辑处理 // 返回上传结果 }); } ``` 通过上述步骤,就可以在Spring Boot应用程序中实现异步表单上传文件的功能。在处理上传文件的方法中,可以根据具体需求对上传的文件进行处理,并返回上传结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值