2009-11-06 22 views
9

Chciałbym zbudować stronę wyników dla strony eksportu raportu. Strona wyników musi wyświetlać status eksportu i umożliwiać pobranie tego eksportu.Wykonaj operację cofania komponentu bean podczas ładowania?

Eksport odbywa się za pomocą metody akcji. Mogę go wykonać przez commandButton, ale musi on zostać wykonany automatycznie po załadowaniu.

Jak mogę to zrobić?

JSF:

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

kopii fasola:

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

Wyjaśnienie: Czy to jest wykonalne z a4j? Pomyślałem o rozwiązaniu, które powoduje, że żądanie Ajax wyzwala moją akcję downloadReport, a jej żądanie to pobranie pliku.

Odpowiedz

15

Można to również rozwiązać w JSF 2.0 przy użyciu zdarzeń systemu komponentów, w szczególności PreRenderViewEvent.

Po prostu utwórz widok pobierania (/download.xhtml), który uruchamia program nasłuchujący do pobrania przed renderowaniem.

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

Następnie w raporcie fasoli (określone za pomocą JSR-299), kiedy pchasz plik i zaznaczyć odpowiedź jako kompletne.

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

To wszystko, o to chodzi!

Możesz połączyć ze stroną pobierania (/download.jsf) lub użyć metatagu HTML, aby przekierować do niego na stronie powitalnej.

+0

Mam spróbować tego rozwiązania. Działa tylko wtedy, gdy strona nie ma innej kontroli. Jeśli strona ma inną kontrolę, np. Wybór pola wyboru, a strona jest kilka razy w przód iw tył, funkcja 'download()' będzie nadal wywoływać, a wartość zostanie na zawsze zresetowana. Czy istnieje zatem sposób, by na zawsze ochronić jego egzekucję na zawsze? – huahsin68

2

Możesz wysłać tylko jedną odpowiedź na każde żądanie. Nie można wysłać dwóch odpowiedzi (samej strony i pliku do pobrania) na żądanie. Najlepsze, co możesz zrobić, to użyć Javascript, aby przesłać (ukryty) formularz po wczytaniu strony.

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

+1. Będzie działać, ale chciałbym użyć a4j do tego, przepraszam, że nie wspomniałem (zobacz edycję wyjaśnień). – guerda

7

Poprzednia odpowiedź spowoduje przesłanie formularza i ewentualnie zmianę nawigacji.

Użyj <rich:jsFunction action="#{bean.action}" name="loadFunction" /> , a następnie window.onload = loadFunction;

Powiązane problemy