【问题标题】:JSF2 download file returns xhtml page sourceJSF2下载文件返回xhtml页面源
【发布时间】:2012-09-20 14:15:50
【问题描述】:

我已经为此工作了几个小时:

按下按钮时,我需要生成 XML 并将其下载给用户。我已经尝试将 primefaces StreamedContent 与 p:fileDownload 一起使用 - 但我得到的唯一输出是实际页面的 .xhtml 源。我可以在返回 StreamedContent 之前使用日志语句来显示它的内容,并且我可以在那里正确地看到我的 XML 代码,但是下载的文件总是有页面源代码。 (我也尝试了很多其他方法,下载 jpg 文件、更改 bean 以直接生成响应并通过 h:commandButton 中的操作调用方法 - 始终获取页面源!)。

这是我的 .xhtml:

        <p:commandButton value="Create XML Bid/Offer" 
                 id="createXMLButton" 
             disabled="#{portfolioBean.noPortfolioSelected}"
                 ajax="false"
                 icon="ui-icon-arrowthichk-s">
    <p:fileDownload value="#{portfolioBean.order}" />  
</p:commandButton>

(替代)

    <h:commandButton value="Create XML Bid/Offer" 
    id="createXMLButton" 
    disabled="#{portfolioBean.noPortfolioSelected}"
     ajax="false"
    icon="ui-icon-arrowthichk-s"
    action="#{portfolioBean.download()}" /> 

以及支持 bean 的方法:

        public StreamedContent getOrder() {
...
}

(替代)

        public String download() {
...
} 

我没有包含方法主体,因为我知道它们返回正确的 XML……这似乎真的是 JSF 魔法中的东西。这是配置问题还是什么?

谢谢!

更新 好的 - 我已经从我的代码中删除了所有内容,所以就是这样:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:p="http://primefaces.org/ui">
<h:head>
    <title>Edison Energy Portal</title>
</h:head>
<h:body>
    <h:form id="form">
        <h:commandButton value="Download PDF" action="#{downloadJPG.downloadFile}" />
     </h:form>
</h:body>
</html>

public class DownloadJPG {

// Constants ----------------------------------------------------------------------------------

private static final int DEFAULT_BUFFER_SIZE = 10240; // 10KB.

// Actions ------------------------------------------------------------------------------------

public void downloadFile() throws IOException {

    // Prepare.
    FacesContext facesContext = FacesContext.getCurrentInstance();
    ExternalContext externalContext = facesContext.getExternalContext();
    HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();

    File file = new File("....", "....");
    BufferedInputStream input = null;
    BufferedOutputStream output = null;

    try {
        // Open file.
        input = new BufferedInputStream(new FileInputStream(file), DEFAULT_BUFFER_SIZE);

        // Init servlet response.
        response.reset();
        response.setHeader("Content-Type", "application/pdf");
        response.setHeader("Content-Length", String.valueOf(file.length()));
        response.setHeader("Content-Disposition", "inline; filename=\"...\"");
        output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);

        // Write file contents to response.
        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
        int length;
        while ((length = input.read(buffer)) > 0) {
            output.write(buffer, 0, length);
        }

        // Finalize task.
        output.flush();
    } finally {
        // Gently close streams.
        close(output);
        close(input);
    }

    // Inform JSF that it doesn't need to handle response.
    // This is very important, otherwise you will get the following exception in the logs:
    // java.lang.IllegalStateException: Cannot forward after response has been committed.
    facesContext.responseComplete();
}

// Helpers (can be refactored to public utility class) ----------------------------------------

private static void close(Closeable resource) {
    if (resource != null) {
        try {
            resource.close();
        } catch (IOException e) {
            // Do your thing with the exception. Print it, log it or mail it. It may be useful to 
            // know that this will generally only be thrown when the client aborted the download.
            e.printStackTrace();
        }
    }
}

}

我检查了我的源图像文件,它没有损坏。 BalusC 的代码尝试了一次,然后我用 XML 文件替换了当前的 jpg,更改了 MIME 类型,此后没有任何效果。好像有什么不好的东西在tomcat中绊倒了,我无法将其取出或重置(我尝试通过eclipse手动清理tomcat,甚至重新启动我的盒子)。

这是一个真正的装腔作势。

更新: 我已经开始 eclipse clean - 没有运气。我真的没主意了。我不得不认为这是某处的配置,因为我知道这段代码可以工作(我见过)。

【问题讨论】:

  • 这有效 - 但它在另一个窗口中打开它,而不是启动“查看/另存为”对话框。谢谢一堆。我正在尝试使其适应我的 XML,然后我需要它来下载而不是显示...欢迎任何建议。

标签: jsf-2 primefaces


【解决方案1】:

鉴于没有其他人(甚至强大的BalusC)回答,我将其发布为评论。

关于如何下载,再次the BalusC blog。如果您有空闲,值得浏览一下。

关于浏览器如何管理它的问题,这取决于浏览器的处理方式,无论如何大多数人都应该尊重Content-Disposition 标头。在示例中更改此行

response.setHeader("Content-Disposition", "inline; filename=\"" + getFileName() + "\"");

response.setHeader("Content-Disposition", "attachment; filename\"" + getFileName() + "\"");

reference

【讨论】:

  • 谢谢,我想通了。我试图将我的 xml 输出缓冲区映射到输入缓冲区并从中读取而不是文件输入,但它产生了错误,所以我只得到了我的 XML 任务可以生成的输出文件之一并将其替换为 pdf 文件(更改mime 类型) - 并且立即再次出现错误,下载的内容是页面源。现在这是踢球者,当我将代码放回使用原始文件时,下载的内容仍然是源代码。我正在使用eclipse进行测试,我已经尝试清理tomcat及其目录,但是出了点问题。
  • 刚刚重新设计了这个以创建一个临时 xml 文件,然后尝试流式传输该文件(而不是尝试重定向 xml 流 - 我知道,很傻,但我正在掌握这一点)。我可以看到创建的和流式传输的两个文件。创建的文件是正确的 xml,但流文件包含页面源...同样的老问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-17
相关资源
最近更新 更多