2010-12-10 5 views
1

JSF/Seam. Ich habe eine Seite, die einige Parameter akzeptiert, die vom Benutzer über ein Formular bereitgestellt werden, und dann (wenn der Benutzer auf eine Schaltfläche auf der Seite klickt) generiert der Server eine Datei und sendet sie in der Antwort, so dass der Benutzer mit einer Sicherungskopie aufgefordert wird. als Dialog. HierSeitennavigation/Render-Antwortphase wird ignoriert, wenn die Antwort eine Datei enthält

ist das Szenario, das ich habe, Probleme mit:

  1. Wenn der Benutzer zunächst ungültige Eingabe eingibt und klickt dann auf die Schaltfläche, verarbeitet Seam die Anfrage, aber hält an der Prozessvalidierungen Phase. Meine Seite zeigt dann die Validierungsfehlermeldung an.
  2. Wenn der Benutzer dann die richtige Eingabe eingibt und auf die Schaltfläche klickt, ruft Seam meinen Aktionshandler auf, die Datei wird generiert und an den Benutzer in der Antwort gesendet - , aber die Validierungsfehlermeldung wird weiterhin angezeigt!

Anfangs habe ich versucht, einige Hacks die rerendering des <h:messages/> Tag zu zwingen, aber nichts war zufriedenstellend. Ich vermute jetzt, dass die Ursache darin liegt, dass Seam nicht in die Render-Response-Phase eintritt, wenn ich eine Datei in die Antwort setze.

Hier ist meine Schaltfläche:

<h:commandButton value="#{messages.Reports_RunReportPDF}" 
       action="#{bean.generateReportPdf}"/> 

Und hier ist meine Action-Handler:

public String generateReportPdf() throws IOException { 
    FacesContext facesContext = FacesContext.getCurrentInstance(); 
    HttpServletResponse response = (HttpServletResponse)facesContext.getExternalContext().getResponse(); 

    ServletOutputStream servletOutputStream = response.getOutputStream(); 

    // add this header to make browser prompt user with a save-as dialog 
    response.addHeader("Content-Disposition", 
        "attachment;filename=" + reportName + ".pdf"); 
    response.setContentType(exportType.contentType()); 

    try { 
    HashMap<String, Object> parameters = getReportParameters(); 
    ReportContent content = createReport(parameters); 

    servletOutputStream.write(content.getContents()); 
    servletOutputStream.flush(); 
    servletOutputStream.close(); 
    } catch (ReportingException e) { 
    e.printStackTrace(); 
    return "fail"; 
    } 

    return "success"; 
} 

Wenn ich den Code Kommentar-out, der die Datei erstellt (und nur "success" zurückkehren, folgt die Seite der Navigationsregeln, die ich korrekt eingerichtet habe. Aber mit der Datei bleibt die Seite genau gleich wie vor dem Drücken der Taste.

Wie kann ich eine Datei in der Antwort zurückgeben und das <h:messages/>-Tag neu gerendert werden?

Antwort

0

Also, wie kann ich beide zurückgeben eine Datei in der Antwort, und bewirken, dass der Tag erneut gerendert werden?

Das ist mit einer einzelnen HTTP-Anfrage nicht möglich. Sie können nur eine Antwort pro Anfrage zurückgeben. Dies ist keine JSF-Einschränkung, dies ist eine HTTP-Beschränkung.

Sie verwenden can JavaScript verwenden, um zwei HTTP-Anforderungen mit einem einzigen Klick auszulösen, aber in Ihrem speziellen Fall würde dies nicht gut funktionieren, da die JSF-Anforderung für die Nachricht vom Ergebnis der Anforderung für den PDF-Download abhängt. Ich sehe keine anderen Möglichkeiten, als das Servlet eine Eigenschaft einer verwalteten Sitzung definieren zu lassen, die den Status des PDF-Exports darstellt und eine Ajax-Abfrage einführt, die diese Eigenschaft in Intervallen anfordert und stoppt, wenn sie nicht mehr null ist.

+0

'" Das ist mit einer einzelnen HTTP-Anfrage nicht möglich. " Ich kann sehen, wie die Ajax-Polling-Lösung funktionieren könnte, aber das ist keine ideale Lösung für uns, also sieht es so aus, als ob ich darüber nachdenken müsste, das aus einem anderen Blickwinkel zu betrachten. Prost. –

0

, dass Sie hinzufügen dies gewährleisten, so nach dem Schreiben auf Ihre Methode

//Skip the rest of JSF phases 
FacesContext.getCurrentInstance().responseComplete(); 

Sie auch die Nähe in einem finally-Block hinzufügen möchten, dass der Strom richtig tritt auf, wenn Ausnahme geschlossen. Oder die @Cleanup Anmerkung aus Lombok hinzufügen, und es wird es für Sie automatisch das Gespräch beenden, bevor die Umleitung, damit die Validierungsnachricht

aktualisiert

Wenn Sie sich in einem langen laufenden Gespräch sind, können Sie tun wird entfernt.

@End(beforeRedirect=true)

+0

Diese Zeile war ursprünglich in meinem Code - ich entfernte es, um zu sehen, was der Effekt wäre. Es wirkt sich nicht auf die erneute Bereitstellung meines Nachrichten-Tags aus. –