परिचय
आप सब कुछ प्राप्त कर सकते हैं ExternalContext
। JSF 1.x में, आप कच्ची HttpServletResponse
वस्तु प्राप्त कर सकते हैं ExternalContext#getResponse()
। JSF 2.x में, आप JSF हुड के तहत से ExternalContext#getResponseOutputStream()
हड़पने की आवश्यकता के बिना नए प्रतिनिधि विधियों के गुच्छा का उपयोग कर सकते हैं HttpServletResponse
।
प्रतिक्रिया पर, आपको Content-Type
हेडर सेट करना चाहिए ताकि क्लाइंट को पता चल सके कि कौन सी एप्लिकेशन प्रदान की गई फ़ाइल के साथ संबद्ध है। और, आपको Content-Length
हेडर सेट करना चाहिए ताकि क्लाइंट डाउनलोड प्रगति की गणना कर सके, अन्यथा यह अज्ञात होगा। और, आपको Content-Disposition
शीर्षलेख सेट करना चाहिए, attachment
यदि आप एक सेव अस डायलॉग चाहते हैं , अन्यथा क्लाइंट इसे इनलाइन प्रदर्शित करने का प्रयास करेगा। अंत में सिर्फ फाइल कंटेंट को रिस्पॉन्स आउटपुट स्ट्रीम में लिखें।
सबसे महत्वपूर्ण हिस्सा FacesContext#responseComplete()
जेएसएफ को सूचित करने के लिए कॉल करना है कि फाइल को प्रतिक्रिया में लिखने के बाद उसे नेविगेशन और रेंडरिंग नहीं करना चाहिए, अन्यथा प्रतिक्रिया का अंत पृष्ठ के HTML सामग्री, या पुराने JSF संस्करणों के साथ प्रदूषित हो जाएगा। , आपको IllegalStateException
एक संदेश के साथ मिलेगा जैसे getoutputstream() has already been called for this response
कि JSF कार्यान्वयन getWriter()
HTML रेंडर करने के लिए कहता है।
Ajax को बंद करें / रिमोट कमांड का उपयोग न करें!
आपको केवल यह सुनिश्चित करने की आवश्यकता है कि कार्रवाई विधि को अजाक्स अनुरोध के द्वारा नहीं कहा जाता है, लेकिन यह कि आपको एक सामान्य अनुरोध के रूप में कहा जाता है, जैसे कि आप आग लगाते हैं <h:commandLink>
और <h:commandButton>
। अजाक्स अनुरोध और दूरस्थ कमांड को जावास्क्रिप्ट द्वारा नियंत्रित किया जाता है जो बदले में सुरक्षा कारणों से, अजाक्स प्रतिक्रिया की सामग्री के साथ एक सेव अस डायलॉग को बाध्य करने की कोई सुविधा नहीं है ।
यदि आप उदाहरण के लिए PrimeFaces का उपयोग कर रहे हैं <p:commandXxx>
, तो आपको यह सुनिश्चित करने की आवश्यकता है कि आप ajax="false"
विशेषता के माध्यम से स्पष्ट रूप से ajax को बंद कर दें । यदि आप ICEfaces का उपयोग कर रहे हैं, तो आपको <f:ajax disabled="true" />
कमांड कंपोनेंट में घोंसला बनाने की आवश्यकता है ।
जेनेरिक जेएसएफ 2.x उदाहरण
public void download() throws IOException {
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
ec.responseReset();
ec.setResponseContentType(contentType);
ec.setResponseContentLength(contentLength);
ec.setResponseHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
OutputStream output = ec.getResponseOutputStream();
fc.responseComplete();
}
जेनेरिक जेएसएफ 1.x उदाहरण
public void download() throws IOException {
FacesContext fc = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) fc.getExternalContext().getResponse();
response.reset();
response.setContentType(contentType);
response.setContentLength(contentLength);
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
OutputStream output = response.getOutputStream();
fc.responseComplete();
}
आम स्थिर फ़ाइल उदाहरण
यदि आपको स्थानीय डिस्क फ़ाइल सिस्टम से एक स्थिर फ़ाइल को स्ट्रीम करने की आवश्यकता है, तो नीचे दिए गए कोड को प्रतिस्थापित करें:
File file = new File("/path/to/file.ext");
String fileName = file.getName();
String contentType = ec.getMimeType(fileName); // JSF 1.x: ((ServletContext) ec.getContext()).getMimeType(fileName);
int contentLength = (int) file.length();
// ...
Files.copy(file.toPath(), output);
आम गतिशील फ़ाइल उदाहरण
यदि आपको डायनामिक रूप से जेनरेट की गई फ़ाइल, जैसे कि पीडीएफ या एक्सएलएस, को स्ट्रीम करने की आवश्यकता है, तो बस output
वहीं प्रदान करें जहां एपीआई का उपयोग किया जा रहा है OutputStream
।
जैसे iText PDF:
String fileName = "dynamic.pdf";
String contentType = "application/pdf";
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, output);
document.open();
document.close();
जैसे Apache POI HSSF:
String fileName = "dynamic.xls";
String contentType = "application/vnd.ms-excel";
HSSFWorkbook workbook = new HSSFWorkbook();
workbook.write(output);
workbook.close();
ध्यान दें कि आप यहां सामग्री की लंबाई निर्धारित नहीं कर सकते। इसलिए आपको प्रतिक्रिया सामग्री की लंबाई निर्धारित करने के लिए लाइन को हटाने की आवश्यकता है। यह तकनीकी रूप से कोई समस्या नहीं है, केवल नुकसान यह है कि एंड्यूसर को एक अज्ञात डाउनलोड प्रगति प्रस्तुत की जाएगी। यदि यह महत्वपूर्ण है, तो आपको वास्तव में पहले एक स्थानीय (अस्थायी) फ़ाइल में लिखना होगा और फिर पिछले अध्याय में दिखाए अनुसार प्रदान करना होगा।
उपयोगिता विधि
आप JSF उपयोगिता पुस्तकालय उपयोग कर रहे हैं OmniFaces , तो आप तीन सुविधाजनक में से एक का उपयोग कर सकते Faces#sendFile()
या तो एक लेने के तरीकों File
, या एक InputStream
, या एक byte[]
, और निर्दिष्ट करने के लिए कि क्या फ़ाइल एक लगाव (के रूप में डाउनलोड किया जाना चाहिए true
) या इनलाइन ( false
)।
public void download() throws IOException {
Faces.sendFile(file, true);
}
हां, यह कोड पूर्ण है-जैसा है। आपको अपने आप को बुलाने की जरूरत नहीं है responseComplete()
। यह विधि आईई-विशिष्ट हेडर और UTF-8 फ़ाइलनाम के साथ भी ठीक से व्यवहार करती है। आप यहां सोर्स कोड पा सकते हैं ।
InputStream
बुनियादी ढाँचे की आवश्यकता होती हैp:fileDownload
, और मैंने इसे बदलने के तरीके को प्रबंधित नहीं कियाOutputStream
हैInputStream
। अब यह स्पष्ट है कि एक एक्शन श्रोता भी प्रतिक्रिया सामग्री प्रकार को बदल सकता है और फिर प्रतिक्रिया को वैसे भी उपयोगकर्ता-एजेंट की ओर से एक फ़ाइल डाउनलोड के रूप में सम्मान दिया जाएगा। धन्यवाद!