提供文件时“没有AsyncContext便无法分派”

时间:2018-09-10 10:26:41

标签: java spring-mvc asynchronous servlet-3.0

我需要在“文件下载控制器”之上编写“一次性文件下载” MVC控制器。将文件传输到客户端后,必须将其从服务器中删除。

最初,代码是为提供文件而编写的

导入org.springframework.core.io.Resource

@GetMapping("/get/{someParam}")
public ResponseEntity<Resource> downloadFile(Long someParam)
{

    Long fileId = identify(someParam);

    return super.downloadFile(fileId); //This uses a "File repository" service binding file IDs to physical paths

}

protected ResponseEntity<Resource> downloadFile(Long fileId){

    File theFile = resolve(fileId);

    return new FileSystemResource(theFile);

}

由于ResponseEntity是某种“未来”实体,因此我无法在finally块中删除该文件,因为它尚无法提供。

因此,我首先编写了一个异步版本的文件下载,利用Commons IO复制有效负载。然后,我利用回调来仅通过我的方法处理文件。

protected WebAsyncTask<Void> downloadFileAsync(Long fileId,HttpResponse response){ //API method for multiple uses across the application

    InputStream is = new FileInputStream(resolve(fileId));
    Callable<Void> ret = () -> {
        IOUtils.copy(is,response.getOutputStream());
        is.close();
        return null;
    };


    return ret;
}

@GetMapping("/get/{someParam}")
public WebAsyncTask<Void> downloadFile(Long someParam,HttpResponse response)
{
    Long fileId = identify(someParam);
    WebAsyncTask ret = downloadFileAsync(fileId,response);


    ret.onCompletion(()-> fileService.delete(fileId)); //Here I leverage the callback because this file, in this point, is disposable

    return ret;
}

运行第二个版本时,出现以下错误。服务器是Tomcat 8.0.50

10-Sep-2018 12:20:37.551 AVVERTENZA [ajp-nio-8009-exec-3] org.apache.catalina.core.AsyncContextImpl.setErrorState onError() failed for listener of type [org.apache.catalina.core.AsyncListenerWrapper]
 java.lang.IllegalArgumentException: Cannot dispatch without an AsyncContext
    at org.springframework.util.Assert.notNull(Assert.java:134)
    at org.springframework.web.context.request.async.StandardServletAsyncWebRequest.dispatch(StandardServletAsyncWebRequest.java:128)
    at org.springframework.web.context.request.async.WebAsyncManager.setConcurrentResultAndDispatch(WebAsyncManager.java:369)
    at org.springframework.web.context.request.async.WebAsyncManager.access$200(WebAsyncManager.java:60)
    at org.springframework.web.context.request.async.WebAsyncManager$3.handle(WebAsyncManager.java:311)
    at org.springframework.web.context.request.async.StandardServletAsyncWebRequest.onError(StandardServletAsyncWebRequest.java:144)
    at org.apache.catalina.core.AsyncListenerWrapper.fireOnError(AsyncListenerWrapper.java:49)
    at org.apache.catalina.core.AsyncContextImpl.setErrorState(AsyncContextImpl.java:421)
    at org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:370)
    at org.apache.coyote.ajp.AbstractAjpProcessor.asyncDispatch(AbstractAjpProcessor.java:745)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:666)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1539)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1495)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

我已经在我的web.xml中配置了所有servlet和过滤器以支持异步操作。我做了一些研究,this answer并没有帮助,因为我使用的是Tomcat的新版本。

我的代码有什么问题?我没有完整地发布它以使其简单,但是调试发现正确的有效负载可以成功完成写操作。

2 个答案:

答案 0 :(得分:0)

我有同样的问题。就我而言,解决方案是配置 select dateCol, myCol, sum(case when dateCol is not null then 1 else 0 end) as sumCol from sampleTable group by dateCol, myCol order by dateCol

AsyncTaskExecutor

答案 1 :(得分:0)

根据@MDenium的评论

  

请勿使用仅供内部使用的WebAsyncTask。只需使用CompletableFuture或返回Callable。如果将try / final放在Callable中,它将起作用

WebAsyncTask并不是一个API,所以当您从MVC方法返回时,Spring不知道如何处理它。这不是执行异步执行的正确方法。它仅在内部用于承载任务和上下文。

Spring MVC支持:

  • DeferredResult
  • 可通话
  • CompletableFuture

,可能还有几个其他