2012-04-24 65 views
2

我成功使用Play 1.2.4向使用renderBinary()方法的用戶提供大型二進制文件下載。在Play框架中完成文件下載時的通知

我想知道用戶何時真正完成下載。一般來說,我知道這是有點可能的,因爲我以前做過。在我的網站的舊版本中,我編寫了一個簡單的servlet來提供二進制文件下載。一旦該servlet寫完文件的內容,就會發送通知。當然不完美,但有用。在我的測試中,它確實提供了用戶下載文件多長時間的指示。

回顧Play源代碼,我發現play.mvc.results.RenderBinary類有一個我可以使用的方便的apply()方法。我編寫了自己的RenderBinary版本,以便在apply()方法完成寫出文件內容後發送通知。

我發現的問題是調用response.out.write()明顯緩存了傳出字節(通過Netty?),所以即使我寫出幾兆字節的數據,調用play.mvc.Http .Response.out.write()在幾秒鐘內完成,即使下載器需要幾分鐘時間才能下載文件。

我不介意編寫自定義類,儘管我更喜歡使用庫存Play 1.2.4發行版。

關於如何獲得文件下載結束時間通知給用戶瀏覽器的任何想法?

回答

0

看來,這可能會幫助你,因爲它剷球一個某種程度上類似的問題:

Detect when browser receives file download

我不知道你會EB能夠通過renderBinary做到這一點,也不是@After註解控制器。一些瀏覽器端檢測到的下載,然後通知服務器(ping下載的結束)將工作。

可能有一種替代方案:使用的WebSockets(通過插座流的文件,然後爲德客戶回答),但它可能是矯枉過正這:)

+0

通過websockets上傳文件的關鍵修復即將推出... https://github.com/playframework/play1/pull/709 – 2013-12-16 14:28:18

0

可以使用ArchivedEventStream

首先創建一個序列化ArcivedEventStream類..

public class Stream<String> extends ArchivedEventStream<String> implements Serializable{ 

    public Stream(int arg0) { 
     super(arg0); 
    } 

} 

那麼你的控制器上......

public static void downloadPage(){ 
    Stream<String> userStream = Cache.get(session.getId(),Stream.class); 
    if(userStream == null){ 
     userStream = new Stream<String>(5); 
     Cache.add(session.getId(), userStream); 
    } 
    render(); 
} 

public static void download(){ 
    await(10000);// to provide some latency. actually no needed 
    renderBinary(Play.getFile("yourfile!")); 
} 

public static void isDownloadFinished(){ 
    Stream<String> userStream = Cache.get(session.getId(),Stream.class); 
    List<IndexedEvent<String>> list = await(userStream.nextEvents(0)); 
    renderJSON(list.get(0).data); 

} 

@After(only="download") 
static void after(){ 
    Stream<String> userStream = Cache.get(session.getId(),Stream.class); 
    userStream.publish("ok"); 
} 

在HTML ...

#{extends 'main.html' /} 

#{set title:'downloadPage' /} 
<a href="download" target="_blank">download</a> 

<script> 
$(document).ready(function(){ 
$.ajax('/application/isDownloadFinished',{success:function(data){ 
    if(data){ 
     console.log("downloadFinished");  
    } 

}}); 
}); 

</script> 

當你下載完了,原始頁面將檢索通知。

此代碼只是一個示例。您可以閱讀ArchivedEventStream的API並自行實施。

+0

除了ArchivedEventStream將DROP數據包在緩衝區最大化....一個輪詢請求修復只有websockets的EventStream是在這裏......有人需要說出來,如果他們想要ArchivedEventStream不像今天一樣丟棄數據包... https ://github.com/playframework/play1/pull/709 – 2013-12-16 14:29:27