【问题标题】:How can I serve a PDF to a browser without storing a file on the server side?如何在不将文件存储在服务器端的情况下将 PDF 提供给浏览器?
【发布时间】:2015-08-08 00:43:23
【问题描述】:

我有两种方法。一个在服务器端生成 PDF,另一个在客户端下载 PDF。

如何在不将其存储在服务器端并允许客户端直接下载的情况下做到这一点。

以下是两种方法:

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");
}

还有:

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;
}

【问题讨论】:

  • 是在客户端下载PDF代码作品

标签: java pdf model-view-controller pdf-generation itext


【解决方案1】:

您正在创建一个 FileOutputStream 来生成 pdf。但是您可以做的是在服务器端方法上使用 HttpServletResponse 中存在的流并将文件直接写入它。

【讨论】:

    【解决方案2】:

    您可以在generatePDF 方法中收到OutputStream。如果您将response.getOutputStream() 传递给 generate 方法,则 PDF 将直接写入响应。

    【讨论】:

      【解决方案3】:

      只需从downloadPDF() 适当调用此方法即可;例如:

      generatePDF(response.getOutputStream());
      

      调用这个方法的:

      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();
              }
      }
      

      【讨论】:

      • 这是错误的:问题是 如何避免使用 FileOutputStream? 在您的代码中,您仍在使用文件而不是在内存(例如使用ByteArrayOutputStream)。请删除此答案。
      • 问题是关于不存储为文件。但我已将代码更新为不使用 FileOutputStream。 @米沙尔
      • 这已经更好了,但是如果你不提前告诉他们可以期待多少字节,一些浏览器会以 1024 字节的块下载内容。如果 PDF 的大小不是 1024 字节的精确倍数,则 PDF 会在结尾处获得大量乱码字节,并且某些 PDF 查看器会阻塞这些字节(因为查看器会在文件末尾开始阅读 PDF)。因此,您使用 response.getOutputStream() 的建议不适用于所有浏览器/查看器...
      • 谢谢,留作日后参考。任何显示问题的现代/流​​行浏览器?
      【解决方案4】:

      建议您使用response.getOutputStream() 而不是创建FileOutputStream 的人是对的。例如,参见我的书第 9 章中的 Hello Servlet:

      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());
              }
          }
      }
      

      但是,当您像这样直接发送字节时,某些浏览器会遇到问题。使用ByteArrayOutputStream 在内存中创建文件并告诉浏览器它可以在内容头中预期多少字节会更安全:

      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());
              }
          }
      }
      

      完整源代码见PdfServlet。你可以在这里试试代码:http://demo.itextsupport.com/book/

      【讨论】:

      • 如果我们在程序中写入内容,我们可以使用 PdfWriter.getInstance(doc, pdfFileout);但是,我有一个文档对象正在生成文档(从外部 Jar 的方法返回)。使用该对象,我可以使用 getInstance 语句动态生成文档吗?有没有其他方法可以做到这一点?
      • 您有一个用于生成内容的文档对象(Document? 类型)。这与“在程序中编写内容”有何不同?此外,您正在劫持一个老问题:您不应该将问题发布为评论。您应该将问题作为问题发布。您可能正在寻找 PdfReader/PdfStamper 对象。在那种情况下,你为什么不阅读official documentation
      猜你喜欢
      • 2012-12-08
      • 1970-01-01
      • 2020-05-15
      • 2011-07-12
      • 2011-12-18
      • 1970-01-01
      • 2013-08-25
      • 2015-07-29
      相关资源
      最近更新 更多