Giriş
Her şeyi halledebilirsiniz ExternalContext
. JSF 1.x'te ham HttpServletResponse
nesneyi ExternalContext#getResponse()
. JSF 2.x'de, JSF davlumbazlarının altından ExternalContext#getResponseOutputStream()
kapmaya gerek kalmadan bir dizi yeni delege yöntemini kullanabilirsiniz HttpServletResponse
.
Yanıtta, Content-Type
istemcinin sağlanan dosyayla hangi uygulamayı ilişkilendireceğini bilmesi için üstbilgiyi ayarlamalısınız . Content-Length
Üstbilgiyi istemcinin indirme ilerlemesini hesaplayabileceği şekilde ayarlamalısınız , aksi takdirde bilinmeyecektir. Ve, Farklı Kaydet iletişim kutusu istiyorsanız Content-Disposition
başlığı olarak ayarlamalısınız , aksi takdirde istemci bunu satır içi olarak görüntülemeye çalışacaktır. Son olarak, dosya içeriğini yanıt çıktı akışına yazın.attachment
En önemli kısım, FacesContext#responseComplete()
dosyayı yanıta yazdıktan sonra gezinme ve işleme gerçekleştirmemesi gerektiğini JSF'ye bildirmektir, aksi takdirde yanıtın sonu sayfanın HTML içeriğiyle veya eski JSF sürümlerinde kirlenir. , bir alacak IllegalStateException
gibi bir mesaj ile getoutputstream() has already been called for this response
JSF uygulama çağrıları yaparken getWriter()
HTML işlemek için.
Ajax'ı kapatın / uzaktan kumanda kullanmayın!
Yalnızca eylem yöntemi olduğundan emin olmak gerekir değil bir ajax isteği tarafından çağrılan, ancak birlikte ateş gibi normal bir istek tarafından çağrılmasını <h:commandLink>
ve <h:commandButton>
. Ajax istekleri ve uzak komutlar JavaScript tarafından işlenir ve bu da güvenlik nedenleriyle ajax yanıtının içeriğiyle Farklı Kaydet diyaloğunu zorlayacak hiçbir tesise sahip değildir.
Örneğin PrimeFaces kullanıyorsanız <p:commandXxx>
, ajax="false"
öznitelik aracılığıyla ajax'ı açıkça kapattığınızdan emin olmanız gerekir . ICEfaces kullanıyorsanız <f:ajax disabled="true" />
, komut bileşenine bir yerleştirmeniz gerekir .
Genel JSF 2.x örneği
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();
}
Genel JSF 1.x örneği
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();
}
Yaygın statik dosya örneği
Yerel disk dosya sisteminden statik bir dosya yayınlamanız gerekirse, kodu aşağıdaki gibi değiştirin:
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);
Ortak dinamik dosya örneği
PDF veya XLS gibi dinamik olarak oluşturulmuş bir dosyayı yayınlamanız output
gerekirse, kullanılan API'nin bir OutputStream
.
Örneğin iText PDF:
String fileName = "dynamic.pdf";
String contentType = "application/pdf";
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, output);
document.open();
document.close();
Örneğin Apache POI HSSF:
String fileName = "dynamic.xls";
String contentType = "application/vnd.ms-excel";
HSSFWorkbook workbook = new HSSFWorkbook();
workbook.write(output);
workbook.close();
Burada içerik uzunluğunu ayarlayamayacağınızı unutmayın. Bu nedenle, yanıt içeriği uzunluğunu ayarlamak için satırı kaldırmanız gerekir. Bu teknik olarak sorun değil, tek dezavantajı, son kullanıcıya bilinmeyen bir indirme ilerlemesi sunulacak olmasıdır. Bunun önemli olması durumunda, gerçekten önce yerel (geçici) bir dosyaya yazmanız ve ardından önceki bölümde gösterildiği gibi sağlamanız gerekir.
Fayda yöntemi
JSF yardımcı program kitaplığı OmniFaces kullanıyorsanız , Faces#sendFile()
a File
, veya bir InputStream
veya a alarak byte[]
ve dosyanın ek ( true
) veya satır içi ( false
) olarak indirilip indirilmeyeceğini belirleyen üç uygun yöntemden birini kullanabilirsiniz .
public void download() throws IOException {
Faces.sendFile(file, true);
}
Evet, bu kod olduğu gibi tamamlandı. responseComplete()
Kendinizi çağırmanıza gerek yok . Bu yöntem aynı zamanda IE'ye özgü üstbilgiler ve UTF-8 dosya adlarıyla da düzgün bir şekilde ilgilenir. Kaynak kodunu burada bulabilirsiniz .
InputStream
altyapısınıp:fileDownload
ve ben dönüştürmek nasıl yönetilen değilOutputStream
etmekInputStream
. Artık bir eylem dinleyicisinin bile yanıt içerik türünü değiştirebileceği ve ardından yanıt, kullanıcı aracısı tarafında bir dosya indirmesi olarak kabul edileceği açıktır. Teşekkür ederim!