Dav*_*avz 7 java streaming playframework
我正在写一个播放2应用程序,我正在努力解决文件流问题.我使用第三方API检索我的文件,其方法具有以下签名:
FileMetadata getFile(OutputStream destination, String fileId)
Run Code Online (Sandbox Code Playgroud)
在传统的Servlet应用程序中,如果我想将内容发送到我的客户端,我会做类似的事情:
HttpServletResponse resp;
myService.getFile(resp.getOutpuStream, fileId);
Run Code Online (Sandbox Code Playgroud)
我的问题是,在我的Play 2 Controller类中,我无法访问底层的OuputStream,因此我的控制器方法的最简单实现是:
public static downloadFile(String id) {
ByteArrayOutputStream baos = new BAOS(...);
myApi.getFile(baos,id); //Load inside temp Array
ByteArrayInputStream bais = new BAIS(baos.toByteArray())
return Ok(bais);
}
Run Code Online (Sandbox Code Playgroud)
它可以工作,但它需要在服务之前将整个内容加载到内存中,因此它不是一个选项(文件可能很大).
我在考虑一个解决方案,包括:
问题是我不知道是否可能(调用getFile是阻塞所以它需要多个线程与共享的OutputStream),也不是它有点过分.
有人遇到过这种问题并找到了解决方案吗?我提议的解决方案能解决我的问题吗
任何见解将不胜感激.
谢谢
编辑1 基于kheraud建议我已经设法有一个工作但仍然不完美的解决方案(下面的代码).
不幸的是,如果在调用getFile方法期间出现问题,则不会将错误发送回客户端(因为我返回了Ok)并且浏览器无限期地等待一个永远不会出现的文件.
有办法处理这种情况吗?
public static Result downloadFile(String fileId {
Thread readerThread = null;
try {
PipedOutputStream pos = new PipedOutputStream();
PipedInputStream pis = new PipedInputStream(pos);
//Reading must be done in another thread
readerThread = new DownloadFileWorker(fileId,pos);
readerThread.start();
return ok(pis);
} catch (Exception ex) {
ex.printStackTrace();
return internalServerError(ex.toString());
}
}
static class DownloadFileWorker extends Thread{
String fileId;
PipedOutputStream pos;
public DownloadFileWorker(String fileId, PipedOutputStream pos) {
super();
this.fileId = fileId
this.pos = pos;
}
public void run(){
try {
myApi.getFile(pos,fileId);
pos.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Run Code Online (Sandbox Code Playgroud)
编辑2
我找到了一种避免无限加载页面的方法,只需在工作线程的catch()部分添加一个pos.close即可.客户端最终得到一个零KB文件,但我想这比无限等待更好.
Play2 Scala框架中有一些为此而设计的东西:Enumerators。这与您的想法非常接近。
您应该查看此文档页面以了解详细信息
我在 Play2 Java API 中没有找到类似的东西,但是查看固件代码源,你有一个:
public static Results.Status ok(java.io.InputStream content, int chunkSize)
Run Code Online (Sandbox Code Playgroud)
方法似乎正是您正在寻找的方法。play.mvc.Results可以在和类中找到实现play.core.j.JavaResults。