2

I have two methods. One that generates a PDF at the server side and another that downloads the PDF at the client side.

How can i do this without storing it in the Server side and allow the client side to directly download this.

The Following are the two methods:

public void downloadPDF(HttpServletRequest request, HttpServletResponse response) throws IOException{

    response.setContentType("application/pdf");
    response.setHeader("Content-disposition","attachment;filename="+ "testPDF.pdf");
    FileInputStream fis = null;
    DataOutputStream os = null;

    try {
        File f = new File("C://New folder//itext3.pdf");
        response.setHeader("Content-Length",String.valueOf(f.length()));

        fis = new FileInputStream(f);
        os = new DataOutputStream(response.getOutputStream());
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = fis.read(buffer)) >= 0) {
            os.write(buffer, 0, len);
        }

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        fis.close();
        os.flush();
        os.close();
    }
    response.setHeader("X-Frame-Options", "SAMEORIGIN");
}

And:

public Document generatePDF() {

    Document doc = new Document();
     try {
            File file = new File("C://New folder//itext_Test2.pdf");
            FileOutputStream pdfFileout = new FileOutputStream(file);
            PdfWriter.getInstance(doc, pdfFileout);

            doc.addAuthor("TestABC");
            doc.addTitle("Aircraft Details");
            doc.open();


            Anchor anchor = new Anchor("Aircraft Report");
            anchor.setName("Aircraft Report");

            Chapter catPart = new Chapter(new Paragraph(anchor), 1);

            Paragraph para1 = new Paragraph();
            Section subCatPart = catPart.addSection(para1);
            para1.add("This is paragraph 1");

            Paragraph para2 = new Paragraph();
            para2.add("This is paragraph 2");


            doc.add(catPart);

            doc.close();


        } catch (Exception e) {
            e.printStackTrace();
        }
     return doc;
}
Bruno Lowagie
  • 75,994
  • 9
  • 109
  • 165
Mishal Harish
  • 93
  • 1
  • 4
  • 14

4 Answers4

11

The people who advise you to use response.getOutputStream() instead of creating a FileOutputStream are right. See for instance the Hello Servlet from Chapter 9 of my book:

public class Hello extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        response.setContentType("application/pdf");
        try {
            // step 1
            Document document = new Document();
            // step 2
            PdfWriter.getInstance(document, response.getOutputStream());
            // step 3
            document.open();
            // step 4
            document.add(new Paragraph("Hello World"));
            document.add(new Paragraph(new Date().toString()));
            // step 5
            document.close();
        } catch (DocumentException de) {
            throw new IOException(de.getMessage());
        }
    }
}

However, some browsers experience problems when you send bytes directly like this. It's safer to create the file in memory using a ByteArrayOutputStream and to tell the browser how many bytes it can expect in the content header:

public class PdfServlet extends HttpServlet {

    protected void service(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        try {
            // Get the text that will be added to the PDF
            String text = request.getParameter("text");
            if (text == null || text.trim().length() == 0) {
                 text = "You didn't enter any text.";
            }
            // step 1
            Document document = new Document();
            // step 2
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            PdfWriter.getInstance(document, baos);
            // step 3
            document.open();
            // step 4
            document.add(new Paragraph(String.format(
                "You have submitted the following text using the %s method:",
                request.getMethod())));
            document.add(new Paragraph(text));
            // step 5
            document.close();

            // setting some response headers
            response.setHeader("Expires", "0");
            response.setHeader("Cache-Control",
                "must-revalidate, post-check=0, pre-check=0");
            response.setHeader("Pragma", "public");
            // setting the content type
            response.setContentType("application/pdf");
            // the contentlength
            response.setContentLength(baos.size());
            // write ByteArrayOutputStream to the ServletOutputStream
            OutputStream os = response.getOutputStream();
            baos.writeTo(os);
            os.flush();
            os.close();
        }
        catch(DocumentException e) {
            throw new IOException(e.getMessage());
        }
    }
}

For the full source code, see PdfServlet. You can try the code here: http://demo.itextsupport.com/book/

Bruno Lowagie
  • 75,994
  • 9
  • 109
  • 165
  • If we are writing contents in a program, we can use PdfWriter.getInstance(doc, pdfFileout); But, I have one document object which is having the document generated(returned from an external Jar's method). With that object, Can I use the getInstance statement to generate the document on the fly. Is there any other way to do that? – Kalyan May 10 '16 at 12:28
  • You have one document object (of type `Document`?) which you use to generate content. How is that different than "writing contents in the program"? Also, you are high-jacking an old question: you shouldn't post a question as a comment. You should post a question as a question. Chances are that you are looking for the [PdfReader](http://developers.itextpdf.com/tags/pdfreader)/[PdfStamper](http://developers.itextpdf.com/tags/pdfstamper) object. In that case, why don't you read the [official documentation](http://developers.itextpdf.com/faq/category/manipulating-existing-pdfs)? – Bruno Lowagie May 10 '16 at 12:45
1

You are creating a FileOutputStream to generate pdf. But what you can do is to use the stream that is present in HttpServletResponse on server side method and write the file directly to it.

mark_o
  • 2,052
  • 1
  • 12
  • 18
1

You can receive an OutputStream in your generatePDF method. If you pass the response.getOutputStream() to the generate method then the PDF will be written to the response directly.

m4ktub
  • 3,061
  • 1
  • 13
  • 17
0

Just call this method appropriately from downloadPDF(); e.g.:

generatePDF(response.getOutputStream());

that calls this method:

public void generatePDF(OutputStream pdfOutputStream) {

    Document doc = new Document();
     try {
            PdfWriter.getInstance(doc, pdfOutputStream);

            doc.addAuthor("TestABC");
            doc.addTitle("Aircraft Details");
            doc.open();


            Anchor anchor = new Anchor("Aircraft Report");
            anchor.setName("Aircraft Report");

            Chapter catPart = new Chapter(new Paragraph(anchor), 1);

            Paragraph para1 = new Paragraph();
            Section subCatPart = catPart.addSection(para1);
            para1.add("This is paragraph 1");

            Paragraph para2 = new Paragraph();
            para2.add("This is paragraph 2");


            doc.add(catPart);

            doc.close();


        } catch (Exception e) {
            e.printStackTrace();
        }
}
Brett Walker
  • 3,566
  • 1
  • 18
  • 36
  • This is wrong: the question is *How do I avoid having to use a FileOutputStream?* In your code, you're still working with a file instead of creating the PDF in memory (e.g. using a `ByteArrayOutputStream`). Please remove this answer. – Bruno Lowagie May 26 '15 at 12:27
  • The question was about not storing as a file. But I have updated the code to not use FileOutputStream. @Mishal – Brett Walker May 26 '15 at 12:42
  • That's already better, but some browsers download content in chunks of 1024 bytes if you don't tell them in advance how many bytes they can expect. If the size of a PDF isn't an exact multiple of 1024 bytes, the PDF gets a lot of gibberish bytes at the end and some PDF Viewers choke on those bytes (because viewers start reading a PDF at the end of the file). Hence your suggestion to use `response.getOutputStream()` won't work for all browsers/viewers... – Bruno Lowagie May 26 '15 at 12:47
  • Thanks, noted for future reference. Any modern/popular browsers that display issue? – Brett Walker May 26 '15 at 12:48