2009-11-06 102 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;