前言
本教程主要介绍了如何通过Dorado5的集成润乾进行报表的开发相关技术细节,以及提供一个现有项目的集成方案作为借鉴。
本教程使用的Dorado版本为Dorado5,润乾版本为4.0。
原理概述
润乾报表4.0与基于JavaEE的Web系统集成,是通过润乾提供的自定标签(Tag)完成报表的解析以及运算,并按照用户配置的属性要求将报表通过HTML的方式输入到客户端。(具体的润乾提供的Tag详述,请见润乾提供的文档《润乾报表4.0用户开发手册》)。

以Dorado作为展现层的JavaEE Web应用系统,通过润乾提供的Tag进行集成,从而简化了表现层的开发,并与润乾良好的配合,实现相关报表业务场景的快速开发。
集成Dorado5工程
下面,将介绍如何将润乾集成到Dorado5 Web工程中。
一. 创建一个基于Dorado5的Web工程。(新建或者已有的Dorado5 Web工程均可)
具体如何创建Dorado5的Web工程,详见Dorado5的相关文档,这里不做累述。
二. 将润乾需要的相关包以及文件,拷贝到Dorado5工程中。
具体参见润乾提供的文档《润乾报表4.0在J2EE部署教程》。
具体拷贝的文件如下图:

其中,”web发布包”即为Dorado5的Web工程。
三. 修改当前工程的Web.xml文件,添加润乾的报表的相关配置。
添加的配置如下:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <servlet> <servlet-name>reportServlet</servlet-name> <servlet-class>com.runqian.report4.view.ReportServlet</servlet-class> <init-param> <param-name>configFile</param-name> <param-value>/WEB-INF/reportConfig.xml</param-value> </init-param> <init-param> <param-name>headless</param-name> <param-value>false</param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>reportServlet</servlet-name> <url-pattern>/reportServlet</url-pattern> </servlet-mapping> <taglib> <taglib-uri>/WEB-INF/runqianReport4.tld</taglib-uri> <taglib-location>/WEB-INF/runqianReport4.tld</taglib-location> </taglib> </web-app>
四. 配置WEB-INF/reportConfig.xml文件。
配置润乾的相关参数,根据具体的应用系统需求,按需定制。
详细配置参见润乾相关文档。
通过以上几步,将润乾报表集成到了Dorado的Web工程中。
方案介绍
主要满足业务场景:动态的查询条件,查询报表结果。
设计思路:将查询条件设计为一个视图文件,将报表的展现设计成另外一个jsp文件(可复用)。将这个view与jsp合并到一个jsp中,通过查询条件的view的相关操作(如点击“查询”按钮,将动态的参数传入到展现报表的jsp中来展现具体的报表应用)。
即主要有三个文件组成:
viewRadReport.jsp –查看报表的父jsp,负责包含下面两个页面。
xxxQueryView.xml –自定义当前报表的查询条件
viewReport.view.xml与viewReport.jsp –展现报表的模板jsp(可复用)
下面分别详细设计示例:
1. xxxQueryView.xml示例
如下图的查询条件

