Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring异步文件上载和处理_Spring_Spring Mvc - Fatal编程技术网

Spring异步文件上载和处理

Spring异步文件上载和处理,spring,spring-mvc,Spring,Spring Mvc,我正试图上传文件,然后读取它,一切正常,但在处理程序方法上添加@Async注释时就不行了 我不希望用户一直等到处理文件。但在放置此注释后,我得到java.lang.IllegalStateException:文件已被移动-无法再次读取exception。发生了什么,我该如何解决?据我所知,Spring可能只是在清除文件,因为请求-响应结束并将其清除。但是@Async不应该阻止这种情况吗 Spring启动应用程序示例: @SpringBootApplication @EnableSwagger2

我正试图上传文件,然后读取它,一切正常,但在处理程序方法上添加
@Async
注释时就不行了

我不希望用户一直等到处理文件。但在放置此注释后,我得到
java.lang.IllegalStateException:文件已被移动-无法再次读取
exception。发生了什么,我该如何解决?据我所知,Spring可能只是在清除文件,因为请求-响应结束并将其清除。但是
@Async
不应该阻止这种情况吗

Spring启动应用程序示例:

@SpringBootApplication
@EnableSwagger2
@ComponentScan(value = "hello")
@EnableAsync
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.regex("/api/.*"))
                .build();
    }
}
上载控制器:

@RestController
@RequestMapping(value = "/files")
public class FilesController {

    @Inject
    private Upload upload;

    @RequestMapping(method = RequestMethod.POST)
    public void addSource(@RequestParam MultipartFile file) throws IOException, InterruptedException {
        upload.process(file);
    }
}
上载服务:

@Component
public class Upload {

    @Async
    public void process(MultipartFile file) throws InterruptedException, IOException {
        sleep(2000);
        System.out.println(new String(IOUtils.readFully(file.getInputStream(), -1, false)));
    }
}

现在我得到了
java.io.FileNotFoundException
。我不确定我错过了什么。可能是我做错了什么,因为我在这方面找不到任何错误,我认为这是一个非常常见的用例。

您不能以您这样做的方式将MultipartFile参数交给您的
@Async
方法

addSource
方法结束时,
MultipartFile
超出范围,资源被释放。因此,“进程”方法内部的访问将失败。你用这种方式建立了某种比赛条件。 Springs
DispatcherServlet
使用
StandardServletMultipartResolver.cleanupMultipart
清理这些文件。在那里放置一个断点,以查看在重新运行
addSource(…)
时何时调用此方法

您应该执行以下操作:将整个文件读入
addSource
方法内的缓冲区。然后将缓冲区传递给
进程
方法,让
addSource
返回

您所谓的“…处理文件…”不是“处理”文件,而是读取文件

@Async
public void process(byte[] bs){
    System.out.println(new String(bs));
    //do some long running processing of bs here
}

@RequestMapping(method = RequestMethod.POST)
public void addSource(@RequestParam MultipartFile file) {
    upload.process(IOUtils.toByteArray(file));
}

上传文件时,您是发出post请求还是发出ajax请求?此外,您是在service方法中还是在controller中使用@Async注释?这是一个简单的post请求(通过招摇过市)。我在服务方法上添加了@Async注释。你能上传相关代码吗?这将帮助我们了解您的尝试。好的,我会尽快上传它(必须先简化)。谢谢!顺便说一句,我在这里做了一些长时间的处理,这只是一个例子。很好的解释!然而,不幸的是,建议的解决方案有一点缺陷:在企业环境中,文件的大小往往无法像这样缓冲到内存中。遗憾的是,
InputStreamResource
也无法工作。据我所知,到目前为止,您最好将内容复制到自己的临时文件(例如,
文件#createTempFile
),您可以在处理线程结束时对其进行清理。是的@Powerslave您完全正确。如果您负担不起内存中的缓冲,那么应该使用文件系统支持的缓冲区(也称为临时文件)。我在示例中使用内存中的方法,因为它不会产生文件处理中出现的新问题(访问限制、必要的清理任务等)