当响应包含文件时,页面导航/渲染响应阶段将被忽略

发布于 2024-10-07 09:44:13 字数 1688 浏览 0 评论 0原文

JSF/接缝。我有一个页面,它接受用户通过表单提供的一些参数,然后(当用户单击页面上的按钮时)服务器生成一个文件并将其在响应中发送,以便提示用户保存-作为对话框。

这是我遇到问题的场景:

  1. 如果用户最初输入无效输入,然后单击按钮,Seam 会处理该请求,但会在“处理验证”阶段停止。然后我的页面显示验证错误消息。
  2. 接下来,如果用户输入正确的输入并单击按钮,Seam 会调用我的操作处理程序,生成文件并在响应中发送给用户 - 但仍然显示验证错误消息!

最初,我尝试了一些技巧来强制重新渲染 标记,但没有什么令人满意的。 我现在怀疑根本原因是因为当我将文件放入响应中时,Seam 没有进入渲染响应阶段。

这是我的按钮:

<h:commandButton value="#{messages.Reports_RunReportPDF}"
                 action="#{bean.generateReportPdf}"/>

这是我的操作处理程序:

public String generateReportPdf() throws IOException {
  FacesContext facesContext = FacesContext.getCurrentInstance();
  HttpServletResponse response = (HttpServletResponse)facesContext.getExternalContext().getResponse();

  ServletOutputStream servletOutputStream = response.getOutputStream();

  // add this header to make browser prompt user with a save-as dialog
  response.addHeader("Content-Disposition",
                     "attachment;filename=" + reportName + ".pdf");
  response.setContentType(exportType.contentType());

  try {
    HashMap<String, Object> parameters = getReportParameters();
    ReportContent content = createReport(parameters);

    servletOutputStream.write(content.getContents());
    servletOutputStream.flush();
    servletOutputStream.close();
  } catch (ReportingException e) {
    e.printStackTrace();
    return "fail";
  }

  return "success";
}

如果我注释掉以下代码添加文件(然后返回“success”,页面遵循我正确设置的导航规则。但是使用该文件,页面与按下按钮之前完全相同。

那么,如何在响应中返回文件并导致 标记被重新渲染?

JSF/Seam. I have a page which accepts some parameters supplied by the user via a form, and then (when the user clicks a button on the page) the server generates a file and sends it in the response such that the user is prompted with a save-as dialog.

Here is the scenario that I'm having trouble with:

  1. If the user initially enters invalid input and then clicks the button, Seam processes the request, but stops at the Process Validations phase. My page then displays the validation error message.
  2. Next, if the user then enters the correct input and clicks the button, Seam calls my action handler, the file is generated and sent to the user in the response - but the validation error message is still displayed!

Initially, I tried some hacks to force the rerendering of the <h:messages/> tag, but nothing was satisfactory. I now suspect the root cause is because Seam does not enter the Render Response phase when I place a file in the response.

Here's my button:

<h:commandButton value="#{messages.Reports_RunReportPDF}"
                 action="#{bean.generateReportPdf}"/>

And here's my action handler:

public String generateReportPdf() throws IOException {
  FacesContext facesContext = FacesContext.getCurrentInstance();
  HttpServletResponse response = (HttpServletResponse)facesContext.getExternalContext().getResponse();

  ServletOutputStream servletOutputStream = response.getOutputStream();

  // add this header to make browser prompt user with a save-as dialog
  response.addHeader("Content-Disposition",
                     "attachment;filename=" + reportName + ".pdf");
  response.setContentType(exportType.contentType());

  try {
    HashMap<String, Object> parameters = getReportParameters();
    ReportContent content = createReport(parameters);

    servletOutputStream.write(content.getContents());
    servletOutputStream.flush();
    servletOutputStream.close();
  } catch (ReportingException e) {
    e.printStackTrace();
    return "fail";
  }

  return "success";
}

If I comment-out the code which adds the file (and just return "success", the page follows the navigation rules I have set up correctly. But with the file, the page stays exactly the same as it was before the button was pushed.

So, how can I both return a file in the response, and cause the <h:messages/> tag to be rerendered?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

神回复 2024-10-14 09:44:13

那么,如何在响应中返回文件并导致标签重新呈现?

这对于单个 HTTP 请求来说是不可能的。每个请求只能返回一个响应。这不是 JSF 限制,而是 HTTP 限制。

可以使用 JavaScript 来触发两个 HTTP 请求:单击一下即可,但在您的特定情况下,这不会很好地工作,因为 JSF 对消息的请求取决于 PDF 下载请求的结果。除了让 servlet 设置代表 PDF 导出状态的会话范围托管属性并引入 ajax 轮询(每隔一段时间请求该属性并在它不再为空时停止)之外,我没有看到其他方法。

So, how can I both return a file in the response, and cause the tag to be rerendered?

That's not possible with a single HTTP request. You can return only one response per request. This is not a JSF limitation, this is a HTTP limitation.

You can use JavaScript to fire two HTTP requests by a single click, but in your particular case this wouldn't work nicely since the JSF request for the message depends on the result of the request for the PDF download. I don't see other ways than letting the servlet set a property of a session scoped managed which represents the status of the PDF export and introduce an ajax poll which requests this property at intervals and stops when it's not null anymore.

满意归宿 2024-10-14 09:44:13

在写入后将其添加到您的方法中

//Skip the rest of JSF phases
FacesContext.getCurrentInstance().responseComplete();

您可能还需要在finally块中添加关闭,以便确保在发生异常时正确关闭流。
或者添加来自 Lombok 的 @Cleanup 注释,它会自动为您

更新

如果您处于长时间运行的对话中,您可以在重定向之前结束对话,从而删除验证消息。

@End(beforeRedirect=true)

Add this to your method after your write

//Skip the rest of JSF phases
FacesContext.getCurrentInstance().responseComplete();

You might also want to add the close in a finally block so that you ensure that the stream is properly closed if exception occurs.
Or add the @Cleanup annotation from Lombok, and it will do it for you automatically

Update

If you are inside a long running conversation, you can end the conversation before the redirect, thus the validation message will be removed.

@End(beforeRedirect=true)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文