2014-09-05 13 views
5

Chúng tôi đang trình chiếu một tập tin nhị phân cho người dùng của chúng tôi, sau khi thủ tục xây dựng trong SO câu hỏi How to provide a file download from a JSF backing bean?Làm cách nào để tải xuống tệp tải xuống và hiển thị thông báo khuôn mặt JSF?

Nói chung các công việc hoạt động như dự định, nhưng trong quá trình tạo ra các tập tin xuất khẩu thu hồi lỗi có thể xảy ra và chúng tôi muốn để hiển thị chúng dưới dạng cảnh báo cho người dùng. Bản thân tệp sẽ vẫn được tạo trong trường hợp đó. Vì vậy, chúng tôi muốn xuất khẩu đó tiếp tục hiển thị các thông báo hiển thị khuôn mặt.

Chỉ cần nhấn mạnh vào điều này: Có, có điều gì đó không ổn với dữ liệu, nhưng người dùng của chúng tôi muốn xuất để tiếp tục và nhận tệp sai sót đó. Sau đó, họ muốn có một cái nhìn tại các tập tin, liên hệ với nhà cung cấp của họ và gửi cho anh ta một thông điệp về lỗ hổng.

Vì vậy, tôi cần xuất để hoàn tất trong mọi trường hợp.

Nhưng nó không hoạt động như chúng tôi muốn. Tôi đã tạo một ví dụ đơn giản để minh họa cách tiếp cận của chúng tôi.

Thay vào đó, chúng tôi đang xem xét một Bean sẽ giữ thông báo và hiển thị chúng sau khi xuất. Nhưng có lẽ có một cách với các cơ chế tích hợp JSF để đạt được điều này.

khiển

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

JSF Trang

<!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 cho ví dụ SSCCE phù hợp. –

+0

'org.apache.tomcat.util.http.fileupload.util.Streams' là Tomcat cụ thể. – BalusC

Trả lời

6

Vì bạn đang thực sự thực hiện một phản ứng tập tin tải về và không phải là một JSF một, nó không phải là có thể cho thông điệp của bạn sẽ được bổ sung trong khi yêu cầu tương tự xảy ra. Giải pháp sạch nhất cho tôi, tránh các yêu cầu không đồng bộ của hacky là sử dụng một bean @ViewScoped và thực hiện tác vụ của bạn theo hai bước. Vì vậy, để có một nút để chuẩn bị tập tin của bạn, thông báo cho người sử dụng sau này và cho phép anh ta để tải về nó khi nó sẵn sàng:

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

Lưu ý giải pháp này có thể có giá trị cho các tập tin nhỏ (toàn bộ nội dung của họ là được lưu trữ trong bộ nhớ trong khi người dùng giữ trong cùng một chế độ xem). Tuy nhiên, nếu bạn định sử dụng nó với các tệp lớn (hoặc số lượng lớn người dùng), tốt nhất là lưu trữ nội dung của nó trong một tệp tạm thời và hiển thị liên kết tới tệp đó thay vì nút tải xuống. Đó là những gì @BalusC đề xuất trong tài liệu tham khảo bên dưới.

Xem thêm:

+2

Bạn có thể sử dụng JS để gọi hành động tiếp theo. – BalusC

+0

@BalusC nó sẽ rất tốt đẹp để xem giải pháp JS của bạn. Bạn có thể gửi một liên kết? – douglaslps

-1

Bạn có thể thử này: Đối primefaces, bạn có thể sử dụng lệnh từ xa thay vì liên kết lệnh, và gọi nó với tên onSuccess của nó. Nếu không, hãy đưa một widget var vào commandlink và gọi phương thức click của nó.

+0

Thêm mô tả và nội dung hữu ích hơn để hỗ trợ câu trả lời của bạn sẽ hữu ích.Nếu không, điều này sẽ chỉ bị xóa. –

Các vấn đề liên quan