Java 当响应包含文件时,将忽略页面导航/呈现响应阶段

Java 当响应包含文件时,将忽略页面导航/呈现响应阶段,java,ajax,http,jsf,seam,Java,Ajax,Http,Jsf,Seam,JSF/Seam。我有一个页面,它接受用户通过表单提供的一些参数,然后(当用户单击页面上的按钮时),服务器生成一个文件,并在响应中发送该文件,这样用户就会收到另存为对话框的提示 以下是我遇到问题的场景: 如果用户最初输入无效输入,然后单击按钮,Seam将处理该请求,但会在流程验证阶段停止。然后,我的页面显示验证错误消息 接下来,如果用户随后输入正确的输入并单击按钮,Seam将调用我的操作处理程序,文件将在响应中生成并发送给用户-,但仍然显示验证错误消息 起初,我尝试了一些黑客手段来强制重新命名标

JSF/Seam。我有一个页面,它接受用户通过表单提供的一些参数,然后(当用户单击页面上的按钮时),服务器生成一个文件,并在响应中发送该文件,这样用户就会收到另存为对话框的提示

以下是我遇到问题的场景:

  • 如果用户最初输入无效输入,然后单击按钮,Seam将处理该请求,但会在流程验证阶段停止。然后,我的页面显示验证错误消息
  • 接下来,如果用户随后输入正确的输入并单击按钮,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";
    }
    
    公共字符串generateReportPdf()引发IOException{
    FacesContext FacesContext=FacesContext.getCurrentInstance();
    HttpServletResponse=(HttpServletResponse)facesContext.getExternalContext().getResponse();
    ServletOutputStream ServletOutputStream=response.getOutputStream();
    //添加此标题可使浏览器提示用户显示另存为对话框
    response.addHeader(“内容处置”,
    “附件;文件名=“+reportName+”.pdf”);
    response.setContentType(exportType.contentType());
    试一试{
    HashMap参数=getReportParameters();
    ReportContent=createReport(参数);
    write(content.getContents());
    servletOutputStream.flush();
    servletOutputStream.close();
    }捕获(报告异常e){
    e、 printStackTrace();
    返回“失败”;
    }
    返回“成功”;
    }
    
    如果我注释掉添加文件的代码(只需返回
    “success”
    ),页面将遵循我正确设置的导航规则。但是对于文件,页面将与按下按钮之前保持完全相同


    那么,如何在响应中返回一个文件,并使
    标记重新提交呢?

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

    //Skip the rest of JSF phases
    FacesContext.getCurrentInstance().responseComplete();
    
    您可能还希望在finally块中添加close,以便在发生异常时确保流正确关闭。 或者从Lombok添加注释,它会自动为您完成

    更新

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

    @End(beforeRedirect=true)

    那么,如何在响应中返回一个文件,并使标记重新提交呢

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


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

    “单次HTTP请求不可能做到这一点。”
    Gotcha。我可以看到ajax轮询解决方案是如何工作的,但这对我们来说不是一个理想的解决方案,所以看起来我必须从另一个角度来考虑这个问题。干杯。这句话最初在我的代码中-我删除它是为了看看效果如何。它不会影响我的messages标记的重新发布。