将 PDF 文件从 Java Bean 返回到 JSP

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/218909/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 11:28:47  来源:igfitidea点击:

Returning a PDF file from a Java Bean to a JSP

javajsppdfxsl-foapache-fop

提问by Philip Morton

EDIT:See my working codein the answers below.

编辑:在下面的答案中查看我的工作代码



In brief:I have a JSP file which calls a method in a Java Bean. This method creates a PDF file and in theory, returns it to the JSP so that the user can download it. However, upon loading the PDF, Adobe Reader gives the error: File does not begin with '%PDF-'.

简而言之:我有一个 JSP 文件,它调用 Java Bean 中的方法。此方法创建一个 PDF 文件,理论上将其返回给 JSP,以便用户下载。但是,在加载 PDF 时,Adobe Reader 会给出错误:文件不以 '%PDF-' 开头

In detail:So far, the JSP successfully calls the method, the PDF is created and then the JSP appears to give the user the finished PDF file. However, as soon as Adobe Reader tries to open the PDF file, it gives an error: File does not begin with '%PDF-'. Just for good measure, I have the method create the PDF on my Desktop so that I can check it; when I open it normally within Windows is appears fine. So why is the output from the JSP different?

详细说明:至此,JSP成功调用了该方法,创建了PDF,然后JSP出现给用户完成的PDF文件。但是,一旦 Adob​​e Reader 尝试打开 PDF 文件,就会出现错误:文件不以 '%PDF-' 开头。只是为了更好地衡量,我有在我的桌面上创建 PDF 的方法,以便我可以检查它;当我在 Windows 中正常打开它时显示正常。那么为什么 JSP 的输出不同呢?

To create the PDF, I'm using Apache FOP. I'm following one of their most basic examples, with the exception of passing the resulting PDF to a JSP instead of simply saving it to the local machine. I have been following their basic usage patternand this example code.

要创建 PDF,我使用的是Apache FOP。我正在关注他们最基本的示例之一,除了将生成的 PDF 传递给 JSP 而不是简单地将其保存到本地机器。我一直在遵循他们的基本使用模式这个示例代码

Here's my JSP file:

这是我的 JSP 文件:

<%@ taglib uri="utilTLD" prefix="util" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/xml" prefix="x" %>
<%@ page language="java" session="false" %>
<%@ page contentType="application/pdf" %>

<%-- Construct and initialise the PrintReportsBean --%>
<jsp:useBean id="printReportsBean" scope="request" class="some.package.printreports.PrintReportsBean" />
<jsp:setProperty name="printReportsBean" property="*"/>

<c:set scope="page" var="xml" value="${printReportsBean.download}"/>

Here's my Java Bean method:

这是我的 Java Bean 方法:

//earlier in the class...
private static FopFactory fopFactory = FopFactory.newInstance();

public File getDownload() throws UtilException {

    OutputStream out = null;
    File pdf = new File("C:\documents and settings\me\Desktop\HelloWorld.pdf");
    File fo  = new File("C:\somedirectory", "HelloWorld.fo");

    try {

        FOUserAgent foUserAgent = fopFactory.newFOUserAgent();

        out = new FileOutputStream(pdf);
        out = new BufferedOutputStream(out);

        Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);

        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer transformer = factory.newTransformer(); //identity transformer

        Source src = new StreamSource(fo);

        Result res = new SAXResult(fop.getDefaultHandler());

        transformer.transform(src, res);

        return pdf;

    } catch (Exception e) {

         throw new UtilException("Could not get download. Msg = "+e.getMessage());

    } finally {

         try {
             out.close();
         } catch (IOException io) {
             throw new UtilException("Could not close OutputStream. Msg = "+io.getMessage());
         }
    }
}

I realise that this is a very specific problem, but any help would be much appreciated!

我意识到这是一个非常具体的问题,但任何帮助将不胜感激!

回答by Knobloch

The way I have implemented this type of feature in the past is to make a servlet write the contents of the PDF file out to the response as a stream. I don't have the source code with me any longer (and it's been at least a year since I did any servlet/jsp work), but here is what you might want to try:

