背景
使用 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
相关链接
- http://www.oracle.com/technetwork/middleware/bi-publisher/adf-bip-ucm-integration-179699.pdf
- http://www.slideshare.net/lucbors/reports-no-notes#btnNext
- http://www.techartifact.com/blogs/2012/03/calling-oracle-report-from-adf-applications.html?goback=%2Egde_4212375_member_102062735
- http://docs.oracle.com/cd/E29049_01/web.1112/e16182/adf_lifecycle.htm#CIABEJFB
谢谢!