0

背景

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

问题

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

源代码

源代码包括:

  • 按钮动作
  • 托管豆
  • 任务流

按钮动作

按钮动作:

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

托管豆

托管 Bean 相当复杂。代码 toresponseComplete被调用,但是它似乎没有被足够早地调用以防止应用程序框架编写 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

相关链接

谢谢!

4

1 回答 1

0

问题是 RFC 2183 的错误实现:

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

;不能,是.

于 2012-12-03T21:45:07.287 回答