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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5662455/
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-30 12:09:25  来源:igfitidea点击:

JSF 2.0 Convert XHTML Page to PDF using Flying Saucer: java.lang.IllegalStateException

javajsfpdf-generationflying-saucer

提问by reen

I am trying to convert and export a JSF Page to PDF. I tried it the following way:

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

Bean:

豆角,扁豆:

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

Page with the Create PDF Button /home.xhtml:

带有“创建 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>

The Page which I want to convert:

我要转换的页面:

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

When I try that I get a PDF only once, then never again. I got following Facelet Exception:

当我尝试时,我只得到一次 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

What am I doing wrong?

我究竟做错了什么?

Updated Bean:see BalusC's answer:

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

回答by BalusC

You need to instruct JSF that you've already taken the response handling in your hands and that JSF should not handle the default navigation when the action method is finished. Add this to the end of the action method:

您需要告诉 JSF 您已经掌握了响应处理,并且当操作方法完成时,JSF 不应处理默认导航。将此添加到操作方法的末尾:

facesContext.responseComplete();


Updateas per the comments, you're accessing ExternalContextas an instance variable which suggests that you assigned it and the FacesContextas class variable, either staticor as property of a session scoped bean. This is definitely a bad idea. You should get hand of them inside the local method by FacesContext#getCurrentInstance()and neverassign them as class variable. They are namely bound to a specific request thread which do not exist in next request anymore.

根据评论更新,您ExternalContext作为实例变量访问,这表明您将它和FacesContextas 类变量分配给了它,static或者作为会话作用域 bean 的属性。这绝对是个坏主意。您应该在本地方法中使用它们,FacesContext#getCurrentInstance()并且永远不要将它们分配为类变量。它们即绑定到特定的请求线程,该线程不再存在于下一个请求中。