JSF 2.0使用Flying Saucer将XHTML页面转换为PDF:java.lang.IllegalStateException

问题描述 投票:7回答:1

我正在尝试将JSF页面转换并导出为PDF。我尝试了以下方式:

豆角,扁豆:

public void createPDF() {
    try {
        ITextRenderer renderer = new ITextRenderer();
        renderer.setDocument(new URL(url).toString());
        renderer.layout();
        HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
        response.reset();
        response.setContentType("application/pdf");
        response.setHeader("Content-Disposition", "inline; filename=\"" +PDF_FILE_NAME+ "\"");
        OutputStream browserStream = response.getOutputStream();
        renderer.createPDF(browserStream);
    } catch (Exception ex) {
        Logger.getLogger(PdfBean.class.getName()).log(Level.SEVERE, null, ex);
    }
}

使用创建PDF按钮/home.xhtml的页面:

<ui:define name="content">
    <center>
        <h:form id="pdfgen">
            <h:panelGrid columns="2">
                <h:outputText value="Enter Name:"/>
                <h:inputText value="#{pdfBean.name}"/>
            </h:panelGrid>
            <h:commandButton value="Create PDF" action="#{pdfBean.createPDF()}"/>
        </h:form>
    </center>
</ui:define>

我要转换的页面:

<ui:define name="content">
    <center>
        <h:outputText value="Hello #{pdfBean.name}"/>
    </center>
</ui:define>

当我尝试我只获得一次PDF时,再也不会。我得到了以下Facelet异常:

SEVERE: Error Rendering View[/home.xhtml]
java.lang.IllegalStateException: PWC3991: getOutputStream() has already been called for this response
...
WARNING: StandardWrapperValve[Faces Servlet]: PWC1406: Servlet.service() for servlet Faces Servlet threw exception
java.lang.IllegalStateException: PWC3991: getOutputStream() has already been called for this response

我究竟做错了什么?

更新Bean:请参阅BalusC的答案:

public void createPDF() {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    ExternalContext externalContext = facesContext.getExternalContext();
    String servername = externalContext.getRequestServerName();
    String port = String.valueOf(externalContext.getRequestServerPort());
    String appname = externalContext.getRequestContextPath();
    String protocol = externalContext.getRequestScheme();
    this.url = protocol + "://" + servername + ":" + port + appname + PDF_PAGE;
    try {
        ITextRenderer renderer = new ITextRenderer();
        renderer.setDocument(new URL(url).toString());
        renderer.layout();
        HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
        response.reset();
        response.setContentType("application/pdf");
        response.setHeader("Content-Disposition", "inline; filename=\"" + PDF_FILE_NAME + "\"");
        OutputStream browserStream = response.getOutputStream();
        renderer.createPDF(browserStream);

    } catch (Exception ex) {
        Logger.getLogger(PdfBean.class.getName()).log(Level.SEVERE, null, ex);
    }
    facesContext.responseComplete();
}
java jsf pdf-generation flying-saucer
1个回答
8
投票

您需要指示JSF您已经完成了响应处理,并且在操作方法完成时JSF不应该处理默认导航。将其添加到操作方法的末尾:

facesContext.responseComplete();

根据评论更新,您将访问ExternalContext作为实例变量,表明您已将其和FacesContext分配为类变量,static或作为会话范围bean的属性。这绝对是一个坏主意。你应该通过FacesContext#getCurrentInstance()在本地方法中获取它们,并且永远不要将它们作为类变量赋值。它们被绑定到一个特定的请求线程,该线程在下一个请求中不再存在。

© www.soinside.com 2019 - 2024. All rights reserved.