Search code examples
jsfevent-handlingrichfaces

Execute backing bean action on load?


I would like to build a results page for a report export page. This results page must display the status of the export and offer the download of this export.

The export is done in an action method. I can execute it via a commandButton but it must be executed automatically on load.

How can I accomplish this?

JSF:

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

Backing bean:

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

Clarification: Is this feasible with a4j? I thought of a solution that an Ajax request triggers my downloadReport action and its request is the file download.


Solution

  • You can also solve this in JSF 2.0 using component system events, specifically the PreRenderViewEvent.

    Just create a download view (/download.xhtml) that fires a download listener before render.

    <?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>
    

    Then, in your report bean (defined using JSR-299), you push the file and mark the response as complete.

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

    That's all there is to it!

    You can either link to the download page (/download.jsf), or use a HTML meta tag to redirect to it on a splash page.