2009-11-06 23 views
9

Me gustaría crear una página de resultados para una página de exportación de informes. Esta página de resultados debe mostrar el estado de la exportación y ofrecer la descarga de esta exportación.¿Ejecuta la acción del bean de respaldo en la carga?

La exportación se realiza mediante un método de acción. Puedo ejecutarlo a través de commandButton pero debe ejecutarse automáticamente en la carga.

¿Cómo puedo lograr esto?

JSF:

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

Copia de frijol:

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

Aclaración: ¿Es esto factible con a4j? Pensé en una solución que una solicitud Ajax desencadena mi acción downloadReport y su solicitud es la descarga del archivo.

Respuesta

15

También puede resolver esto en JSF 2.0 utilizando eventos del sistema de componentes, específicamente PreRenderViewEvent.

Simplemente cree una vista de descarga (/download.xhtml) que active un oyente de descarga antes del procesamiento.

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

Luego, en su informe de frijol (define utilizando JSR-299), que empuja el archivo y marcar la respuesta no es completa.

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

¡Eso es todo!

Puede vincular a la página de descarga (/download.jsf), o usar una metaetiqueta HTML para redirigir a ella en una página de presentación.

+0

He intentado con esta solución. Funciona solo si la página no tiene otro control. Si la página tiene otro control, como la selección del cuadro desplegable, y la página va y viene varias veces, 'download()' seguirá llamando y el valor se restablecerá para siempre. Por lo tanto, ¿hay alguna manera de proteger su ejecución a una sola vez para siempre? – huahsin68

2

Puede enviar solo una respuesta por solicitud. No puede enviar dos respuestas (la página misma y el archivo de descarga) por solicitud. Lo mejor que puedes hacer es usar Javascript para enviar un formulario (oculto) después de la carga de la página.

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

+1. Funcionará, pero me gustaría utilizar a4j para esto, lo siento por no mencionar (ver edición de aclaración). – guerda

7

La respuesta anterior enviará el formulario y tal vez cambie la navegación.

Use <rich:jsFunction action="#{bean.action}" name="loadFunction" /> y luego window.onload = loadFunction;

Cuestiones relacionadas