2009-11-06 104 views
9

我想爲報表導出頁面創建一個結果頁面。此結果頁面必須顯示導出的狀態並提供此導出的下載。在加載時執行backing bean操作?

導出是在一個操作方法中完成的。我可以通過commandButton執行它,但它必須在加載時自動執行。

我怎樣才能做到這一點?

JSF:

<h:commandButton value="Download report" action="#{resultsView.downloadReport}"/> 

支持bean:

public String downloadReport() { 
    ... 
    FileDownloadUtil.downloadContent(tmpReport, REPORT_FILENAME); 
    // Stay on this page 
    return null; 
    } 

澄清:這是可行的與A4J?我想到了一個解決方案,即Ajax請求觸發我的動作,其請求是文件下載。

回答

15

您還可以使用組件系統事件(特別是PreRenderViewEvent)在JSF 2.0中解決此問題。

只需創建一個下載視圖(/download.xhtml),它在渲染之前觸發下載偵聽器。

<?xml version="1.0" encoding="UTF-8"?> 
<f:view 
    xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:f="http://java.sun.com/jsf/core"> 
    <f:event type="preRenderView" listener="#{reportBean.download}"/> 
</f:view> 

然後,在你的報告豆,你把文件和標記響應,完整(使用JSR-299定義)。

public @Named @RequestScoped class ReportBean { 

    public void download() throws Exception { 
     FacesContext ctx = FacesContext.getCurrentInstance(); 
     pushFile(
      ctx.getExternalContext(), 
      "/path/to/a/pdf/file.pdf", 
      "file.pdf" 
    ); 
     ctx.responseComplete(); 
    } 

    private void pushFile(ExternalContext extCtx, 
     String fileName, String displayName) throws IOException { 
     File f = new File(fileName); 
     int length = 0; 
     OutputStream os = extCtx.getResponseOutputStream(); 
     String mimetype = extCtx.getMimeType(fileName); 

     extCtx.setResponseContentType(
     (mimetype != null) ? mimetype : "application/octet-stream"); 
     extCtx.setResponseContentLength((int) f.length()); 
     extCtx.setResponseHeader("Content-Disposition", 
     "attachment; filename=\"" + displayName + "\""); 

     // Stream to the requester. 
     byte[] bbuf = new byte[1024]; 
     DataInputStream in = new DataInputStream(new FileInputStream(f)); 

     while ((in != null) && ((length = in.read(bbuf)) != -1)) { 
     os.write(bbuf, 0, length); 
     } 

     in.close(); 
    } 
} 

這就是它的全部!

您可以鏈接到下載頁面(/download.jsf),也可以使用HTML元標記在啓動頁面上重定向到它。

+0

我試過這個解決方案。它只有在頁面沒有其他控制的情況下才有效。如果頁面具有其他控件(如下拉框選擇),並且頁面來回多次,則「download()」將繼續調用並且該值將永久重置。因此,有沒有辦法永遠保護它的執行只有一次? – huahsin68 2012-08-30 02:33:48

2

每個請求只能發送一個響應。每個請求都不能發送兩個響應(頁面本身和下載文件)。最好你可以做的是在頁面加載後使用Javascript提交(隱藏)表單。

window.onload = function() { 
    document.formname.submit(); 
} 
+0

+1。將工作,但我想用a4j這個,抱歉不提(見澄清編輯)。 – guerda 2009-11-06 12:38:09

7

上一個答案將提交表單並可能更改導航。

使用<rich:jsFunction action="#{bean.action}" name="loadFunction" /> 然後在window.onload = loadFunction;