Java 使用播放框架和第三方API流式传输大文件

Java 使用播放框架和第三方API流式传输大文件,java,playframework,streaming,Java,Playframework,Streaming,我正在编写一个Play2应用程序,我正在努力解决一个文件流问题。 我使用具有以下签名的第三方API检索文件: FileMetadata getFile(OutputStream destination, String fileId) 在传统的Servlet应用程序中,如果我想将内容发送到我的客户端,我会执行以下操作: HttpServletResponse resp; myService.getFile(resp.getOutpuStream, fileId); 我的问题是,在play 2控

我正在编写一个Play2应用程序,我正在努力解决一个文件流问题。 我使用具有以下签名的第三方API检索文件:

FileMetadata getFile(OutputStream destination, String fileId)
在传统的Servlet应用程序中,如果我想将内容发送到我的客户端,我会执行以下操作:

HttpServletResponse resp;
myService.getFile(resp.getOutpuStream, fileId);
我的问题是,在play 2控制器类中,我无法访问底层的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);
 }
它可以工作,但在提供服务之前需要将整个内容加载到内存中,因此这不是一个选项(文件可能很大)

我在想一个解决方案,包括:

  • 在我的控制器内定义ByteArrayOutputStream(BAS)
  • 使用此baos in参数调用第三方API
  • 使用play框架的区块返回发送 一旦第三方API在内部写入内容,就会立即启动BAO
问题是,我不知道这是否可能(对getFile的调用被阻塞了,所以它需要多个线程和一个共享的输出流),也不知道这是否是过度杀伤力

有人曾经面对过这样的问题并找到了解决方案吗? 我提出的解决方案能解决我的问题吗

如有任何见解,将不胜感激

谢谢

编辑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();
          }
      }
}
编辑2


我找到了一种避免页面无限加载的方法,只需在工作线程的catch()部分添加一个pos.close。客户端最终会得到一个零KB的文件,但我想这比无限等待要好。

Play2 Scala框架中有一些东西就是为这个而设计的:
枚举数
。这与您的想法非常接近

你应该看看这个

我在Play2 Java API中没有找到类似的内容,但查看fw代码源代码,您有一个:

public static Results.Status ok(java.io.InputStream content, int chunkSize)

方法选择要查找的接缝。实现可以在
play.mvc.Results
play.core.j.JavaResults
类中找到。

关于play!邮件列表,最近有一个关于同一主题的讨论:


它包含一个小片段,允许不懂scala的人(比如我)使用Play!的scala流媒体接口

谢谢,我来看看。我不知道Scala,现在只使用API的Java部分,但如果它能帮助我解决问题,我会尝试一下。哎哟,我回答得太快了,我没注意到你用Java使用了play2。我在Play2 Java API中没有发现相同的概念…它似乎确实不存在,但应该可以将scala与Java@Davz混合使用。我编辑了我的答案,它表明控制器方法允许从InputStream@kheraus我接受你的回答,因为你把我带上了管道。我已经编辑了我的问题,把工作代码。谢谢。是的,我已经发了两封信;-)邮件列表中的代码与此页上的代码相同。