将查询条件,设计成一个dorado的视图文件,范例借鉴如下(部分js与具体系统应用有关,仅仅提供借鉴,具体应用系统需要自定义实现与本系统相关的部分):
<?xml version="1.0" encoding="UTF-8"?>
<view>
<Datasets>
<Dataset type="Form" id="dsCondition">
<MasterLink/>
<Fields>
<Field dropDown="#ddExchange" visible="false" label="交易所代码:" defaultValue="${Session.EXCHANGEID}" dataType="string" name="i_chExchangeID">
<Properties/>
<FieldType/>
</Field>
<Field dropDown="#ddSettlementGroup" label="结算组代码:" defaultValue="${Session.SETTLEMENTGROUPID}" dataType="string" readOnly="false" name="i_chSettlementGroupID">
<Properties/>
<FieldType/>
</Field>
<Field dropDown="#dropdownDate" label="开始日期(YYYYMMDD):" dataType="" name="i_chStartDate">
<Properties/>
<Validator type="Required"/>
<FieldType validators="length,pattern,required" name="tradingDay"/>
</Field>
<Field dropDown="#dropdownDate" label="结束日期(YYYYMMDD):" dataType="" name="i_chEndDate">
<Properties/>
<Validator type="Required"/>
<FieldType validators="length,pattern,required" name="tradingDay"/>
</Field>
</Fields>
<Parameters/>
<Properties/>
</Dataset>
</Datasets>
<Controls>
<Control type="AutoForm" dataset="dsCondition" id="formCondition">
<FormGroup name="groupCondition" defaultControlWidth="260" dataset="dsCondition" labelWidth="180" title="查询条件">
<Element name="i_chExchangeID" dataset="dsCondition" type="TextEditor" field="i_chExchangeID">
<FieldLabel/>
<TextEditor/>
</Element>
<Element name="i_chSettlementGroupID" dataset="dsCondition" colSpan="2" type="TextEditor" field="i_chSettlementGroupID">
<FieldLabel/>
<TextEditor/>
</Element>
<Element name="i_chStartDate" type="TextEditor" field="i_chStartDate">
<FieldLabel/>
<TextEditor/>
</Element>
<Element name="i_chEndDate" type="TextEditor" field="i_chEndDate">
<FieldLabel/>
<TextEditor/>
</Element>
<Element name="Search" controlAlign="right" showLabel="false" type="Custom" controlId="buttonSearch">
<FieldLabel/>
</Element>
<Element name="Reset" controlAlign="left" showLabel="false" type="Custom" controlId="buttonReset">
<FieldLabel/>
</Element>
</FormGroup>
</Control>
<Control id="buttonSearch" width="80" type="Button" value="查询">
<Events>
<Event name="onClick">if(!dsCondition.postRecord()){
return;
}
var i_chStartDate = dsCondition.getCurrent().getValue("i_chStartDate");
var i_chEndDate = dsCondition.getCurrent().getValue("i_chEndDate");
var i_chExchangeID = dsCondition.getCurrent().getValue("i_chExchangeID");
var i_chSettlementGroupID = dsCondition.getCurrent().getValue("i_chSettlementGroupID");
var i_chOperatorID = "${session.getAttribute('userId')}";
//var raq = Report.raqRelaPath(xmlName);
var saveAsName = "XXXX";
var reportframe = document.getElementById("reportframe");
param = "&i_chExchangeID=" + i_chExchangeID
+ "&i_chSettlementGroupID=" + i_chSettlementGroupID
+ "&i_chOperatorID=" + i_chOperatorID
+ "&i_chStartDate=" + i_chStartDate
+ "&i_chEndDate=" + i_chEndDate
+ "&saveAsName=" + saveAsName;
//alert("../../framework/report/viewReport.jsp?raq=" + raq + param);
reportframe.src="../../framework/report/viewReport.jsp?xmlName=" + xmlName + param;
</Event>
</Events>
</Control>
<Control id="buttonReset" width="80" type="Button" value="重置">
<Events>
<Event name="onClick">init();
dsCondition.setValue("i_chSettlementGroupID",'${Session.SETTLEMENTGROUPID}');
</Event>
</Events>
</Control>
</Controls>
<Properties/>
<Events>
<Event name="onLoad">init();
</Event>
<Event name="functions">function init(){
top.dsSysDate.flushData();
var sysDate = top.dsSysDate.getValue("sysDate");

// dsCondition.setValue("i_chStartDate",sysDate);
dsCondition.setValue("i_chStartDate","20120510");
dsCondition.setValue("i_chEndDate",sysDate);
}
</Event>
</Events>
</view>
具体的步骤,如红色代码注释。
2. ViewReport.jsp示例
主要的负责展现润乾的代码如下,步骤详见代码中的注释:
<%@page import="com.bstek.dorado.common.cache.CacheManager"%>
<%@ page contentType="text/html; charset=GBK" %>
<%@ taglib uri="http://www.bstek.com/dorado" prefix="d" %>
<%@taglib uri="/WEB-INF/runqianReport4.tld" prefix="report" %>
<html>
<head>
<title></title>
</head>
<body>
<d:View config="com.report.viewmodel.viewReport">
<d:SubWindow id="subwindowConfirm">
<table width="100%" height="100%">
<tr heigth = "80%">
<td align="center">没有查询到符合条件的记录!</td>
</tr>
<tr>
<td align="center"><d:Button id="btnEnsure" /></td>
</tr>
</table>
</d:SubWindow>
<center>
<%
// 1、处理由xxxQueryView.xml的buttonSearch按钮传过来的参数
request.setCharacterEncoding("GBK");
String paramStr = ReportUtil.getInstance().generateRequestParameters(request);
String reportFileName = ReportUtil.getInstance().getReportFileName(request);
request.setAttribute("i_chReportName",ReportUtil.getInstance().getRaqName(request));
String saveAsName =null;
if(ParamsPool.get(reportFileName)==null){
saveAsName =new String(request.getParameter("saveAsName").getBytes("Iso-8859-1"), "GBK");
Hashtable<String,String> params = new Hashtable<String,String>(1);
params.put("saveAsName", saveAsName);
ParamsPool.put(reportFileName, params);
}else{
saveAsName=(String)ParamsPool.get(reportFileName).get("saveAsName");
}
%>
// 2、负责调用润乾的Tag,展现HTML报表
<report:html name="report1"
scale="1.4"
reportFileName="<%=reportFileName%>"
funcBarLocation="top" needPageMark="yes" functionBarColor="#fff5ee" funcBarFontSize="9pt" funcBarFontColor="blue" separator=" " needSaveAsExcel="yes" needSaveAsPdf="yes" needPrint="yes" pageMarkLabel="页号{currpage}/{totalPage}" printLabel="打印" displayNoLinkPageMark="yes"
calculateListener="com.sfit.report.common.util.CalculateListener"
params="<%=paramStr%>"
saveAsName="<%=saveAsName%>"
useCache="no"
width="-1"
exceptionPage="/framework/report/errorPage.jsp"/>
</center>
<div id=pop style="position:absolute;width:100;height:50;z-index:99;display:none">
<table border=0 bgcolor=#E5E5E5><tr><td><span id="buttonTitle"></span></td></tr></table>
</div>
</d:View>
<%
if("true".endsWith(String.valueOf(request.getAttribute("showNoDataWindow")))) {
%>
<script language="JavaScript">
var sw =getViewModel().getControl("subwindowConfirm");
sw.show(true, true);
sw.style.top = "20px";
</script>
<%
}
%>
<script language="javascript">
//隐藏"正在加载"的提示
try {
parent.hideLoadingTip();
} catch(e){}
</script>
</body>
</html>
3. viewRadReport.jsp负责引用xxxQueryView.xml,并设置显示最后html润乾报表结果的iframe。
<%@ page contentType="text/html; charset=GBK"%>
<%@ taglib uri="http://www.bstek.com/dorado" prefix="d"%>
<html>
<head>
<title></title>
<meta http-equiv="content-type" content="text/html; charset=GBK" />
</head>
<body>
<d:View config="XXXX" />
<%
String xmlName=new String(request.getParameter("xmlfile").getBytes("Iso-8859-1"), "GB2312");
String reportFileName=xmlName.split("\\.")[1];
String reportStatus=ReportInfo.getReportStatus(xmlName);
String xmlConfigName=ReportInfo.getXmlConfigName(xmlName);
//设置默认显示报表收藏按钮,当参数showFavorite="1"时不显示
String showFavorite=request.getParameter("showFavorite");
if(showFavorite==null||showFavorite==""){
showFavorite="0";
}else{
if(!showFavorite.equals("1")){
showFavorite="0";
}
}
if(reportStatus!=null && reportStatus.trim().equals("0")){
%>
<script language="javascript">
xmlName='<%=xmlName%>';
reportFileName='<%=reportFileName%>';
</script>
<%if(showFavorite.equals("0")){ %>
//
<iframe scrolling="no" src="../../report/workspace/operateReport.jsp?reportFileName=<%=reportFileName %>" id="opeReportFrame" name="opeReportFrame"
frameborder="0" style="width: 100%; height: 18px; overflow: hidden;"></iframe>
<%} %>
// 动态显示查询条件view 如"xxxQueryView.xml" 的部分
<d:View config='<%=xmlConfigName %>'>
<script language="javascript">
hideLoadingTip();
</script>
<d:Layout type="border">
<d:AutoForm id="formCondition" />
<table width="100%">
<tr>
<td width="20%">
</td>
<td width="20%">
</td>
</tr>
</table>
<d:Pane position="center" width="100%">
<script language="javascript">
function OnSrcChanged () {
if ("propertyName" in event && event["propertyName"] == "src") { // Internet Explorer
if(event.srcElement.src != "" && event.srcElement.src.indexOf("viewExtReport") == -1){
try {
showLoadingTip();
} catch(e){}
}
}
}
</script>
// 动态展现润乾报表的HMTL的iframe(src为显示viewReport.jsp)
<iframe src="" id="reportframe" name="reportframe" frameborder="0"
style="width: 100%; height: 600px; overflow: hidden;" onpropertychange=OnSrcChanged() ></iframe>
</d:Pane>
</d:Layout>
</d:View>
<%}else if(reportStatus!=null && reportStatus.trim().equals("1")){
out.println("<table border=0 cellpadding=0 cellspacing=0 width=100% height=400 ><tr><td align=center valign=center><img src=../../images/lock.gif width=50 height=50 border=0/><font size=5 > <strong>该报表已被冻结</strong></font></td></tr></table>");
}else if(reportStatus!=null && reportStatus.trim().equals("2")){
out.println("<table border=0 cellpadding=0 cellspacing=0 width=100% height=400 ><tr><td align=center valign=center><img src=../../images/delete.gif width=50 height=50 border=0/><font size=5 > <strong>该报表已被删除</strong></font></td></tr></table>");
}
else if(reportStatus!=null && reportStatus.trim().equals("3")){
out.println("<table border=0 cellpadding=0 cellspacing=0 width=100% height=400 ><tr><td align=center valign=center><img src=../../images/maintenance.gif width=50 height=50 border=0/><font size=5 > <strong>该报表正在维护中。。。</strong></font></td></tr></table>");
}
else{
out.println("<table border=0 cellpadding=0 cellspacing=0 width=100% height=400 ><tr><td align=center valign=center><img src=../../images/exception.gif width=50 height=48 border=0/><font size=5 > <strong>该报表状态异常</strong></font></td></tr></table>");
}
%>
</body>
</html>
页面演示图:

注:此方案部分示例代码,包含具体项目的其他业务要求,请参考具体关于润乾与Dorado结合部分。