2010-05-26 21 views
11

Tôi đã tạo một ứng dụng JSF và tôi muốn nhúng một liên kết vào một trang mà khi được nhấp sẽ khiến bean sao lưu trộn một số xml và buộc mở hộp thoại lưu dưới dạng tải xuống để người dùng có thể chọn vị trí để lưu tệp. Tôi đã viết mã JAXB.Bắt buộc lưu đối thoại từ bất kỳ trình duyệt web nào từ ứng dụng JSF

Điều này được thực hiện như thế nào?

Cảm ơn

Trả lời

33

Đặt tiêu đề HTTP Content-Disposition để attachment. Thao tác này sẽ bật một hộp thoại Lưu dưới dạng. Bạn có thể làm điều đó bằng cách sử dụng HttpServletResponse#setHeader(). Bạn có thể nhận phản hồi servlet HTTP từ bên dưới mũ trùm JSF bằng ExternalContext#getResponse().

Trong ngữ cảnh JSF, bạn chỉ cần đảm bảo rằng bạn gọi FacesContext#responseComplete() sau đó để tránh việc bay IllegalStateException.

Kickoff dụ:

public void download() throws IOException { 
    FacesContext facesContext = FacesContext.getCurrentInstance(); 
    ExternalContext externalContext = facesContext.getExternalContext(); 
    HttpServletResponse response = (HttpServletResponse) externalContext.getResponse(); 

    response.reset(); // Some JSF component library or some Filter might have set some headers in the buffer beforehand. We want to get rid of them, else it may collide. 
    response.setContentType("application/xml"); // Check http://www.iana.org/assignments/media-types for all types. Use if necessary ServletContext#getMimeType() for auto-detection based on filename. 
    response.setHeader("Content-disposition", "attachment; filename=\"name.xml\""); // The Save As popup magic is done here. You can give it any filename you want, this only won't work in MSIE, it will use current request URL as filename instead. 

    BufferedInputStream input = null; 
    BufferedOutputStream output = null; 

    try { 
     input = new BufferedInputStream(getYourXmlAsInputStream()); 
     output = new BufferedOutputStream(response.getOutputStream()); 

     byte[] buffer = new byte[10240]; 
     for (int length; (length = input.read(buffer)) > 0;) { 
      output.write(buffer, 0, length); 
     } 
    } finally { 
     close(output); 
     close(input); 
    } 

    facesContext.responseComplete(); // Important! Else JSF will attempt to render the response which obviously will fail since it's already written with a file and closed. 
} 
+0

cảm ơn rất nhiều. Tôi đặt mã trong và bây giờ, khi tôi nhấp vào liên kết, trình duyệt (FF) sẽ thay thế trang hiện tại bằng một trang chứa nội dung tệp thay vì bật lên cửa sổ tải xuống. Tôi có thể làm gì sai? – volvox

+1

Hãy thử trong một trình duyệt khác (IE, Chrome) hoặc khởi động lại FF với cấu hình sạch sẽ. Có thể xảy ra một webbrowser được cấu hình là ứng dụng mặc định cho các tệp XML và các tệp XML sẽ được mở tự động khi được tải xuống. – BalusC

+1

Ồ, cũng đảm bảo rằng đây không phải là yêu cầu không đồng bộ (ajaxical), mà chỉ là một yêu cầu đồng bộ ("plain vanilla"). I E. chỉ cần sử dụng 'h: commandLink' hoặc' h: commandButton', nhưng không phải là các thành phần 'UICommand' được hỗ trợ bởi RichFaces, Ajax4jsf, IceFaces, vv. – BalusC

3

Sử dụng các tiêu đề HTTP content-disposition: attachment

0

đôi khi bạn cần để buộc các nhà văn để gửi nội dung cho khách hàng bằng cách gọi response.getWriter().flush(); trước khi đóng cửa nhà văn. Điều này nhắc nhở lưu như popup trong trường hợp của tôi.

+1

Điều này chỉ cần thiết khi chuỗi yêu cầu-đáp ứng chứa một triển khai 'HttpServletResponseWrapper' tùy chỉnh bị hỏng mà trả về một trình soạn thảo tùy chỉnh bị hỏng. Đối với việc triển khai Servlet và JSF chuẩn, điều này hoàn toàn không cần thiết. Các giải pháp nên được để sửa chữa mà thực hiện wrapper/nhà văn và không phải bằng tay tuôn ra các nhà văn ở khắp mọi nơi trong mã. – BalusC

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