2009-11-06 6 views
9

Ich möchte eine Ergebnisseite für eine Berichtsexport-Seite erstellen. Diese Ergebnisseite muss den Status des Exports anzeigen und den Download dieses Exports anbieten.Back-Bean-Aktion beim Laden ausführen?

Der Export erfolgt in einer Aktionsmethode. Ich kann es über eine commandButton ausführen, aber es muss automatisch beim Laden ausgeführt werden.

Wie kann ich das erreichen?

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

Klarstellung: Ist das machbar mit a4j? Ich dachte an eine Lösung, dass eine Ajax Anfrage meine downloadReport Aktion auslöst und ihre Anfrage ist der Dateidownload.

Antwort

15

Sie können dies auch in JSF 2.0 lösen, indem Sie Komponentensystemereignisse verwenden, insbesondere das PreRenderViewEvent.

Erstellen Sie einfach eine Download-Ansicht (/download.xhtml), die vor dem Rendern einen Download-Listener auslöst.

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

Dann in Ihrem Bericht Bean (definiert mit JSR-299), können Sie die Datei aus und markieren Sie die Antwort als komplette drücken.

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

Das ist alles, was es gibt!

Sie können entweder auf die Download-Seite (/download.jsf) verlinken oder ein HTML-Meta-Tag verwenden, um darauf auf einer Splash-Seite umzuleiten.

+0

Ich habe diese Lösung versucht. Es funktioniert nur, wenn die Seite kein anderes Steuerelement hat. Wenn die Seite andere Steuerelemente wie die Dropdown-Box-Auswahl hat und die Seite ein paar Mal vor und zurück ist, ruft 'download()' weiter auf und der Wert wird für immer zurückgesetzt. Gibt es also einen Weg, seine Ausführung für immer nur einmal zu schützen? – huahsin68

2

Sie können nur eine Antwort pro Anfrage senden. Sie können nicht zwei Antworten (die Seite selbst und die Download-Datei) pro Anfrage senden. Am besten können Sie Javascript verwenden, um nach dem Laden der Seite ein (verstecktes) Formular zu senden.

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

+1. Wird funktionieren, aber ich würde gerne a4j dafür verwenden, sorry für die Nennung (siehe Klarstellung bearbeiten). – guerda

7

Die vorherige Antwort wird das Formular senden und vielleicht die Navigation ändern.

Verwenden Sie <rich:jsFunction action="#{bean.action}" name="loadFunction" /> und dann window.onload = loadFunction;

Verwandte Themen