I use JSF and I have an h:commandButton
to prompt for a file download. The file is in a PDF format. The downloaded file has correct number of pages but they are blank.
When the file is opened in the browser I get this message:
This PDF document might not be displayed correctly.
This is my commandButton:
<h:form>
<h:commandButton action="#{fileDownloadView.fileDownloadView}" value="Download"/>
</h:form>
And this is my class:
@ManagedBean
public class FileDownloadView {
private static final String FILENAME = "manual.pdf";
private static final String CONTENT_TYPE = "application/pdf";
public FileDownloadView() throws IOException, DocumentException {
Resource resource = new ClassPathResource(FILENAME);
InputStream stream = resource.getInputStream();
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
externalContext.responseReset();
externalContext.setResponseContentType(CONTENT_TYPE);
externalContext.setResponseHeader("Content-Disposition", "attachment; filename=\"" + FILENAME + "\"");
OutputStream outputStream = externalContext.getResponseOutputStream();
byte[] bytes = IOUtils.toByteArray(stream);
outputStream.write(bytes);
facesContext.responseComplete();
}
}
What could be the cause of this?
EDIT:
Claimed duplicate post gives this pice of code:
public void download() throws IOException {
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
ec.responseReset(); // 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.
ec.setResponseContentType(contentType); // Check http://www.iana.org/assignments/media-types for all types. Use if necessary ExternalContext#getMimeType() for auto-detection based on filename.
ec.setResponseContentLength(contentLength); // Set it with the file size. This header is optional. It will work if it's omitted, but the download progress will be unknown.
ec.setResponseHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); // The Save As popup magic is done here. You can give it any file name you want, this only won't work in MSIE, it will use current request URL as file name instead.
OutputStream output = ec.getResponseOutputStream();
// Now you can write the InputStream of the file to the above OutputStream the usual way.
// ...
fc.responseComplete(); // Important! Otherwise JSF will attempt to render the response which obviously will fail since it's already written with a file and closed.
}
If you look closer my code is the same with the exception of the comment part that writes:
// Now you can write the InputStream of the file to the above OutputStream the usual way. // ...
What i have writen for this is
byte[] bytes = IOUtils.toByteArray(stream);
outputStream.write(bytes);
What is wrong with that? Isn't that a byte array that is written in the output stream? Why is this not working?