简体   繁体   English

在新标签页/窗口中打开/下载文件时刷新/浏览当前页面

[英]Refresh/navigate current page while opening/downloading file in new tab/window

I have a button which opens a new tab with a generated pdf-file. 我有一个按钮,它将打开一个带有生成的pdf文件的新标签页。 However, after I click on the button, I want to navigate to another page. 但是,单击按钮后,我想导航到另一个页面。

That means, after clicking on the button i want to open a new tab with the pdf and navigate to another page on the initial tab. 这意味着,单击按钮后,我想用pdf打开一个新标签,然后导航到初始标签上的另一页。 I am using primefaces p:commandButton and tried with onclick="window.location.href='www.google.de'" but it does not work. 我正在使用primefaces p:commandButton并尝试使用onclick="window.location.href='www.google.de'"但它不起作用。 However onclick="window.lalert('www.google.de')" does work. 但是onclick="window.lalert('www.google.de')"确实可以工作。

This is my code: 这是我的代码:

<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() does create a pdf-File with following code, I think here is the issue: 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();       

You're basically trying to send 2 responses back to 1 request. 您基本上是在尝试将2个响应发送回1个请求。 This is not ever going to work in HTTP. 这永远不会在HTTP中起作用。 If you want to send 2 responses back, you've got to let the client fire 2 requests somehow. 如果您想发回2个响应,则必须让客户端以某种方式触发2个请求。 You were already looking in the right direction for the solution, with little help of JavaScript it's possible to fire multiple requests on a single event (click). 您已经在为解决方案寻找正确的方向,而在JavaScript的帮助下,可以在单个事件(点击)上触发多个请求。 Your attempt in onclick is however not valid, the change of window.location on click of the submit button, right before the form submit, completely aborts the original action of the button, submitting the form. 但是,您对onclick尝试无效,在提交表单之前,单击“提交”按钮时更改window.location完全中止按钮的原始操作,从而提交表单。

Your best bet is to directly navigate to the result page which in turn invokes JavaScript window.open() on page load, pointing to the URL of the PDF file which you'd like to open. 最好的选择是直接导航到结果页面,该页面依次在页面加载时调用JavaScript window.open() ,指向您要打开的PDF文件的URL。 It's namely not possible to send some HTML/JS code along with the PDF file instructing a navigation (as that would obviously corrupt the PDF file). 也就是说,无法与指示导航的PDF文件一起发送一些HTML / JS代码(因为这显然会破坏PDF文件)。 This also means, that you can't return the PDF directly to the form submit request. 这也意味着,您不能将PDF直接返回到表单提交请求。 The code has to be redesigned in such way that the PDF can be retrieved by a subsequent GET request. 必须重新设计代码,以便可以通过后续的GET请求检索PDF。 The best way is to use a simple servlet. 最好的方法是使用简单的servlet。 You could store the generated PDF temporarily on disk or in session, associated with an unique key, and pass that unique key as request pathinfo or parameter to the servlet in window.open() URL. 您可以将生成的PDF与唯一键临时存储在磁盘或会话中,然后将该唯一键作为请求pathinfo或参数传递给window.open() URL中的servlet。

Here's a kickoff example: 这是一个启动示例:

Initial form: 初始形式:

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

Bean: 豆角,扁豆:

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

    // Write content to it.

    return "targetview";
}

Target view: 目标视图:

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

PDF servlet (nullchecks etc omitted for brevity; Java 7 assumed for Files#copy() ): PDF Servlet(为简洁起见,省略了nullchecks等;为Files#copy()假定使用Java 7):

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

}

As BalusC said, Refresh/navigate current page and opening downloading file are two different responses, there must be two resquests. 正如BalusC所说, Refresh/navigate current pageopening downloading file是两个不同的响应,必须有两个请求。 I encountered a similar problem. 我遇到了类似的问题。 I solved it with jsf ajax successfully. 我用jsf ajax成功解决了。

Here's part of my code: 这是我的代码的一部分:

XHTML: XHTML:

<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: 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 renders a message area on page and download-button2 triggers a download method. download-button在页面上呈现消息区域,而download-button2触发下载方法。 they are two different requests. 他们是两个不同的请求。 When the first request completed, the second request will be triggered. 当第一个请求完成时,将触发第二个请求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM