背景
使用 JDeveloper 11.1.2.3 创建报告下载按钮,使用fileDownloadActionListener如下:
<af:commandButton text="Run Report" id="submitReport">
  <af:fileDownloadActionListener method="#{reportBean.run}"/>
</af:commandButton>
此 JSF 页面的顶部是以下内容:
<f:view afterPhase="#{validationBean.afterPhase}" ...>
  ...
    <af:form id="f1">
      <f:event listener="#{validationBean.postValidate}" type="postValidate"/>
这个想法是验证 Bean 可以捕获任何验证问题,如下所示:
public void afterPhase(javax.faces.event.PhaseEvent phaseEvent) {
  if (phaseEvent.getPhaseId() == PhaseId.RENDER_RESPONSE) {
    FacesContext context = phaseEvent.getFacesContext();
    FacesMessage.Severity severity = context.getMaximumSeverity();
    if (isSevereError(severity)) {
      context.getExternalContext().getSessionMap().put(ERROR_FLAG_NAME, true);
    }
  }
}
这按预期工作。当用户按下按钮,但表单出现错误时,validationError会话变量设置为true. 如果表单参数有错误,这应该允许框架防止生成报告。
问题
报告 bean的validationErrorrun 方法使用 session 变量,如下所示:
  public void run(FacesContext facesContext, OutputStream outputStream) {
    Object error = facesContext.getExternalContext().getSessionMap().get( ERROR_FLAG_NAME );
    if( error != null && error != Boolean.TRUE ) {
      Report report = null;
      try {
        report = getReport();
        report.setOutputStream(outputStream);
        configure(report.getParameters());
        report.run();
      } catch (Exception e) {
        if (report != null && facesContext != null) {
          report.publish(e);
        }
      }
    }
    else {
      facesContext.getExternalContext().getSessionMap().remove( ERROR_FLAG_NAME );
      facesContext.renderResponse();
    }
  }
当页面出现验证错误时,facesContext.renderResponse();代码被执行,但生成的网页是空白的。不记录任何异常。不会产生错误。
问题
避免这种情况的一种方法是使用隐藏按钮、自定义 Java 和一些 JavaScript,如下页所述:
- http://jobinesh.blogspot.ca/2010/01/customizing-execution-of-to-validate.html
 - http://tompeez.wordpress.com/2011/07/14/validate-data-before-export-via-afexportcollectionactionlistener-or-affiledownloadactionlistener/
 
然而,这种机制是复杂的。如果页面可以照常呈现,我想到的解决方案将起作用。
af:fileDownloadActionListener事件触发后如何强制呈现页面?