自定义数据集介绍
◆ 背景说明:
报表的数据来源大部分来自数据库,正常情况润乾报表都能自动处理,但是也会有特殊的情况,例如通过中间件连接数据库而非直连?通过业务程序算出的数据传递给报表进行展现等等。因此需要用户自定义数据集。
自定义数据集常用到的API接口主要包括获取系统数据源连接、获取报表参数、读取定义数据集时定义的传入参数、读取同一报表中已算出的数据集、构造数据集并返回等等
自定义数据集需要实现润乾报表提供的com.raqsoft.report.dataset.IDataSetFactory接口,请看如下示例:
◆ 代码示例:
package …; //定义类路径
import com.raqsoft.report.dataset.DataSet;
import com.raqsoft.report.dataset.IDataSetFactory;
import com.raqsoft.report.usermodel.Context;
import com.raqsoft.report.usermodel.DataSetConfig;
import ……; //其它需要引入的相关类包
public class MyDataSet implements IDataSetFactory {
public DataSet createDataSet(Context ctx, DataSetConfig dsc, boolean retrieve) {
//ctx为报表引擎环境,dsc为数据集定义类,reteieve是指是否检查出数据,如果为false,只返回数据集的结构
DataSet ds=null;
//…… //主体代码
return ds; //返回结果数据集
}
}
参考文件:MyDataSet.java
● 注意:要把写好的MyDataSet.java编译后的.class文件放到java类路径下,否则找不到这个类,会提示计算数据集失败。
在设计器中使用自定义类应把编译后的.class文件放在classes\自定义类所在的包名下面。比如MyDataSet.java在com.raqsoft包中,那么就应该把编译后的MyDataSet.class文件放在设计器安装路径\classes\com\raqsoft包中,如果classes下面不包含com.raqsoft包,用户需要自己新建。如下图所示:
在服务器中运行使用自定义类的报表文件时应把自定义类编译后的.class文件放在raqsoft\webapps\WEB-INF\classes\自定义类所在的包名下面。比如MyDataSet.java在com. raqsoft包中,那么就应该把编译后的MyDataSet.class文件放在设计器安装路径\raqsoft\report\web\webapps\WEB-INF\demo\classes下的 com\raqsoft包中,如果classes下面不包含com. raqsoft包,用户需要自己新建。如下图所示:
获取系统数据源连接
◆ 背景说明:
自定义数据集往往需要自行连接数据库获取数据,因此需要调用API获取系统数据源
◆ 代码示例:
String datasourceName = dsc.getDataSourceName(); //获取数据集定义里设置的数据源名称
if( datasourceName==null || "".equals(datasourceName) ) //如果数据集里没有指定数据源,则取系统默认
datasourceName = ctx.getDefDataSourceName(); //取系统默认数据源
Connection con;
try {
con = ctx.getConnectionFactory( datasourceName ).getConnection(); //获取数据库连接
System.out.println( "得到的数据源是:"+con ); //把数据库连接打出来看看是否正确
//……… //主体代码
con.close(); //最后所有任务完成,不要忘了关闭数据库连接
} catch (Exception ex) {
ex.printStackTrace();
}
参考文件:MyDataSet.java
获取报表参数
◆ 背景说明:
自定义数据集里,往往需要根据报表传入的参数来生成返回的数据集,因此需要调用API接口获取报表参数
◆ 代码示例:
Map map = ctx.getParamMap(false); //获得当前报表的所有参数对照表
if( map != null ){
Iterator it =map.entrySet().iterator();
while( it.hasNext() ){
String key = it.next().toString(); //获取参数名
String value = map.get(key).toString(); //获取参数值
System.out.println("报表传入的参数"+key+"的值是:"+value); //打出参数名和参数值
//…… //主体代码
}
}
参考文件:MyDataSet.java
读取定义数据集时定义的传入参数
◆ 背景说明:
定义数据集时,允许为自定义数据集单独传入一些参数,必须注意的是,此时传入的参数值都为字符型。如果有特殊需要,可以在获取参数值后自行进行数据类型的转换。如果传入的参数值需要是表达式,那么也以字符串的形式传进去,然后在自定义数据集里把字符串转换成表达式,再把表达式算出来。
如上图所示,假设我们定义数据集的时候定义了三个传入参数,这三个参数分别为整数、字符、表达式,可是我们在自定义数据集里接收到的都是字符串,请看如下代码,如何进行转换:
◆ 代码示例:
//读取定义数据集时定义的传入参数
CustomDataSetConfig cdsc = (CustomDataSetConfig)dsc; //把数据集定义类转成自定义数据集类
String[] args = cdsc.getArgNames(); //获取自定义数据集传入参数名的集合
String[] vals = cdsc.getArgValue(); //获取自定义数据集传入参数值的集合
int intValue=0;
Object expValue=null;
if( args != null ){
for( int i=0; i<args.length; i++ ){ //依次获取传入参数值
String key = args[i];
if(key==null) continue;
String value = vals[i];
if(key.equalsIgnoreCase("intValue")){ //把传入参数转成整型
intValue=Integer.parseInt(value);
}
else if(key.equalsIgnoreCase("expValue")){ //把传入参数解析成表达式并计算出表达式值
Expression exp=new Expression(ctx,value);
expValue=exp.calculate(ctx);
}
System.out.println("定义数据集时传入参数"+key+"的值是:"+value); //打出传入参数值
//……… //主体代码
}
}
参考文件:MyDataSet.java
读取同一报表中已算出的数据集
◆ 背景说明:
润乾报表支持多数据集,因此就出现了这样的需求:同一个报表中,某个数据集的生成依赖于另一个数据集的结果数据。
为了实现这种依赖关系,同时也为了避免循环引用等,润乾报表规定了数据集的运算顺序,严格按照定义时的顺序进行运算。即定义在前面的数据集先算,定义在后面的后算,后面的数据集可以引用前面的数据集。
于是,自定义数据集也必然出现了这样的需求:引用报表中已经算出的数据集的值。请看如下例子代码:
◆ 代码示例:
DataSet ds = ctx.getDataSet("ds1"); //根据数据集的名称获取已算出的数据集
if(ds==null) return null;
int colCount=ds.getColCount(); //获得数据集的行数列数
int rowCount=ds.getRowCount();
for(int i=1;i++;i<=rowCount){ //注意数据集的行号列号从1开始
for(int j=1;j++;j<=colCount){
Object value = ds.getData(i, j); //获取某行某列的数据值
System.out.print("第"+i+"行第"+j+"列的值为"); //逐个打出数据集的值
System.out.println(value);
//……. //主体代码
}
}
参考文件:MyDataSet.java
构造数据集
◆ 背景说明:
自定义数据集的最终目的是生成数据集并返回,因此必不可少的一步是构造数据集,请看如下例子代码:
◆ 代码示例:
//构造一个数据集
int rowCount=100;
int colCount=10; //这是指为列信息分配的空间,一般与实际列数相等为宜
String dsName="ds2"; //定义数据集名
String[] colNames=……; //定义列名数组
DataSet ds = new DataSet(rowCount, colCount, dsName); //构造数据集的时候最好直接指定差不多的行数列数,否则每次追加行、列的时候不停地分配空间影响性能
for (int i = 0; i < colCount; i++) { //添加列,注意:添加列要在添加行之前
ColInfoBase ci = new ColInfoBase(); //逐列构造列信息对象
ci.setColName(colNames[i]); //设置列英文名
ci.setColTitle(colNames[i]); //设置列中文名,这里省略,直接用英文名代替
ci.setDataType(com. raqsoft.report.usermodel.Types.DT_STRING); //设置列的数据类型
ds.addColInfo(ci);
仅用于数据集运算时不需要如此多的信息,可直接调用ds.addCol(colName)即可
}
//设置数据集中的数据
//添加行
for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
Row row = ds.addRow(); //添加行
Object[] rowData = ……; //主体代码,构造每一行的数据
for (int i = 0; i < colCount; i++) {
try {
row.setData(i + 1, rowData[i]); //逐行逐列设置数据集的数据
} catch (Exception e) {
throw new ReportError(e.getMessage(),e);
}
}
}
参考文件:MyDataSet.java
集算器文件数据转成DataSet
◆背景说明:
在自定义数据集时,有时候有些数据可能来自集算器文件某单元格,那我们就需要通过计算集算器文件读取数据,并转成润乾报表的数据集DataSet。
◆ 代码示例:
// 设置报表数据集中使用的数据源名称
ctx.setDefDataSourceName(dsc.getDataSourceName());
…
EsProcDataSetFactory esprocfactory = new EsProcDataSetFactory();
EsProcDataSetConfig esprocConfig = new EsProcDataSetConfig();
// 设置使用自定义数据集的数据集名称
esprocConfig.setName(dsc.getName()); //
CustomDataSetConfig customConfig = (CustomDataSetConfig) dsc;
// 获取报表自定义数据集窗口中设置的参数名称和参数值
String[] argname = customConfig.getArgNames();
String[] argvalue = customConfig.getArgValue();
if (argname != null && argvalue != null&& argname.length == argvalue.length) {
List<String> esprocNames = new ArrayList<String>();
List<String> esprocValues = new ArrayList<String>();
for (int i = 0; i < argname.length; i++) {
String arg = argname[i];
// 判断是否有参数名为dfxPath的参数,dfxPath为集算器文件的路径
if ("dfxPath".equalsIgnoreCase(arg)) {
// 设置加载集算器文件
esprocConfig.setDfxFileName(argvalue[i]);
} else {
esprocNames.add(argname[i]);
esprocValues.add(argvalue[i]);
}
}
// 设置集算器文件中参数名称和参数值
esprocConfig.setParamNames(esprocNames);
esprocConfig.setParamExps(esprocValues);
… …
}
// 计算集算器文件
DataSet dataset = esprocfactory.createDataSet(ctx, esprocConfig, true);
参考文件:MyDmDataSet.java