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

时间:2010-12-10 05:53:55

标签: java ajax http jsf seam

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

以下是我遇到问题的情况:

      
  1. 如果用户最初输入无效输入然后单击该按钮,Seam将处理该请求,但会在Process Validations阶段停止。然后我的页面显示验证错误消息。
  2.   
  3. 接下来,如果用户输入正确的输入并单击按钮,Seam会调用我的操作处理程序,生成文件并将其发送给响应中的用户 - 但仍会显示验证错误消息!< /强>
  4. 最初,我尝试了一些黑客强制重新发布<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"),该页面将遵循我已正确设置的导航规则。但是对于该文件,页面保持完全相同按下按钮之前。

    那么,我如何在响应中返回一个文件,并导致<h:messages/>标记被重新呈现?

2 个答案:

答案 0 :(得分:0)

在写完

后将其添加到您的方法中
//Skip the rest of JSF phases
FacesContext.getCurrentInstance().responseComplete();

您可能还希望在finally块中添加close,以便确保在发生异常时正确关闭流。 或者从Lombok添加@Cleanup注释,它会自动为您执行

<强>更新

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

@End(beforeRedirect=true)

答案 1 :(得分:0)

  

那么,我怎样才能在响应中返回一个文件,并导致标记被重新呈现?

单个HTTP请求无法实现。每个请求只能返回一个响应。这不是JSF限制,这是HTTP限制。

can使用JavaScript只需点击一下即可触发两个HTTP请求,但在你的特定情况下,由于JSF对消息的请求取决于PDF下载请求的结果,因此无法正常工作。我没有看到其他方法,除了让servlet设置一个会话范围的托管属性,表示PDF导出的状态,并引入一个ajax轮询,它会间隔地请求此属性,并在它不再为null时停止。