jsf 2 - How to provide a file download from a JSF backing bean? -
is there way of providing file download jsf backing bean action method? have tried lot of things. main problem cannot figure how outputstream
of response in order write file content to. know how servlet
, cannot invoked jsf form , requires new request.
how can outputstream
of response current facescontext
?
introduction
you can through externalcontext
. in jsf 1.x, can raw httpservletresponse
object externalcontext#getresponse()
. in jsf 2.x, can use bunch of new delegate methods externalcontext#getresponseoutputstream()
without need grab httpservletresponse
under jsf hoods.
on response, should set content-type
header client knows application associate provided file. and, should set content-length
header client can calculate download progress, otherwise unknown. and, should set content-disposition
header attachment
if want save as dialog, otherwise client attempt display inline. write file content response output stream.
most important part call facescontext#responsecomplete()
inform jsf should not perform navigation , rendering after you've written file response, otherwise end of response polluted html content of page, or in older jsf versions, illegalstateexception
message getoutputstream() has been called response
when jsf implementation calls getwriter()
render html.
generic jsf 2.x example
public void download() throws ioexception { facescontext fc = facescontext.getcurrentinstance(); externalcontext ec = fc.getexternalcontext(); ec.responsereset(); // jsf component library or filter might have set headers in buffer beforehand. want rid of them, else may collide. ec.setresponsecontenttype(contenttype); // check http://www.iana.org/assignments/media-types types. use if necessary externalcontext#getmimetype() auto-detection based on filename. ec.setresponsecontentlength(contentlength); // set file size. header optional. work if it's omitted, download progress unknown. ec.setresponseheader("content-disposition", "attachment; filename=\"" + filename + "\""); // save popup magic done here. can give file name want, won't work in msie, use current request url file name instead. outputstream output = ec.getresponseoutputstream(); // can write inputstream of file above outputstream usual way. // ... fc.responsecomplete(); // important! otherwise jsf attempt render response fail since it's written file , closed. }
generic jsf 1.x example
public void download() throws ioexception { facescontext fc = facescontext.getcurrentinstance(); httpservletresponse response = (httpservletresponse) fc.getexternalcontext().getresponse(); response.reset(); // jsf component library or filter might have set headers in buffer beforehand. want rid of them, else may collide. response.setcontenttype(contenttype); // check http://www.iana.org/assignments/media-types types. use if necessary servletcontext#getmimetype() auto-detection based on filename. response.setcontentlength(contentlength); // set file size. header optional. work if it's omitted, download progress unknown. response.setheader("content-disposition", "attachment; filename=\"" + filename + "\""); // save popup magic done here. can give file name want, won't work in msie, use current request url file name instead. outputstream output = response.getoutputstream(); // can write inputstream of file above outputstream usual way. // ... fc.responsecomplete(); // important! otherwise jsf attempt render response fail since it's written file , closed. }
common static file example
in case need stream static file local disk file system, substitute code below:
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);
common dynamic file example
in case need stream dynamically generated file, such pdf or xls, provide output
there api being used expects outputstream
.
e.g. itext pdf:
string filename = "dynamic.pdf"; string contenttype = "application/pdf"; // ... document document = new document(); pdfwriter writer = pdfwriter.getinstance(document, output); document.open(); // build pdf content here. document.close();
e.g. apache poi hssf:
string filename = "dynamic.xls"; string contenttype = "application/vnd.ms-excel"; // ... hssfworkbook workbook = new hssfworkbook(); // build xls content here. workbook.write(output); workbook.close();
note cannot set content length here. need remove line set response content length. technically no problem, disadvantage enduser presented unknown download progress. in case important, need write local (temporary) file first , provide shown in previous chapter.
turn off ajax!
you need make sure action method not called ajax request, called normal request fire <h:commandlink>
, <h:commandbutton>
. ajax requests handled javascript in turn has, due security reasons, no facilities force save as dialogue content of ajax response.
in case you're using e.g. primefaces <p:commandxxx>
, need make sure explicitly turn off ajax via ajax="false"
attribute. in case you're using icefaces, need nest <f:ajax disabled="true" />
in command component.
utility method
if you're using jsf utility library omnifaces, can use 1 of 3 convenient faces#sendfile()
methods taking either file
, or inputstream
, or byte[]
, , specifying whether file should downloaded attachment (true
) or inline (false
).
public void download() throws ioexception { faces.sendfile(file, true); }
yes, code complete as-is. don't need invoke responsecomplete()
, on yourself. method deals ie-specific headers , utf-8 filenames. can find source code here.
Comments
Post a Comment