3

我有一个按钮,可以打开一个带有生成的 pdf 文件的新选项卡。但是,单击按钮后,我想导航到另一个页面。

这意味着,单击按钮后,我想用 pdf 打开一个新选项卡并导航到初始选项卡上的另一个页面。我正在使用 primefacesp:commandButton并尝试过,onclick="window.location.href='www.google.de'"但它不起作用。但是onclick="window.lalert('www.google.de')"确实有效。

这是我的代码:

<h:form id="transForm" target="_blank">
<p:commandButton  value="Zertifikat erstellen" ajax="false" 
                                label="Speichert die Anmeldung und erstellt ein Zertifikat im PDF-Format"
                                action="#{transportErfassen.generatePDFZertifikat()}"/>

</h:form>

generatePDFZertifikat()确实使用以下代码创建了一个pdf文件,我认为这是问题所在:

    FacesContext facesContext = FacesContext.getCurrentInstance();
    ExternalContext externalContext = facesContext.getExternalContext();

    externalContext.setResponseContentType("application/pdf" );
    externalContext.setResponseHeader("Expires", "0");
    externalContext.setResponseHeader("Cache-Control","must-revalidate, post-check=0, pre-check=0");
    externalContext.setResponseHeader("Pragma", "public");
    externalContext.setResponseHeader("Content-disposition", "inline; filename=\"" + fileName +"\"");
    externalContext.setResponseContentLength(out.length);
    externalContext.addResponseCookie(Constants.DOWNLOAD_COOKIE, "true", new HashMap<String, Object>());

    //setze explizit auf OK
    externalContext.setResponseStatus(200);     

    OutputStream os = externalContext.getResponseOutputStream();
    os.write(out, 0, out.length);
    os.flush();

    facesContext.responseComplete();       
    facesContext.renderResponse();       
4

2 回答 2

4

您基本上是在尝试将 2 个响应发送回 1 个请求。这在 HTTP 中是行不通的。如果你想发回 2 个响应,你必须让客户端以某种方式触发 2 个请求。您已经在寻找解决方案的正确方向,几乎没有 JavaScript 的帮助就可以在单个事件(单击)上触发多个请求。但是,您的尝试onclick无效,window.location在表单提交之前单击提交按钮的更改完全中止了按钮的原始操作,即提交表单。

您最好的选择是直接导航到结果页面,该页面反过来window.open()在页面加载时调用 JavaScript,指向您要打开的 PDF 文件的 URL。即不可能与指示导航的 PDF 文件一起发送一些 HTML/JS 代码(因为这显然会损坏 PDF 文件)。这也意味着,您不能将 PDF 直接返回到表单提交请求。必须重新设计代码,以便后续 GET 请求可以检索 PDF。最好的方法是使用一个简单的 servlet。您可以将生成的 PDF 临时存储在磁盘或会话中,与唯一键关联,然后将该唯一键作为请求路径信息或参数传递给window.open()URL 中的 servlet。

这是一个启动示例:

初始形式:

<h:form>
    ...
    <p:commandButton ... action="#{bean.submit}" />
</h:form>

豆:

public String submit() {
    File file = File.createTempFile("zertifikat", ".pdf", "/path/to/pdfs");
    this.filename = file.getName();

    // Write content to it.

    return "targetview";
}

目标视图:

<h:outputScript rendered="#{not empty bean.filename}">
    window.open('#{request.contextPath}/pdfservlet/#{bean.filename}');
</h:outputScript>

PDF servlet(为简洁起见省略了 nullchecks 等;假定为 Java 7 Files#copy()):

@WebServlet("/pdfservlet/*")
public class PdfServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        File file = new File("/path/to/pdfs", request.getPathInfo().substring(1));
        response.setHeader("Content-Type", "application/pdf");
        response.setHeader("Content-Length", String.valueOf(file.length()));
        response.setHeader("Content-Disposition", "inline; filename=\"zertifikat.pdf\"");
        Files.copy(file.toPath(), response.getOutputStream());
    }

}
于 2013-08-20T11:20:22.627 回答
1

正如 BalusC 所说,Refresh/navigate current page并且opening downloading file是两个不同的响应,必须有两个请求。我遇到了类似的问题。我用jsf ajax成功解决了。

这是我的代码的一部分:

XHTML:</p>

<h:commandButton id="download-button" class="download-button"
    value="download">
<f:ajax event="click" execute="@form" render=":msg-area"
    listener="#{myController.checkForDownload}" onevent="checkCallBack" />
</h:commandButton>
<h:commandButton id="download-button2" class="download-button2"
    value="download" style="display: none;"
    action="#{myController.download}">
</h:commandButton>

Javascript:

function checkCallBack(data) {
    var ajaxStatus = data.status;
    switch (ajaxStatus) {
    case "begin":
        break;
    case "complete":
        break;
    case "success":
        document.getElementById('download-form:download-button2').click();
        break;
    }
}

download-button在页面上呈现消息区域并download-button2触发下载方法。他们是两个不同的请求。当第一个请求完成时,将触发第二个请求。

于 2015-12-08T09:56:44.983 回答