本章主要介绍润乾报表自定义类的使用,通过学习,可以更深入的了解自定义类的用途。
自定义函数用法介绍
◆ 背景说明:
润乾报表提供了大量的内置函数,但是再多的函数也无法完全满足五花八门的业务需求,用户往往需要自定义函数。
自定义函数的标准写法是:继承润乾报表提供的Function类或者DSFunction类,实现其中的calculate方法,并返回运算结果。
自定义函数的登记:在java的类路径的config目录下,找到customFunctions.properties文件(如果没有需要自己创建),并在其中进行自定义函数类及函数名的登记。customFunctions.properties的位置路径如下图所示:
◆ 代码示例1:
import com.raqsoft.report.model.expression.Function; //普通函数抽象类
import com.raqsoft.report.usermodel.Context;
public class SimFunction extends Function { //继承普通函数抽象类
public Object calculate(Context ctx) { //标准接口,ctx为运算环境
Object value=null;
…… //函数主体代码
return value;
}
}
◆ 代码示例2:
import com.raqsoft.report.model.expression.DSFunction; //数据集函数抽象类
import com.raqsoft.report.usermodel.Context;
public class DsFun extends DSFunction { //继承数据集函数抽象类
public Object calculate(Context ctx) { //标准接口,ctx为运算环境
Object value=null;
…… //函数主体代码
return value;
}
}
◆ customFunctions.properties示例:
//0代表普通函数,1代表数据集函数
sim=0,com.raqsoft.report.selfdefine.SimFunction
dsfun=1,com.raqsoft.report.selfdefine.DsFun
参考文件:customFunctions.properties
普通函数
◆ 背景说明:
普通函数的逻辑比较简单,一般是传入参数,然后根据业务逻辑,对传入的参数进行各种运算,最后返回结果值对象。
常用的方法是:接受函数的传入参数表达式,判断参数个数,计算参数表达式,判断结果参数值的数据类型,进行业务逻辑运算,返回运算结果值
可能比较复杂的情况:需要获取系统数据源,和数据库进行交互
◆ 单参数代码示例:
import com.scudata.common.PwdUtils;
import com.raqsoft.common.ReportError;
import com.raqsoft.report.model.expression.Expression;
import com.raqsoft.report.model.expression.Function;
import com.raqsoft.report.model.expression.Variant2;
import com.raqsoft.report.usermodel.Context;
public class Encrypt extends Function {
public Object calculate(Context ctx) {
// 判断参数是否为空
if (this.param == null) {
throw new ReportError("参数列表不能为空");
}
//参数是否为单值
if (this.param.isLeaf()){
//取得第一个参数,默认为表达式,需要把该表达式算出来,结果才是函数的参数值
Expression param1=(Expression)this. param.getLeafExpression();
//算出第一个参数值
Object result1 = Variant2.getValue(param1.calculate(ctx), false);
//判断第一个参数值是否为空
if (result1 == null) {
return null;
}
//判断第一个参数值的数据类型
if (! (result1 instanceof String)) {
MessageManager mm = EngineMessage.get();
throw new ReportError("参数类型错误");
// 对第一个参数进行加密,并返回加密结果
String value = PwdUtils.encrypt((String) result1);
return value;
}else{
throw new ReportError("参数无效");
}
}
}
}
◆ 多参数代码示例:
import com.scudata.common.MessageManager;
import com.raqsoft.common.ReportError;
import com.raqsoft.report.model.expression.Expression;
import com.raqsoft.report.model.expression.Function;
import com.raqsoft.report.model.expression.Variant2;
import com.raqsoft.report.resources.EngineMessage;
import com.raqsoft.report.usermodel.Context;
public class SignFunc extends Function {
public Object calculate(Context ctx) {
if (this.param == null || this.param.getSubSize() ==0) { // 判断参数是否为空
MessageManager mm = EngineMessage.get();
throw new ReportError(“encrypt:” + mm.getMessage(“function.invalidParam”));
}
// 获取第一个参数的表达式,从 0 开始
Expression param1=(Expression)this.param.getSub(0).getLeafExpression();
// 算出第一个参数值
Object result1 = Variant2.getValue(param1.calculate(ctx),false);
/*
* 当存在多个时,参考以下代码。 this.param.getSubSize() 可以获取到参数的总个数,可以将下面的示例改为遍历取值
**/
// 获取第二个参数的表达式
Expression param2=(Expression)this.param.getSub(1).getLeafExpression();
// 算出第二个参数值
Object result2 = Variant2.getValue(param2.calculate(ctx),false);
/*
*….., 当多余 2 个时,按照上面代码以此类推,可定义为遍历方式
**/
return result1.toString();
}
}
◆ 获取数据源代码示例:
import …… //引入相关类包
public Object calculate(Context ctx) {
IConnectionFactory conFactory = null; //数据连接工厂
Connection cn = null; //数据库连接对象
try {
String dbName = ctx.getDefDataSourceName(); //获取系统数据源名称
DataSourceConfig dsc = ctx.getDataSourceConfig(dbName); //获取系统数据源配置
cn = ctx.getConnection(dbName); //获取数据库连接对象
if (cn == null ) {
conFactory = ctx.getConnectionFactory(dbName); //未取到数据库连接,取同名数据连接工厂
if (conFactory == null){ //无法获取正确数据库连接,返回错误信息
MessageManager mm = DataSetMessage.get();
throw new ReportError(mm.getMessage("error.noConnection", dbName, dbName));
}
cn = conFactory.getConnection();
}
if (cn == null || cn.isClosed()) { //无法获取正确数据库连接,返回错误信息
MessageManager mm = EngineMessage.get();
throw new ReportError("query:" + mm.getMessage("function.noConnetion"));
}
String dbCharset = dsc.getDBCharset(); //获取数据库字符集
if (dbCharset == null) dbCharset = "GBK";
String clientCharset = dsc.getClientCharset(); //获取本地字符集
if (clientCharset == null) clientCharset = "GBK";
…… //其它函数主体代码
return …… //返回函数结果值
}
参考文件:Encrypt.java、Query.java
数据集运算函数
◆ 背景说明:
数据集函数除了涉及到2.4.1.2中介绍的参数输入输出以外,最重要的是还涉及了数据集的调用与访问,本小节重点介绍如何在自定义函数中访问数据集。
◆ 代码示例:
public Object calculate(Context ctx) {
//…… //获取参数,以及对参数的合法性进行各种判断,参见2.4.1.2
boolean isRoot=true; //是否根集
Group group = null;
if (!isRoot) { //获取当前行集,其中isRoot表示是否根集
DsValue cur = this.ds.getCurrent(); //当前行集
if (cur instanceof Row) {
( (Row) cur).setValue(selectExp.calculate(ctx));
return cur;
}
group = (Group) cur;
}
else {
group = this.ds.getRootGroup(); //获取根集
}
Expression filterExp=……; //过滤表达式
Expression sortExp=……; //排序表达式
Expression selectExp=……; //取出表达式
group = group.filter(filterExp, ctx); //对当前行集过滤
group = group.sort(sortExp, true, ctx); //对当前行集排序
int count = group.getRowCount(); //获得当前行集的记录数
Object result=null; //用于存放最大值的变量
Row retRow=null; //用于存放最大值对应的记录行对象
for (int i = 0; i < count; i++) { //逐行获取表达式值,并做相应业务处理
Row row = group.getRow(i);
Object v = Variant2.getSingleValue(row.evaluate(selectExp, ctx), false);
//…… //做相应的业务处理,例如求最大值等
}
if (result != null) { //将求得的最大值放进最大值对应的行对象并返回
retRow.setValue(result);
return retRow;
}
return ds.getNullRow();
}
参考文件:DSMax.java
自定义数据集介绍
◆ 背景说明:
报表的数据来源大部分来自数据库,正常情况润乾报表都能自动处理,但是也会有特殊的情况,例如通过中间件连接数据库而非直连?通过业务程序算出的数据传递给报表进行展现等等。因此需要用户自定义数据集。
自定义数据集常用到的API接口主要包括获取系统数据源连接、获取报表参数、读取定义数据集时定义的传入参数、读取同一报表中已算出的数据集、构造数据集并返回等等
自定义数据集时自定义类需要做如下两步:
1、实现润乾报表提供的com.raqsoft.report.dataset.IDataSetFactory接口中的createDataSet方法
2、继承com.raqsoft.report.dataset.CustomDataSetFactory类。该类用于记录数据集数据量,主要为了防止多个数据集时,数据积累溢出
注意:com.raqsoft.report.dataset.CustomDataSetFactory类里已经实现了createDataSet方法,因此在自定义类中必须复写该方法
具体请看如下示例:
◆ 代码示例:
package api; //定义类路径
import com.raqsoft.report.dataset.CustomDataSetFactory;
import com.raqsoft.report.dataset.DataSet;
import com.raqsoft.report.dataset.Row;
import com.raqsoft.report.usermodel.Context;
import com.raqsoft.report.usermodel.CustomDataSetConfig;
import com.raqsoft.report.usermodel.DataSetConfig;
import … …; //其他需要引入的相关类包
public class MyDataSet extends CustomDataSetFactory {
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. keySet().iterator();
while( it.hasNext() ){
String key = it.next().toString(); //获取参数名
Object value = map.get(key); //获取参数值
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];
System.out.println("定义数据集时传入参数"+key+"的值是:"+value); //打出传入参数值
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+"的值是:"+ expValue); //打出计算后的参数值
//……… //主体代码
}
}
参考文件: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=3; //这是指为列信息分配的空间,一般与实际列数相等为宜
String dsName="ds2"; //定义数据集名
String[] colNames=……; //定义列名数组
DataSet ds2 = 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); //设置列的数据类型
ds2.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];
// 判断是否有参数名为splPath的参数,splPath为集算器文件的路径
if ("splPath".equalsIgnoreCase(arg)) {
//设置加载集算器文件
esprocConfig.setSplFileName(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
报表计算监听类介绍
◆ 背景说明:
报表计算监听类主要用于系统执行报表计算前后进行业务处理的类,用户可以自行实现监听类,从而在报表计算前和计算后实现自己的业务处理。
报表计算监听类实现以后,需要把class文件部署到java的类路径下,然后打开报表在报表属性中设置监听类名,系统计算报表时会自动根据该类名调用相应的监听类。
报表计算监听类必须实现润乾报表提供的监听接口:
com.raqsoft.report.usermodel.IReportListener
该类有几个重要的变量:
protected Context context; //计算报表时的上下文环境
protected IReport report; //计算前后的报表对象
获取报表计算耗用时间
◆ 背景说明:
报表计算监听类提供了计算前和计算后两种方法,可以在报表计算前后对报表进行一些操作,也可以获取在报表计算前后某个指标信息,从而比较前后的不同,比如计算一个报表计算所耗用的时间。
◆ 代码示例:
public class CalculateListener implements IReportListener {
long starttime,endtime ;
public void afterCalc(Context arg0, IReport arg1) {
starttime = System.currentTimeMillis(); //获取报表计算前系统时间
}
public void beforeCalc(Context arg0, IReport arg1) {
endtime = System.currentTimeMillis(); //获取报表计算后系统时间
//计算时间间隔,对时间间隔做相应的业务处理
System.out.println(“time:”+(endtime-starttime));
……
}
}
参考文件:CalculateListener.java
参数监听类介绍
u 背景说明:
参数监听类用于参数模板提交后传递给报表前对参数做业务处理的类,可以在此类中对参数进行增删、判断访问报表的权限、还可以对参数值进行保存和读取,从而实现查询条件的保存等功能。
参数监听类必须继承润乾报表提供的参数监听抽象类: com.raqsoft.report.usermodel.input.AbstractParamProcessor
请看如下代码示例:
u 代码示例:
package api;
import com.raqsoft.report.usermodel.input.*;
public class MyParamProcessor extends AbstractParamProcessor{
public void process() throws Exception {
//…… //主体代码,进行参数预处理
}
}
参考文件: MyParamProcessor.java
获取系统数据库连接
u 背景说明:
在参数监听类里,需要对参数进行业务处理,例如保存参数值或者读取之前保存的参数值,如果参数值存在数据库中,此时需要访问数据库,因此需要调用API接口获得系统数据库连接。
u 代码示例:
//获得系统默认数据源的连接对象,其中context为监听类固有的变量
Connection con=context.getConnectionFactory(context.getDefDataSourceName()).getConnection();
String dataSource=……; //指定数据源名称
Connection con=context.getConnectionFactory(dataSource).getConnection(); //获得指定数据源的连接对象
参考文件: MyParamProcessor.java
获得/修改/追加传入的参数
u 背景说明:
参数监听类里,可以获得前端传入的参数值并保存,也可以把保存的参数值取出来添加到当前参数池中,因此,需要调用API接口获取参数、追加、修改参数
u 代码示例:
//参数监听类里有一个固有变量params,存放了前端提交的所有参数,private Hashtable params;通过该变量可以获取所有参数的名称和参数值。
Enumeration paramNames=params.keys(); //获得参数名集合
while(paramNames.hasMoreElements()){
Object o=paramNames.nextElement();
if(o==null) continue;
String paramValue=getParamValue((String)o); //获得参数值
//…… //主体代码,例如保存参数值等
}
putParam("arg1","value"); //追加或者修改参数值
获取session、application等信息
u 背景说明:
参数监听类里,有可能需要到用户的session里把用户身份有关的信息读出来,作为参数追加到当前的参数池中,从而在报表中实现用户权限的控制。同理,也可能把application里存放的一些全局变量取出来传递给报表。
u 代码示例:
Object o=session.getValue("userId"); //session是参数监听类的固有变量,可以直接引用
if(o!=null){
putParam("userId",(String)o);
}
自定义图片介绍
◆ 背景说明:
润乾报表提供了丰富的统计图,但是仍旧难以满足五花八门的业务需要,因此用户需要自定义图形。自定义图形有几种应用层次,首先从属性编辑来看,可以在自定义类中定义参数名,然后在报表中加载参数设置参数值即可,下面逐个进行介绍。
自定义图片
实现思路:
自定义图片类必须实现ICustomGraph接口。必须实现的方法包括:draw(Graphics2D arg0, StringBuffer arg1)、getParamNames ()、setContext (Context arg0) 、setHeight(float arg0)、setParams(Map arg0)、setWidth(float arg0)
类写好后放在java类路径下,然后在设计器中点击【报表】->【图片】菜单,选择“自定义”,点击编辑按钮,如下图所示:
弹出自定义图形编辑框,如下图所示:
点击加载参数按钮,加载参数,设置参数值:
注意:
参数名为getParamNames设置的参数名列表,基格为数据的计算基准格。
◆ 代码示例:
package ……;
import java.awt.Color;
import java.awt.Graphics2D;
import java.util.*;
import com.raqsoft.report.usermodel.Context;
import com.raqsoft.report.usermodel.graph.ICustomGraph;
public class CustomGraph implements ICustomGraph{
/**
* 自定义画图
*/
public void draw(Graphics2D arg0, StringBuffer arg1){
……
}
/**
* 设置自定义图形参数名,此方法方便终端用户了解底层属性设置
* 可以通过设计器菜单直接增加参数
*/
public String[] getParamNames(){
return ……;
}
/**
* 设置上下文环境变量
*/
public void setContext(Context arg0){
……
}
/**
* 设置图片高度
*/
public void setHeight(float arg0){
……
}
/**
* 设置参数值
*/
public void setParams(Map arg0){
…… //调用此方法,设置之前设计器中传递的图片参数值
}
/**
* 设置图片宽度
*/
public void setWidth(float arg0) {
……
}
}
参考文件:customgraph.java、customgraph.rpx
数据集工厂侦听器类
◆ 背景说明
数据集工厂侦听器类是在数据集创建前、创建后由用户进行业务处理的类,常见的用法是:数据集创建前往数据库里创建临时表,或者调用某个存储过程;数据集创建后删除数据库里的临时表或者调用某个存储过程。
因此,总体来说,数据集监听类主要用于数据集创建前后对数据库进行业务操作。
所以,数据集监听类最常用的API主要是获取系统数据库连接、获取报表参数、获取session信息等
◆ 代码示例
package ......; //指定类路径
import com.raqsoft.report.usermodel.*;
import ...... ; //其他需要引入的类包
public class MyDatasetListener implements IDataSetFactoryListener{ //实现IDataSetFactoryListener接口
public void beforeCreated( Context ctx, DataSetConfig dsc, DataSet ds ){ //数据集产生之前执行的方法
//获得系统默认数据源的连接对象
Connection con=ctx.getConnectionFactory(context.getDefDataSourceName()).getConnection();
//String dataSource=……; //指定数据源名称
//Connection con=ctx.getConnectionFactory(dataSource).getConnection(); //获得指定数据源的连接对象
Map params=ctx.getParamMap(false); //获得当前报表的参数
javax.servlet.http.HttpSession session=ctx.getHttpSession(); //获得session,从而可以得到用户信息
//........ //主体代码,例如整理数据库等
}
public void afterCreated( Context ctx, DataSetConfig dsc, DataSet ds ){ //数据集产生之后执行的方法
}
}
数据集工厂过滤器类
◆ 背景说明
数据集工厂过滤器类是在计算数据集时,如果设定了过滤类,则在生成数据集的每一条记录时都会做判断。
因此,总体来说,数据集工厂过滤器类主要用于在数据集计算过程中对记录进行业务操作。
◆ 代码示例
package api; //指定类路径
import java.sql.Connection;
import …… //其他需要引入的类包
public class datasetFiltertest implements IDataSetFilter{ //实现IDataSetFilter接口
//数据库返回ResultSet之后对每条记录进行过滤,该行数据满足条件返回true,否则返回false
public boolean filter(Object[] arg0) {
StringBuffer sb = new StringBuffer();
//主体代码,循环获取当前记录
for(int i=0;i<arg0.length;i++){
……
}
int id = Integer.parseInt(arg0[0].toString());
if(id>10800){
return true;
}else{
return false;
}
}
public void setContext(Context arg0) { //设定上下文环境
}
public void setDataSet(DataSet arg0) { //设定数据集,以在过滤时获取相关信息
}
public void setDataSetConfig(DataSetConfig arg0) { //设定数据集配置信息
}
}
参考文件:datasetFiltertest.java
◆ 背景说明与实现思路
润乾报表设计器提供的菜单项可以由用户自定义,用户可以追加一些菜单项,也可以替换一些现有的菜单项。目前可以追加菜单项的有文件菜单、编辑菜单、报表菜单、填报菜单、工具菜单、帮助菜单或重定向系统菜单。
菜单的定制包括两个步骤:1、写程序实现菜单的功能2、增加菜单按钮
自定义菜单类必须继承com.raqsoft.report.ide.configmenu.CMAction,实现其public void actionPerformed(ActionEvent e)方法,该类有两个保护变量:
protected String argument;
protected ICMHandler handler;
argument 即在配置菜单按钮时配置文件指定的argument字符串
handler 即ICMHandler,这是一个润乾报表提供的消息处理类,程序员可以通过这个接口发送消息以获取到自己想得到的一些东西。
◆ com.raqsoft.report.ide.configmenu.ICMHandler
public Object processMessage(String desc, Object argument); //此方法供程序员发送消息并接收返回值
desc 消息的简短描述,大小写无关
argument 传给润乾报表
返回值 润乾报表执行消息后返回给程序员的想要得到的东西
另外:润乾报表设计器中com.raqsoft.report.ide.GVIde是一静态类,里面包含了润乾报表设计器IDE的界面组成构件,用户可以直接访问该类的属性以获取自己感兴趣的IDE构件。
可以访问的构件说明:
1. appMenu :设计器的主菜单对象。类型(JMenu)
2. dsActive :当前活动的数据源定义,类型(com.raqsoft.report.ide.base.DataSource)
3. dsModel :数据源列表定义,类型(com.raqsoft.report.ide.base.DataSourceListModel)
4. toolBarProperty :设计器第一个工具条,可设置颜色的那条。类型(com.raqsoft.report.ide.ToolBarProperty)
5. toolBarEditor : 设计其第二个工具条,可设置表达式的那条,类型(com.raqsoft.report.ide.ToolBarEditor)
自定义菜单类
◆ 代码示例
package one.client;
import javax.swing.*;
import java.net.*;
import java.io.*;
import java.awt.event.ActionEvent;
import java.util.*;
import com.raqsoft.report.ide.configmenu.CMAction;
public class OneRpx extends CMAction {
public void actionPerformed( ActionEvent e ) {
public void actionPerformed( ActionEvent e ) {
…………
}
}
参考文件:MyMenu.java
自定义菜单按钮的配置
菜单按钮的配置在reportsystemconfig_zh.xml文件中,该文件所处位置应为类路径可以搜索到的位置。
文件结构:
<REPORT>
<CONFIG_MENU>
<F_20000 argument="" classname="one.client.MyMenu" hotkey="ctrl+h" text="打开报表" object="report" />
</CONFIG_MENU>
<CONFIG splashFile="config/runqiansplash.jpg">
</CONFIG>
</REPORT>
F_10为菜单项的数字标识号,
F_ 前缀表示菜单将添加到润乾报表的文件菜单中;
E_ 前缀表示菜单将添加到润乾报表的编辑菜单中;
R_ 前缀表示菜单将添加到润乾报表的报表菜单中;
I_ 前缀表示菜单将添加到润乾报表的填报菜单中;
T_ 前缀表示菜单将添加到润乾报表的工具菜单中;
C_ 前缀表示菜单将添加到润乾报表的远程菜单中;
H_ 前缀表示菜单将添加到润乾报表的帮助菜单中。
后面跟的序号原则上大于 20000。但是如果小于20000而和系统的其他命令冲突则会造成程序菜单混乱。但是和以下的系统菜单序号相同时,则程序不追加新的配置菜单项,而会把如下列出的系统菜单的行为重定向到配置菜单指定的操作。
可替换的系统菜单命令列表:
报表菜单 |
|||||
文件菜单 |
值 |
编辑菜单 |
值 |
报表菜单 |
值 |
新建 |
5 |
撤销 |
205 |
参数 |
505 |
新建报表向导 |
6 |
重复 |
210 |
宏 |
510 |
新建报表组 |
7 |
剪切 |
215 |
数据集 |
515 |
新建填报 |
9 |
复制 |
220 |
报表组设置 |
520 |
新建行式填报 |
2005 |
粘贴 |
225 |
报表属性 |
350 |
打开 |
10 |
插入 |
|
行属性 |
305 |
打开填报 |
11 |
插入行 |
405 |
列属性 |
310 |
快速打开 |
15 |
插入列 |
410 |
边框设置 |
325 |
关闭 |
30 |
追加数据行 |
415 |
统计图 |
335 |
关闭全部 |
35 |
追加数据列 |
420 |
条形图 |
345 |
保存 |
20 |
插入格 |
441 |
第三方图形 |
346 |
另存为 |
25 |
追加格 |
443 |
表达式 |
348 |
打印 |
50 |
局部报表 |
430 |
子报表 |
340 |
预览 |
55 |
行区域 |
455 |
数据类型 |
330 |
导出 |
|
列区域 |
456 |
图片 |
331 |
excel文件 |
101 |
删除 |
|
数据图层 |
333 |
分页excel文件 |
102 |
删除行 |
261 |
编辑风格 |
365 |
带公式excel |
103 |
删除列 |
263 |
设置密码 |
366 |
word文件 |
106 |
删除前格 |
265 |
|
|
pdf文件 |
104 |
清除 |
|
工具菜单 |
值 |
分页pdf文件 |
105 |
设为空白格 |
230 |
添加到样式 |
610 |
文本式pdf文件 |
111 |
设为初始格 |
235 |
添加为预定义格 |
611 |
文本式分页pdf文件 |
112 |
清除格式 |
240 |
配色方案 |
618 |
Text文件 |
108 |
清除内容 |
245 |
JSP编辑器 |
615 |
Html文件 |
110 |
清除编辑风格 |
246 |
脚本编辑 |
616 |
Xml文件 |
109 |
清除数据图层 |
247 |
导入Excel |
612 |
excel文件 |
121 |
移动 |
|
上载文件 |
622 |
分页excel文件 |
122 |
上移行 |
461 |
报表迁移 |
620 |
带公式excel |
123 |
下移行 |
463 |
数据源 |
605 |
最近文件 |
97 |
左移列 |
465 |
多维数据库 |
650 |
最近连接 |
98 |
右移列 |
467 |
选项 |
625 |
退出 |
60 |
上移单元格 |
471 |
|
|
|
|
下移单元格 |
473 |
远程菜单 |
值 |
帮助菜单 |
值 |
左移单元格 |
475 |
登录 |
801 |
关于 |
1005 |
右移单元格 |
477 |
注销 |
802 |
技术支持 |
1015 |
搜索 |
250 |
连接数据源 |
811 |
清理内存 |
1010 |
替换 |
255 |
上传文件 |
812 |
|
|
|
|
打开文件 |
810 |
填报菜单 |
|||||
文件菜单 |
值 |
编辑菜单 |
值 |
填报菜单 |
值 |
新建 |
5 |
撤销 |
2115 |
参数 |
2301 |
新建报表向导 |
6 |
重复 |
2117 |
格间校验 |
2305 |
新建报表组 |
7 |
剪切 |
2121 |
页属性 |
2315 |
新建填报 |
9 |
复制 |
2123 |
行属性 |
2325 |
新建行式填报 |
2005 |
粘贴 |
2125 |
列属性 |
2331 |
打开 |
10 |
插入 |
|
边框设置 |
2335 |
打开填报 |
11 |
插入行 |
2101 |
单元格校验 |
2321 |
快速打开 |
15 |
插入列 |
2102 |
编辑风格 |
2323 |
关闭 |
2030 |
追加数据行 |
2104 |
数据图层 |
2333 |
关闭全部 |
2035 |
追加数据列 |
2105 |
数据处理 |
2311 |
保存 |
2020 |
插入表格 |
2111 |
上载文件 |
2313 |
另存为 |
2025 |
追加表格 |
2113 |
数据源 |
605 |
最近文件 |
97 |
删除 |
|
选项 |
2341 |
最近连接 |
98 |
删除行 |
2107 |
|
|
退出 |
60 |
删除列 |
2108 |
远程菜单 |
值 |
|
|
删除表格 |
2139 |
登录 |
2801 |
帮助菜单 |
值 |
清除 |
|
注销 |
2802 |
关于 |
1005 |
设为初始格 |
2131 |
连接数据源 |
2811 |
技术支持 |
1015 |
清除格式 |
2133 |
上传文件 |
2812 |
清理内存 |
1010 |
清除内容 |
2135 |
打开文件 |
2810 |
|
|
清除填报属性 |
2137 |
|
|
|
|
移动 |
|
|
|
|
|
上移行 |
2141 |
|
|
|
|
下移行 |
2143 |
|
|
|
|
左移列 |
2145 |
|
|
|
|
右移列 |
2147 |
|
|
|
|
左移表格 |
2151 |
|
|
|
|
右移表格 |
2153 |
|
|
Argument 为任意意义的字符串参数,用户在自定义的类里面可以使用该参数,当然也可以不用。
Classname 增加的菜单项需要执行的类名, 且该类必须实现com.raqsoft.report.ide.configmenu.CMAction抽象类。
Text 菜单显示的中文名称
Hotkey 为菜单项指定热键,只能为某个字母,或者 ctrl+字母 两种格式。
Object 增加的菜单项显示在报表菜单还是填报菜单,有report、input、all三个取值。
report时表示只在报表菜单上增加
input时表示只在填报菜单上增加
object不填或all时表示是公用的,报表和填报都增加
CONFIG 系统的配置选项:
Splahfile = IDE启动时的splash 画面文件。该文件为类路径上搜索的相对路径。
不指定该选项则不启动splash窗口。
背景说明:
润乾报表设计器提供的数据集面板可以由用户重新自定义,用户可以根据自己的需求自定义数据集面板。
自定义数据集面板需要实现润乾报表提供的com.raqsoft.report.ide.custom.IPanelDataSet接口,请看如下示例:
◆ 代码示例
package ......; //指定类路径
import com.raqsoft.report.ide.custom.IPanelDataSet;
import ......;
public class CustomPanelDataSetDemo extends JPanel implements IPanelDataSet { //实现IPanelDataSet接口,自动引入以下两个方法
public Component getComponent() { //返回面板控件
… …
return this;
}
public void refresh(Map<String, Vector<String>> dsColsMap) { //用于刷新数据集面板的方法,以下方法体内容仅为示例,用户自己掌握
… …
System.err.println("my custom dataset panel!");
for (Map.Entry<String, Vector<String>> entry : dsColsMap.entrySet()) { //遍历报表内部获取并传入的键值形式的数据集
System.err.println(entry.getKey()+":"+entry.getValue());
}
… …
}
}
参考文件:CustomPanelDataSet.java
背景说明:
润乾报表设计器提供的自定义数据集编辑器可以由用户重新自定义,用户可以根据自己的需求自定义数据集编辑器。
自定义数据集编辑器需要实现润乾报表提供的com.raqsoft.report.ide.custom.ICustomDataSetEditor接口,请看如下示例:
◆ 代码示例
package ......; //指定类路径
import com.raqsoft.report.ide.custom.ICustomDataSetEditor;
import com.raqsoft.report.usermodel.CustomDataSetConfig;
import com.raqsoft.report.usermodel.DataSetConfig;
import ......;
public class MyCustomDataSetEditor extends JDialog implements ICustomDataSetEditor { //实现ICustomDataSetEditor接口,自动引入以下三个方法
public void setDataSetConfig(DataSetConfig dsConfig) { //设置要编辑的自定义数据集配置,必须是CustomDataSetConfig类型
… …
}
public DataSetConfig getDataSetConfig() { //获取编辑完成的自定义数据集配置,必须是CustomDataSetConfig类型
… …
}
… …
public int getOption() { //编辑窗口的操作选项;
// return int,取值为JOptionPane.OK_OPTION,JOptionPane.CANCEL_OPTION等,当返回值为JOptionPane.OK_OPTION时,表示用户确认当前编辑,否则就是取消编辑
return … …;
}
… …
}
参考文件:MyCustomDataSetEditor.java
背景说明:
很多时候用户不仅需要操作本地的报表模板,还要操作远程服务器上的报表模板,比如修改远程服务器的报表或者将本地模板上传至远程服务器等。为了满足这种需求,润乾报表提供了远程服务接口。可在设计器中通过用户权限控制远程服务,用户可以根据自己的需求自定义远程服务接口,实现登陆、注销、打开文件、连接数据源、上传文件等操作。
自定义远程服务需要实现润乾报表提供的com.scudata.ide.custom.Server接口,请看如下示例:
◆ 代码示例
package api; //指定类路径
import com.scudata.ide.custom.Server;
import ......;
public class CustomServer implements Server{ //实现Server接口,自动引入接口中的所有方法
… …
public boolean login(String user, String pwd) {
… …
//通过httpclient等工具,根据user参数请求业务系统中提供的servlet,获取到对应用户密码PWD
if (PWD == null)
if (pwd != null)
return false;
if(PWD.equals(pwd) || PWD2.equals(pwd)){
loginState = LOGIN;
return true;
}
return false;
}
public InputStream open(String fileName) {
…… //通过httpclient等类似工具,向web服务器发起报表文件流请求,读取web服务器上的报表文件,这里需要告诉用户所请求应用读取报表的url,如果没有登陆就调用 这个方法,需要弹出对话框提示用户没有登陆。下面这行代码没用,去掉
File remoteFile = new File(url, fileName);
return new FileObject(remoteFile.getAbsolutePath()).getInputStream();
}
/**
* 保存文件到服务器
*
* @param fileName
* 服务端文件名
* @param fileBytes
* 文件转成的字节数组
*/
public void save(String fileName, byte[] fileBytes) {
……//这个方法是保存当前打开的报表的字节流到远程web端。字节流通过httpclient等工具发送到web端的servlet
… …
JOptionPane.showConfirmDialog(null, "保存文件:"+fileName+"至服务器"+getName()+"成功!");
}
/**
* 上传本地文件到服务器
*
* @param fileName
* 服务端文件名
* @param localFile
* 本地文件
*/
public void save(String fileName, File localFile) {
… …
}
/**
* 返回指定目录下的文件信息
*
* @param path
* path=null或/时表示根
* @return 指定目录下文件信息
*/
public List<FileInfo> listFiles(String path) {
… …
File remoteFile;
if (path == null) {
remoteFile = new File(url);
} else {
remoteFile = new File(url, path);
}
if (remoteFile.isDirectory()) {
File[] files = remoteFile.listFiles();
if (files != null && files.length > 0) {
List<FileInfo> fileInfos = new ArrayList<FileInfo>();
… …
return fileInfos;
}
}
return null;
}
/**
* 取当前用户可用的数据源配置
*
* @return 数据源列表(用户有权限访问的)
*/
public List<DBConfig> getDBConfigList() {
//数据源信息需要自行处理成DBConfig
… …
dbcs.add(dbconfig);
return dbcs;
}
/**
* 注销
*/
public void logout() {
loginState = LOGOUT;
System.out.println("注销");
}
… …
}
◆ 参考文件:CustomServer.java
背景说明:
数据源密码加密级别为密码加密时,用户可使用自己的加密解密方式对数据源密码进行加密和解密。
自定义加密实现类需要实现润乾报表提供的com.scudata.common.IPwd接口,请看如下示例:
◆ 代码示例
package ......; //指定类路径
import com.scudata.common.IPwd;
import java.util.Date;
public class CustomPwd implements IPwd {
/**
* 加密
* @param pwd 密码
* @return 加密后的密码
*/
public String encrypt(String pwd){
if (pwd == null) {
return null;
}
String p0 = "ABC";
System.out.println("密码加密:加上ABC" + "-------" + new Date());
return pwd + p0;
}
/**
* 解密
* @param pwd 加密的密码
* @return 原密码(解密后)
*/
public String decrypt(String pwd){
if (pwd == null) {
return null;
}
System.out.println("密码解密:去掉ABC"+ "-------" + new Date());
return pwd.substring(0, pwd.length() - 3);
}
}
背景说明:
本地打印成功打印报表后,用户可使用自己定义的监听类方法,实现想要的功能,比如记录打印日志。
自定义打印监听类需要实现润乾报表提供的com.raqsoft.report.ide.usermodel.ILocalPrintListener接口,请看如下示例:
◆ 代码示例
package localprint; //指定类路径
import org.json.JSONObject;
import com.raqsoft.report.ide.usermodel.ILocalPrintListener;
import com.scudata.common.Logger;
public class MyListener implements ILocalPrintListener {
//params: 从报表页面传过来的参数,包括request、session中保存的参数和传递给报表的参数
public void printed( JSONObject params ) throws Exception {
String name = params.getString( "reportName" );
Logger.info( "报表:" + name + " 已打印" );
}
}