2014-09-05 18 views
5

SO istendiği gibi iş akışı çalışır Genelde How to provide a file download from a JSF backing bean?Dosya akışı nasıl yapılır ve bir JSF karşı karşıya mesaj gönderir? Biz prosedür takip eden kullanıcılara bir ikili dosya akışı vardır

sorgulamaya detaylandırılır fakat verilen dosyaların oluşturma sırasında kazanılabilir hatalar meydana gelebilir ve istediğimiz Bunları kullanıcıya bir uyarı olarak görüntülemek için Dosya bu durumda yine de oluşturulmalıdır. Dolayısıyla, bu dışa aktarma işleminin ve görüntü yüzleri iletilerine devam etmesini istiyoruz.

Sadece bunu vurgulamak için: Evet, verilerle ilgili bir sorun yok, ancak kullanıcılarımız ihracatın devam etmesini ve bu hatalı dosyayı almasını istiyorlar. Ardından, dosyaya bir göz atmak, satıcıyla iletişim kurmak ve kusurla ilgili bir mesaj göndermek istiyorlar.

Her durumda bitirmek için dışa aktarma ihtiyacım var.

Ama bizim istediğimiz gibi çalışmıyor. Yaklaşımımızı göstermek için basitleştirilmiş bir örnek oluşturdum. Alternatif olarak, mesajları tutacak ve ihracattan sonra gösterecek bir Bean'i düşünmekteyiz. Ama muhtemelen bunu başarmak için JSF yerleşik mekanizmaların bir yolu var.

Kontrolör

import java.io.ByteArrayInputStream; 
import java.io.IOException; 
import java.io.OutputStream; 
import javax.faces.application.FacesMessage; 
import javax.faces.bean.ManagedBean; 
import javax.faces.bean.RequestScoped; 
import javax.faces.context.ExternalContext; 
import javax.faces.context.FacesContext; 
import org.apache.tomcat.util.http.fileupload.util.Streams; 

@ManagedBean 
@RequestScoped 
public class ExportController { 

    public void export() { 
     FacesContext fc = FacesContext.getCurrentInstance(); 
     ExternalContext ec = fc.getExternalContext(); 

     byte[] exportContent = "Hy Buddys, thanks for the help!".getBytes(); 
     // here something bad happens that the user should know about 
     // but this message does not go out to the user 
     fc.addMessage(null, new FacesMessage("record 2 was flawed")); 

     ec.responseReset(); 
     ec.setResponseContentType("text/plain"); 
     ec.setResponseContentLength(exportContent.length); 
     String attachmentName = "attachment; filename=\"export.txt\""; 
     ec.setResponseHeader("Content-Disposition", attachmentName); 
     try { 
      OutputStream output = ec.getResponseOutputStream(); 
      Streams.copy(new ByteArrayInputStream(exportContent), output, false); 
     } catch (IOException ex) { 
      ex.printStackTrace(); 
     } 

     fc.responseComplete(); 
    } 
} 

MTU Sayfa aslında bir dosya indirme tepkisi yapmakta olduğunuz ve iletiniz eklenecek için MTU biri bu mümkün değil bir değil beri

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" 
     xmlns:h="http://java.sun.com/jsf/html" 
     xmlns:f="http://java.sun.com/jsf/core" 
     xmlns:ui="http://java.sun.com/jsf/facelets" 
     xmlns:p="http://primefaces.org/ui"> 

    <f:view contentType="text/html"> 
     <h:body> 
      <h:form prependId="false"> 
       <h:messages id="messages" /> 
       <h:commandButton id="download" value="Download" 
           actionListener="#{exportController.export()}" /> 
      </h:form> 
     </h:body> 
    </f:view> 
</html> 
+0

+1. –

+0

'org.apache.tomcat.util.http.fileupload.util.Streams', Tomcat'a özgüdür. – BalusC

cevap

6

aynı istek olduğunda. Benim için en temiz çözüm, zorlu asenkron isteklerden kaçınmak, @ViewScoped fasulye kullanmak ve görevinizi iki adımda yapmaktır. Yani, dosyanızı hazırlarken daha sonra kullanıcı bildiren ve hazır olduğunda onu indirmek için izin için bir düğme var:

@ManagedBean 
@ViewScoped 
public class ExportController implements Serializable { 

    private byte[] exportContent; 

    public boolean isReady() { 
     return exportContent != null; 
    } 

    public void export() { 
     FacesContext fc = FacesContext.getCurrentInstance(); 
     ExternalContext ec = fc.getExternalContext(); 
     ec.responseReset(); 
     ec.setResponseContentType("text/plain"); 
     ec.setResponseContentLength(exportContent.length); 
     String attachmentName = "attachment; filename=\"export.txt\""; 
     ec.setResponseHeader("Content-Disposition", attachmentName); 
     try { 
      OutputStream output = ec.getResponseOutputStream(); 
      Streams.copy(new ByteArrayInputStream(exportContent), output, false); 
     } catch (IOException ex) { 
      ex.printStackTrace(); 
     } 

     fc.responseComplete(); 
    } 

    public void prepareFile() { 
     exportContent = "Hy Buddys, thanks for the help!".getBytes(); 
     // here something bad happens that the user should know about 
     FacesContext.getCurrentInstance().addMessage(null, 
       new FacesMessage("record 2 was flawed")); 
    } 
} 
<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:f="http://java.sun.com/jsf/core" 
    xmlns:ui="http://java.sun.com/jsf/facelets" 
    xmlns:p="http://primefaces.org/ui"> 

<f:view contentType="text/html"> 
    <h:body> 
     <h:form> 
      <h:messages id="messages" /> 
      <h:commandButton value="Prepare" 
       action="#{exportController.prepareFile}" /> 
      <h:commandButton id="download" value="Download" 
       disabled="#{not exportController.ready}" 
       action="#{exportController.export()}" /> 
     </h:form> 
    </h:body> 
</f:view> 
</html> 

Not bu çözüm küçük dosyalar için geçerli olabilir (onların tüm içeriğidir kullanıcı aynı görünümde kalırken bellekte saklanır). Ancak, büyük dosyalarla (veya çok sayıda kullanıcıyla) kullanacaksanız, içeriğinizi geçici bir dosyada saklamak ve bir indirme düğmesi yerine ona bir bağlantı göstermek en iyisidir. @BalusC'nin aşağıdaki referansta önerdiği şey budur.

Ayrıca bakınız:

+2

Bir sonraki eylemi çağırmak için JS'yi kullanabilirsiniz. – BalusC

+0

@BalusC JS çözümünüzü görmek çok güzel olurdu. Bir bağlantı gönderebilir misin? – douglaslps

-1

Bunu denemek olabilir: primefaces için , bunun yerine komut bağlantının uzaktan komutunu kullanın ve adı onSuccess ile çağırabilirsiniz. Aksi takdirde, komut bağlantısına bir widget var ve tıklama yöntemini çağır. Uygun SSCCE örneği için

+0

Daha fazla açıklama eklemek ve cevabınızı desteklemek için yararlı içerik yararlı olacaktır.Aksi takdirde bu sadece silinir. –

İlgili konular