【问题标题】:Download PDF in JSF returns blank pages在 JSF 中下载 PDF 返回空白页
【发布时间】:2019-06-21 06:58:38
【问题描述】:

我使用 JSF,我有一个 h:commandButton 来提示下载文件。该文件为 PDF 格式。下载的文件有正确的页数,但它们是空白的。

当文件在浏览器中打开时,我收到以下消息:

此 PDF 文档可能无法正确显示。

这是我的命令按钮:

    <h:form>
        <h:commandButton action="#{fileDownloadView.fileDownloadView}" value="Download"/>
    </h:form>

这是我的课:

@ManagedBean
public class FileDownloadView {

    private static final String FILENAME = "manual.pdf";
    private static final String CONTENT_TYPE = "application/pdf";

    public FileDownloadView() throws IOException, DocumentException {
        Resource resource = new ClassPathResource(FILENAME);
        InputStream stream = resource.getInputStream();
        FacesContext facesContext = FacesContext.getCurrentInstance();
        ExternalContext externalContext = facesContext.getExternalContext();
        externalContext.responseReset();
        externalContext.setResponseContentType(CONTENT_TYPE);
        externalContext.setResponseHeader("Content-Disposition", "attachment; filename=\"" + FILENAME + "\"");
        OutputStream outputStream = externalContext.getResponseOutputStream();
        byte[] bytes = IOUtils.toByteArray(stream);
        outputStream.write(bytes);
        facesContext.responseComplete();
    }

}

这可能是什么原因?

编辑:

声称重复的帖子给出了这段代码:

public void download() throws IOException {
    FacesContext fc = FacesContext.getCurrentInstance();
    ExternalContext ec = fc.getExternalContext();

    ec.responseReset(); // Some JSF component library or some Filter might have set some headers in the buffer beforehand. We want to get rid of them, else it may collide.
    ec.setResponseContentType(contentType); // Check http://www.iana.org/assignments/media-types for all types. Use if necessary ExternalContext#getMimeType() for auto-detection based on filename.
    ec.setResponseContentLength(contentLength); // Set it with the file size. This header is optional. It will work if it's omitted, but the download progress will be unknown.
    ec.setResponseHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); // The Save As popup magic is done here. You can give it any file name you want, this only won't work in MSIE, it will use current request URL as file name instead.

    OutputStream output = ec.getResponseOutputStream();
    // Now you can write the InputStream of the file to the above OutputStream the usual way.
    // ...

    fc.responseComplete(); // Important! Otherwise JSF will attempt to render the response which obviously will fail since it's already written with a file and closed.
}

如果您仔细观察,我的代码除了注释部分之外是相同的:

// 现在可以将文件的InputStream写入上面 OutputStream 以通常的方式。 // ...

我为此写的是

byte[] bytes = IOUtils.toByteArray(stream);
outputStream.write(bytes);

这有什么问题?那不是写在输出流中的字节数组吗?为什么这不起作用?

【问题讨论】:

  • 所以如果你使用h:commandButton 页面不是空的吗?或者如果你返回一个文本文件它不为空?
  • 页面都是空的(p:commandButton 或 h:commandButton)
  • 所以我上面所做的代码更改也不起作用?因此,您检查了在整个过程中,如果您为了测试使用 FileOutputStream 而不是来自外部上下文,是否会获得内容正确的文件?
  • DO 在 java 和 xhtml 中都有一段错误的代码,@Seleron 对此发表了评论:“嗯,我从未见过将 bean 构造函数用作操作方法 - 是否打算工作?” 对于您在 java 中可能出现的错误,我写了另一条评论:“如果您为了测试使用 FileOutputStream 而不是来自外部上下文,您会得到一个包含正确内容的文件?” 我还提到了一些关于测试非 pdf 文件的内容......请更积极一点。

标签: java jsf


【解决方案1】:

您的 bean 的 构造函数 的主体与示例中给出的下载 方法 的主体相同。

您的命令链接 &lt;h:commandButton action="#{fileDownloadView.fileDownloadView}" .../&gt; 操作 method 表达式正在尝试在您的 bean 上查找并调用名为 fileDownloadViewmethod,但该 method 不存在。

您的public FileDownloadView 是一个构造函数,因为它没有返回值类型并且与类同名。如果您将其更改为public void download,则 bean 将不再具有显式构造函数,但最后是一个可由命令按钮调用的方法,如下所示:

 <h:commandButton action="#{fileDownloadView.download}" value="Download"/>

大小写很重要,所以不要调用public void Download之类的方法。

我不确定您当前的实现中实际发生了什么,但我猜在解决 #{fileDownloadView.fileDownloadView} 时,从表达式的第一部分和构造函数中的代码创建了一个新的 bean fileDownloadView 实例被成功执行。一些 CPU 周期之后,ELResolver 无法解析表达式的第二个 .fileDownloadView 部分,并引发异常,这会搞砸事情。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-20
    • 2020-08-07
    • 2015-04-22
    • 2018-06-22
    • 2021-09-01
    • 2015-08-19
    相关资源
    最近更新 更多