使用带有自定义HTTP标头的Managed Bean生成PDF

时间:2012-11-30 23:23:29

标签: jsf-2 http-headers reporting jdeveloper oracle-adf

背景

使用ADF任务流生成各种格式的报告(例如PDF,分隔符,HTML)。

问题

HTTP标头被发送两次:一次由框架发送,一次由bean发送。

源代码

源代码包括:

  • 按钮操作
  • Managed Bean
  • 任务流程

按钮操作

按钮操作:

<af:commandButton text="Report" id="submitReport" action="Execute" />

Managed Bean

Managed Bean相当复杂。调用responseComplete的代码,但似乎没有足够早地调用它来阻止应用程序框架编写HTTP头。

HTTP响应标头覆盖

/**
 * Sets the HTTP headers required to indicate to the browser that the
 * report is to be downloaded (rather than displayed in the current
 * window).
 */
protected void setDownloadHeaders() {
  HttpServletResponse response = getServletResponse();
  response.setHeader( "Content-Description", getContentDescription() );
  response.setHeader( "Content-Disposition", "attachment, filename="
    + getFilename() );
  response.setHeader( "Content-Type", getContentType() );
  response.setHeader( "Content-Transfer-Encoding",
    getContentTransferEncoding() );
}

问题回复完成

getFacesContext().responseComplete();

Bean运行和配置

public void run() {
  try {
    Report report = getReport();
    configure(report.getParameters());
    report.run();
  } catch (Exception e) {
    e.printStackTrace();
  }
}

private void configure(Parameters p) {
  p.put(ReportImpl.SYSTEM_REPORT_PROTOCOL, "http");
  p.put(ReportImpl.SYSTEM_REPORT_HOST, "localhost");
  p.put(ReportImpl.SYSTEM_REPORT_PORT, "7002");
  p.put(ReportImpl.SYSTEM_REPORT_PATH, "/reports/rwservlet");
  p.put(Parameters.PARAM_REPORT_FORMAT, "pdf");

  p.put("report_cmdkey", getReportName());
  p.put("report_ORACLE_1", getReportDestinationType());
  p.put("report_ORACLE_2", getReportDestinationFormat());
}

任务流程

任务流调用Execute,它引用bean的run()方法:

entry -> main -> Execute -> ReportBeanRun

其中:

  <method-call id="ReportBeanRun">
    <description>Executes a report</description>
    <display-name>Execute Report</display-name>
    <method>#{reportBean.run}</method>
    <outcome>
      <fixed-outcome>success</fixed-outcome>
    </outcome>
  </method-call>

将bean分配到request范围,并使用一些托管属性:

  <control-flow-rule id="__3">
    <from-activity-id>main</from-activity-id>
    <control-flow-case id="ExecuteReport">
      <from-outcome>Execute</from-outcome>
      <to-activity-id>ReportBeanRun</to-activity-id>
    </control-flow-case>
  </control-flow-rule>

  <managed-bean id="ReportBean">
    <description>Executes a report</description>
    <display-name>ReportBean</display-name>
    <managed-bean-scope>request</managed-bean-scope>
    ...
  </managed-bean>

<fixed-outcome>success</fixed-outcome>让我觉得不对 - 我不希望方法调用返回另一个任务。

限制

报表服务器专门接收来自Web服务器的请求。出于安全原因,浏览器不能使用报表服务器URL直接下载。

错误消息

生成的错误消息:

  

从服务器收到的重复标头

     

错误349(net :: ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION):收到多个不同的Content-Disposition标头。这是不允许的,以防止HTTP响应分裂攻击。

尽管如此,生成的报告 。阻止框架编写HTTP头将解决此问题。

问题

如何在使用任务流通过调用托管bean生成PDF时在ADF中设置HTTP标头?

其他一些想法:

  • 覆盖网页生命周期阶段监听器(ADFPhaseListener + PageLifecycle
  • 在Web服务器上开发自定义Servlet

相关链接

谢谢!

1 个答案:

答案 0 :(得分:0)

问题是RFC 2183的实施不正确:

response.setHeader( "Content-Disposition", "attachment; filename="
  + getFilename() );

;不能是,