Read and open the PDF in a new browser window
The goal is to use JSF to open a PDF file inline in a new browser window without showing the full PDF path and filename for some (security) reasons. You can use either a h:commandLink or a h:commandButton for this:
<h:form> <h:commandLink value="Download PDF" action="#{myBean.downloadPDF}" target="_blank" /> </h:form>
<h:form target="_blank"> <h:commandButton value="Download PDF" action="#{myBean.downloadPDF}" /> </h:form>
Note: when using an ajax-capable command button/link from a library such as PrimeFaces, then don't forget to turn off the ajax capability by e.g. adding ajax="false"
in case of PrimeFaces command components. It's namely not possible to download files using ajax, for the simple reason that JavaScript is due to security restrictions not capable of forcing a Save As dialogue from the client side on.
The downloadPDF() method of the backing bean MyBean.java sends the PDF to the HttpServletResponse as follows:
package mypackage; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.servlet.http.HttpServletResponse; public class MyBean { // Constants ---------------------------------------------------------------------------------- private static final int DEFAULT_BUFFER_SIZE = 10240; // 10KB. // Actions ------------------------------------------------------------------------------------ public void downloadPDF() throws IOException { // Prepare. FacesContext facesContext = FacesContext.getCurrentInstance(); ExternalContext externalContext = facesContext.getExternalContext(); HttpServletResponse response = (HttpServletResponse) externalContext.getResponse(); File file = new File(getFilePath(), getFileName()); BufferedInputStream input = null; BufferedOutputStream output = null; try { // Open file. input = new BufferedInputStream(new FileInputStream(file), DEFAULT_BUFFER_SIZE); // Init servlet response. response.reset(); response.setHeader("Content-Type", "application/pdf"); response.setHeader("Content-Length", String.valueOf(file.length())); response.setHeader("Content-Disposition", "inline; filename=\"" + getFileName() + "\""); output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE); // Write file contents to response. byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; int length; while ((length = input.read(buffer)) > 0) { output.write(buffer, 0, length); } // Finalize task. output.flush(); } finally { // Gently close streams. close(output); close(input); } // Inform JSF that it doesn't need to handle response. // This is very important, otherwise you will get the following exception in the logs: // java.lang.IllegalStateException: Cannot forward after response has been committed. facesContext.responseComplete(); } // Helpers (can be refactored to public utility class) ---------------------------------------- private static void close(Closeable resource) { if (resource != null) { try { resource.close(); } catch (IOException e) { // Do your thing with the exception. Print it, log it or mail it. It may be useful to // know that this will generally only be thrown when the client aborted the download. e.printStackTrace(); } } } }
The names of the getFilePath() and getFileName() are self-explaining, so there is no need to describe those methods.
If you don't care about showing request parameters or filenames in the URL, then you can also consider to use a FileServlet.
Copyright - There is no copyright on the code. You can copy, change and distribute it freely. Just mentioning this site should be fair.
(C) May 2006, BalusC