【问题标题】:Page navigation / Render response phase is ignored when response contains a file当响应包含文件时,页面导航/渲染响应阶段将被忽略
【发布时间】:2011-05-23 07:25:59
【问题描述】:

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

这是我遇到问题的场景:

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

最初,我尝试了一些技巧来强制重新呈现<h:messages/> 标记,但没有什么令人满意的。 我现在怀疑根本原因是因为当我在响应中放置文件时,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",则页面遵循我正确设置的导航规则。但是有了文件,页面与之前完全相同按钮被按下。

那么,我怎样才能既在响应中返回一个文件,又使&lt;h:messages/&gt; 标记被重新呈现呢?

【问题讨论】:

    标签: java ajax http jsf seam


    【解决方案1】:

    在你写完之后把它添加到你的方法中

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

    您可能还想在 finally 块中添加关闭,以便确保在发生异常时正确关闭流。 或者从 Lombok 添加 @Cleanup 注释,它会自动为你做这件事

    更新

    如果您在一个长时间运行的对话中,您可以在重定向之前结束对话,因此验证消息将被删除。

    @End(beforeRedirect=true)

    【讨论】:

    • 该行最初在我的代码中 - 我将其删除以查看效果。它不会影响我的消息标签的重新呈现。
    【解决方案2】:

    那么,我怎样才能既在响应中返回一个文件,又让标签重新渲染呢?

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

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

    【讨论】:

    • "That's not possible with a single HTTP request." 明白了。我可以看到 ajax 轮询解决方案是如何工作的,但这对我们来说不是一个理想的解决方案,所以看起来我必须考虑从另一个角度解决这个问题。干杯。
    猜你喜欢
    • 1970-01-01
    • 2015-05-08
    • 1970-01-01
    • 2018-07-01
    • 2011-09-11
    • 2018-03-24
    • 1970-01-01
    • 2012-11-08
    相关资源
    最近更新 更多