过去,我实现此类功能的方法是让 servlet 将 PDF 文件的内容作为流写入响应。我不再随身携带源代码(而且我已经至少一年没有做任何 servlet/jsp 工作了),但您可能想尝试以下方法:

In a servlet, get a handle on the response's output stream. Change the mime type of the response to "application/pdf", and have the servlet do the file handling you have in your example. Only, instead of returning the File object, have the servlet write the file to the output stream. See examples of file i/o and just replace any outfile.write(...) lines with responseStream.write(...) and you should be set to go. Once you flush and close the output stream, and do the return, if I remember correctly, the browser should be able to pick up the pdf from the response.

在 servlet 中,获取响应输出流的句柄。将响应的 mime 类型更改为“application/pdf”,并让 servlet 执行示例中的文件处理。只有让 servlet 将文件写入输出流,而不是返回 File 对象。查看文件 i/o 的示例,只需用 responseStream.write(...) 替换任何 outfile.write(...) 行,您就应该开始了。一旦您刷新并关闭输出流并返回,如果我没记错的话,浏览器应该能够从响应中获取 pdf。

回答by Philip Morton

Ok, I got this working. Here's how I did it:

好的,我得到了这个工作。这是我如何做到的:

JSP:

JSP:

<%@ taglib uri="utilTLD" prefix="util" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/xml" prefix="x" %>
<%@ page language="java" session="false" %>
<%@ page contentType="application/pdf" %>

<%-- Construct and initialise the PrintReportsBean --%>
<jsp:useBean id="printReportsBean" scope="request" class="some.package.PrintReportsBean" />
<jsp:setProperty name="printReportsBean" property="*"/>

<%
    // get report format as input parameter     
    ServletOutputStream servletOutputStream = response.getOutputStream();

    // reset buffer to remove any initial spaces
    response.resetBuffer(); 

    response.setHeader("Content-disposition", "attachment; filename=HelloWorld.pdf");

    // check that user is authorised to download product
    printReportsBean.getDownload(servletOutputStream);
%>

Java Bean method:

Java Bean方法:

//earlier in the class...
private static FopFactory fopFactory = FopFactory.newInstance();

public void getDownload(ServletOutputStream servletOutputStream) throws UtilException {

    OutputStream outputStream = null;

    File fo  = new File("C:\some\path", "HelloWorld.fo");

    try {

        FOUserAgent foUserAgent = fopFactory.newFOUserAgent();

        outputStream = new BufferedOutputStream(servletOutputStream);

        Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, outputStream);

        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer transformer = factory.newTransformer(); //identity transformer

        Source src = new StreamSource(fo);

        Result res = new SAXResult(fop.getDefaultHandler());

        transformer.transform(src, res);

    } catch (Exception e) {

        throw new UtilException("Could not get download. Msg = "+e.getMessage());

    } finally {

        try {
            outputStream.close();
        } catch (IOException io) {
            throw new UtilException("Could not close OutputStream. Msg = "+io.getMessage());
        }
     }
 }

Thanks to everyone for their input!

感谢大家的投入!

回答by matt b

Just a guess, but have you checked the MIME type that your JSP page is returning?

只是猜测,但您是否检查过您的 JSP 页面返回的 MIME 类型?

edit: if I actually read the code you posted I would see you did set it, so nevermind :)

编辑:如果我真的阅读了你发布的代码,我会看到你确实设置了它,所以没关系:)

edit2: Aren't the newlines between JSP tags in your JSP code going to end up in the output stream? Could that throw off the response returned by the server? I don't know anything about the format of a PDF, but does it depend on certain "marker" characters being in certain locations in the file? (The error message returned sounds like it does).

编辑 2:您的 JSP 代码中的 JSP 标记之间的换行符不是会出现在输出流中吗?这可以摆脱服务器返回的响应吗?我对 PDF 的格式一无所知,但它是否取决于文件中某些位置的某些“标记”字符?(返回的错误消息听起来确实如此)。

回答by Leonel Martins

I agree with matt b, maybe its the spaces between JSP tags. Try putting the directive

我同意matt b,也许它是 JSP 标签之间的空格。尝试放置指令

<%@ page trimDirectiveWhitespaces="true" %>