[ Team LiB ] |
![]() ![]() |
Recipe 13.1 Sending a PDF FileProblemYou want to send binary data representing a PDF file to a user. SolutionUse a servlet and a java.io.BufferedInputStream to read the bytes from the file. Send the file content to the user with a javax.servlet.ServletOutputStream retrieved from the javax.servlet.http.HttpServletResponse object. DiscussionPDF files are ubiquitous on the Web, as most users are equipped with the Adobe Reader application that reads them. Example 13-1 takes a filename from a query string that is part of the request to the servlet, and responds with binary data that represents the PDF file. The servlet identifies the file that it sends to the client as the MIME type application/pdf by using the Content-Type response header.
Table 13-1 shows several MIME types that web developers may encounter.
The request to the servlet looks like this: http://localhost:8080/home/sendpdf?file=chapter5 Example 13-1 checks to see if the request parameter file is valid and then adds the file extension .pdf to the filename if it does not already have that suffix. This is the filename the HTTP response recommends to the browser (it will appear as the default filename in any displayed "Save As" windows).
Example 13-1. Sending a PDF file as binary datapackage com.jspservletcookbook; import java.io.FileInputStream; import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import javax.servlet.*; import javax.servlet.http.*; public class SendPdf extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //get the filename from the "file" parameter String fileName = (String) request.getParameter("file"); if (fileName == null || fileName.equals("")) throw new ServletException( "Invalid or non-existent file parameter in SendPdf servlet."); // add the .pdf suffix if it doesn't already exist if (fileName.indexOf(".pdf") == -1) fileName = fileName + ".pdf"; //where are PDFs kept? String pdfDir = getServletContext( ).getInitParameter("pdf-dir"); if (pdfDir == null || pdfDir.equals("")) throw new ServletException( "Invalid or non-existent 'pdfDir' context-param."); ServletOutputStream stream = null; BufferedInputStream buf = null; try{ stream = response.getOutputStream( ); File pdf = new File(pdfDir + "/" + fileName); //set response headers response.setContentType("application/pdf"); response.addHeader( "Content-Disposition","attachment; filename="+fileName ); response.setContentLength( (int) pdf.length( ) ); FileInputStream input = new FileInputStream(pdf); buf = new BufferedInputStream(input); int readBytes = 0; //read from the file; write to the ServletOutputStream while((readBytes = buf.read( )) != -1) stream.write(readBytes); } catch (IOException ioe){ throw new ServletException(ioe.getMessage( )); } finally { //close the input/output streams if (stream != null) stream.close( ); if (buf != null) buf.close( ); } } //end doGet public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); } } Example 13-1 gets the directory where the PDF files are stored from a context-param element in the deployment descriptor: <context-param> <param-name>pdf-dir</param-name> <param-value>h:/book/distribute</param-value> </context-param>
The code then gets the ServletOutputStream from the HttpServletResponse object. The binary data representing the PDF is written to this stream: stream = response.getOutputStream( ); The servlet does not use a java.io.PrintWriter as in response.getWriter( ), because a PrintWriter is designed for returning character data, such as HTML, that the browser displays on the computer screen. Example 13-1 adds the response headers that help prevent the browsers from trying to display the bytes as content in the browser window: response.setContentType("application/pdf"); response.addHeader( "Content-Disposition","attachment; filename="+fileName ); response.setContentLength( (int) pdf.length( ) ); The Content-Disposition header field signals the client to treat the received content as an attachment, not as characters to be displayed in the browser. This optional response header also provides a recommended filename, which the browser may include as the default filename in any "Save As" windows.
The client browser can use the Content-Length header value (provided with response.setContentLength( )) to indicate to the user the download progress with a widget that shows a horizontal bar steadily filling with color. The servlet also uses a java.io.BufferedInputStream to buffer the input from the file in a byte[] array, which speeds up the transfer of data from the server to the client.
The code closes the ServletOutputStream and the BufferedInputStream in a finally block to release any system resources used by these objects. The code within the finally block executes regardless of whether the code throws an exception.
See AlsoRecipe 13.2-Recipe 13.4 on sending Word, XML, and MP3 files as binary data; Recipe 13.5 on getting an input stream representing a web resource such as web.xml; RFC technical documents on MIME: ftp://ftp.rfc-editor.org/in-notes/rfc2045.txt and ftp://ftp.rfc-editor.org/in-notes/rfc2046.txt.; RFC 2183 at ftp://ftp.rfc-editor.org/in-notes/rfc2183.txt for background information on the Content-Disposition header; the Media Types section of the HTTP Pocket Reference by Clinton Long (O'Reilly). ![]() |
[ Team LiB ] |
![]() ![]() |