2

I have written a jsp page to display contents of pdf, but end up with ascii codes in jsp. I want to display the contents of pdf in jsp. Whats the part that I have missed. When I try to write the read content in pdf it shows only ascii values and not in readable format

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=${encoding}"></head>

<%@page import="java.io.File"%>
<%@page import="java.io.*"%>
<%@page import="javax.servlet.*"%>
<%@page import="com.itextpdf.text.Image"%>
<%@page import="com.itextpdf.text.Document"%>
<%@page import="com.itextpdf.text.DocumentException"%>
<%@page import="com.itextpdf.text.pdf.PdfReader"%>
<%@page import="com.itextpdf.text.pdf.PdfImportedPage"%>
<%@page import="com.itextpdf.text.pdf.PdfWriter"%>
<%@page import="com.itextpdf.text.pdf.PdfContentByte"%>
<%@ page language="java" contentType="application/pdf; charset=UTF-8"
    pageEncoding="UTF-8"%>

<%
    response.reset();
    response.setContentType("application/pdf");
    File file = new File("D:\\TNWRD_Documents\\CHAPTER_II.pdf");
    response.setHeader("Content-Type", "application/pdf");
    response.setHeader("Content-Disposition",
            "inline;filename=Saba_PhBill.pdf");
    response.setContentLength((int) file.length());
    response.setHeader("Content-Type",
            getServletContext().getMimeType(file.getName()));
    response.setHeader("Content-Length", String.valueOf(file.length()));
    //OPen an input stream to the file and post the file contents thru the
    //servlet output stream to the browser
    FileInputStream in = new FileInputStream(file);
    ServletOutputStream outs = response.getOutputStream();
    response.setContentLength(in.available());
    byte[] buf = new byte[8192];
    int c = 0;
    try {
        while ((c = in.read(buf, 0, buf.length)) > 0) {
            //System.out.println("size:"+c);
            outs.write(buf, 0, c);
            out.write(outs.toString());
        }

    } catch (IOException ioe) {
        ioe.printStackTrace(System.out);
    } finally {
        outs.flush();
        outs.close();
        in.close();
    }
%>
</html>
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
user1989615
  • 39
  • 1
  • 1
  • 3
  • Before your JSP directives, you have a complete HTTP header. When your JSP code executes `response.reset(),` this header may well have already been sent. Furthermore you send a closing ` – mkl Apr 26 '13 at 09:40
  • My comment is of a more general nature: JSP technology was introduced to eliminate the necessity of polluting Java code with HTML. You wrote a servlet in JSP, and somehow managed to pollute it with HTML. – Marcin Płonka Apr 26 '13 at 12:27
  • 1
    It's interesting that you tagged this question with `[servlets]`, even though you are nowhere using a servlet in your code at all, but it **is** the right answer to your concrete problem! Basically, you already knew the answer beforehand, you just didn't see it. – BalusC Apr 26 '13 at 18:48

3 Answers3

8

JSP is the wrong tool for the job of serving a file download. JSP is designed as a view technology with the intent to easily produce HTML output with taglibs and EL. Basically, with your JSP approach, your PDF file is cluttered with <!DOCTYPE>, <html> etc tags and therefore corrupted and not recognizable as a valid PDF file. This is by the way one of the reasons why using scriptlets is a bad practice. It has namely completely confused you as to how stuff is supposed to work. In this particular case, that is using a normal Java class for the file download job.

You should be using a servlet instead. Here's a kickoff example, assuming that Servlet 3.0 and Java 7 is available:

@WebServlet("/foo.pdf")
public class PdfServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        File file = new File("/absolute/path/to/foo.pdf");
        response.setHeader("Content-Type", getServletContext().getMimeType(file.getName()));
        response.setHeader("Content-Length", String.valueOf(file.length()));
        response.setHeader("Content-Disposition", "inline; filename=\"foo.pdf\"");
        Files.copy(file.toPath(), response.getOutputStream());
    }

}

(if Servlet 3.0 is not available, then map it in web.xml the usual way, if Java 7 is not available, then use a read/write loop the usual way)

Just copypaste this class in its entirety into your project and open the desired PDF file by /contextpath/Saba_PhBill.pdf instead of /contextpath/youroriginal.jsp (after having organized it in a package and autocompleted the necessary imports in the class, of course).

E.g. as follows in a JSP where you'd like to show the PDF inline:

<object data="${pageContext.request.contextPath}/Saba_PhBill.pdf" type="application/pdf" width="500" height="300">
    <a href="${pageContext.request.contextPath}/Saba_PhBill.pdf">Download file.pdf</a>
</object>

(the <a> link is meant as graceful degradation when the browser being used doesn't support inlining application/pdf content in a HTML document, i.e. when it doesn't have Adobe Reader plugin installed)

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Can you please look at my question? http://stackoverflow.com/questions/16232916/displaying-pdf-in-jsp I hope you will answer for this. A kind help! Please look at this question. –  Jul 01 '14 at 15:27
2

Supposing we completely ignore the advice against using a JSP (and as BalusC says - there are BETTER WAYS), here's an ugly and shameful little bodge that worked okay for me. It doesn't even set all the right headers, but here goes:

<%@ page import="java.io.File" %><%@ page import="org.apache.commons.io.FileUtils" %><%
File pdfFile = (File) request.getAttribute("pdf");
byte[] pdfByteArray = FileUtils.readFileToByteArray(pdfFile);
response.setContentType("application/pdf");
response.getOutputStream().write(pdfByteArray);
response.getOutputStream().flush();
%>

It's important ensure there are no new-lines (or other whitespace) outside the scriptlet tags.

They made me do it, okay?!

Ollie Bennett
  • 4,424
  • 1
  • 19
  • 26
  • 1
    Sad but true, sometimes you have to do things the ugly way :) Yu can also remove fileUtils creation, unless you are using other methods than the "FileUtils.readFileToByteArray". Anyway, thank you for this brute force scriplet :) – lbrutti Jan 09 '14 at 08:47
  • Great, thanks @lbrutti - I've removed the redundant code. Glad it helped! – Ollie Bennett Jan 09 '14 at 14:30
1

I could see multiple problems:

  • There are extra html tags at the top and bottom of your JSP. You do not want them there - you only want to have the pdf contents in your response output.
  • The code sets content type is multiple times. That is probably not the root cause, however make sure you do it only once (set it to application/pdf)
  • In the while loop, data are first written to the response output stream, then a toString() is written to the out (which is actually a Writer instance opened on the response output stream - the one in outs). Only use the response stream in the loop, as

    while ((c = in.read(buf, 0, buf.length)) > 0) { outs.write(buf, 0, c);
    }

david a.
  • 5,283
  • 22
  • 24