FineReport报表软件API源代码之程序数据集自定义函数和导出API.docx
《FineReport报表软件API源代码之程序数据集自定义函数和导出API.docx》由会员分享,可在线阅读,更多相关《FineReport报表软件API源代码之程序数据集自定义函数和导出API.docx(30页珍藏版)》请在冰点文库上搜索。
![FineReport报表软件API源代码之程序数据集自定义函数和导出API.docx](https://file1.bingdoc.com/fileroot1/2023-6/5/60270d0f-2650-4097-b5db-6d3ed26b4978/60270d0f-2650-4097-b5db-6d3ed26b49781.gif)
FineReport报表软件API源代码之程序数据集自定义函数和导出API
概述
随着FineReport的发展,它提供的设计器和服务器应该能够满足您绝大部分的需求,完全实现零编码的软件开发,革命性地加快软件开发速度,提高软件稳定性。
但是需求是千变万化的,而FineReport所包含的功能是报表行业中比较普遍的、典型的,也许某些个性化的功能通过FineReport软件无法实现。
因此FineReport开放了能够进行二次开发的接口,来更好的满足您软件产品或项目中的个性化的需求。
您可以根据该引擎API文档学习各类接口的使用方法,另外若您是一名程序员,且对FineReport报表深感兴趣,希望更深入地了解FineReport软件的内部原理,您也可以阅读该章节。
FineReport引擎API文档对如何定义类、编译类文件及JAVA开发平台使用等JAVA基础知识未作介绍,因此在您查看引擎API文档前请确保您有一定的JAVA基础。
目录
1.程序数据源
2.1简单程序数据集
2.2带参程序数据集
2.自定义函数
1
2
3
3.1自定义函数
3.2SubSection函数-Oracle查询参数个数限制
3.3自定义函数生产UPC条形码
3.导出api
注:
另有报表调用的相关代码,如有需要可以另行下载。
程序数据集
简单程序数据集
FineReport报表的数据来源可以是数据库数据或是文本数据,并且还可以是其它任何类型的数据,因为FineReport是通过TableData接口来读取数据源的,而上述所有的数据来源都实现了该接口,因此用户只要实现了TableData接口,也就可以用自定义类型的数据源了(程序数据集),FineReport报表引擎就能够读取定义的数据源作为报表数据源使用。
TableData接口主要有5个方法,如下:
//获取TableData的总列数
public int getColumnCount();
//获取TableData中第columnIndex列的列名
public String getColumnName(int columnIndex);
//判断是否存在第rowIndex行,这主要是用于处理超大数据时,完全遍历所有数据获取总行数相当困难,用这个方法来判断第rowIndex行是否存在,存在则可读取
public boolean hasRow(int rowIndex);
//获取TableData的总行数
public int getRowCount();
//获取TableData中第columnIndex列,第rowIndex行的数据
public Object getValueAt(int rowIndex, int columnIndex);
使用程序数据集分为如下三个步骤:
在某些应用场景中,需要在程序中对数据进行处理后再作为报表的数据源使用,以下例子即为一个简单的不带参程序数据集ArrayTableData的使用过程,并以此简要说明程序数据集的使用方法。
1.1. 定义程序数据源
由之前的概述可知,程序数据集需要实现TableData接口,可以直接继承该接口,实现其5个方法,也可以从AbstractTableData扩展,因为AbstractTableData已经实现了默
认的hasRow(introwIndex)方法。
该例中的程序数据集ArrayTableData就是直接从AbstractTableData扩展的,完整代码如下:
packagecom.fr.data;
importcom.fr.data.AbstractTableData;
publicclassArrayTableDataDemoextendsAbstractTableData{
//定义程序数据集的列名与数据保存位置
privateString[]columnNames;
privateObject[][]rowData;
//实现构建函数,在构建函数中准备数据
publicArrayTableDataDemo(){
String[]columnNames={"Name","Score"};
Object[][]datas={{"Alex",newInteger(15)},{"Helly",newInteger(22)},{"Bobby",newInteger(99)}};
this.columnNames=columnNames;
this.rowData=datas;
}
//实现TableData的其他四个方法,因为AbstractTableData已经实现了hasRow方法
publicintgetColumnCount(){
returncolumnNames.length;
}
publicStringgetColumnName(intcolumnIndex){
returncolumnNames[columnIndex];
}
publicintgetRowCount(){
returnrowData.length;
}
publicObjectgetValueAt(introwIndex,intcolumnIndex){
returnrowData[rowIndex][columnIndex];
}
}
1.1 把上面代码复制到txt文档重命名为ArrayTableDataDemo.java
放到报表环境/WebReport/WEB-INF/classes/com/fr/data这个目录下
1.2 编译ArrayTableData.java生成ArrayTableData.class类
将生成的类文件拷贝到报表工程/WEB-INF/classes目录下。
由于该类是在com.fr.data包中的,因此最终应该将该ArrayTableData.class放在/WEB-INF/classes/com/fr/data下面。
此时该程序数据源便定义好了。
2. 配置程序数据源
2.1 新建报表
在报表数据集中新建程序数据源,选择我们定义好的程序数据集,如下图
名字可以自定义,如student
2.3. 使用程序数据集
配置好程序数据源后便可以使用定义的student程序数据集了,与其他类型的数据集使用方法是相同的,可以通过拖拽方法实现单元格数据列绑定。
如下图
带参程序数据集
在实际应用中,可能需要根据表名动态地改变数据源,比如在程序数据集中,通过传进的表名参数,到数据库取出对应的表作为数据源。
因为FineReport是通过TableData接口来读取数据源的,而上述所有的数据来源都实现了该接口,因此用户只要实现了TableData接口,也就可以用自定义类型的数据源了(程序数据集),FineReport报表引擎就能够读取定义的数据源作为报表数据源使用。
以下就对这种情况举例说明。
TableData接口主要有5个方法,如下:
//获取TableData的总列数
public int getColumnCount();
//获取TableData中第columnIndex列的列名
public String getColumnName(int columnIndex);
//判断是否存在第rowIndex行,这主要是用于处理超大数据时,完全遍历所有数据获取总行数相当困难,用这个方法来判断第rowIndex行是否存在,存在则可读取
public boolean hasRow(int rowIndex);
//获取TableData的总行数
public int getRowCount();
//获取TableData中第columnIndex列,第rowIndex行的数据
public Object getValueAt(int rowIndex, int columnIndex);
使用程序数据集分为如下三个步骤:
►定义程序数据源
►配置程序数据源
►使用程序数据集
3.1.定义程序数据源
首先在构建函数中定义好所用的程序数据集表结构,通过参数获得表名;其次在初始化函数中准备数据并放入定义的表中;完整代码如下:
packagecom.fr.data;
importjava.sql.Connection;
importjava.sql.DriverManager;
importjava.sql.ResultSet;
importjava.sql.ResultSetMetaData;
importjava.sql.Statement;
importjava.util.ArrayList;
importjava.util.logging.Level;
importcom.fr.base.FRContext;
importcom.fr.data.AbstractTableData;
importcom.fr.report.parameter.Parameter;
publicclassParamTableDataDemoextendsAbstractTableData{
//列名数组,保存程序数据集所有列名
privateString[]columnNames=null;
//定义程序数据集的列数量
privateintcolumnNum=10;
//保存查询表的实际列数量
privateintcolNum=0;
//保存查询得到列值
privateArrayListvalueList=null;
//构造函数,定义表结构,该表有10个数据列,列名为column#0,column#1,。
。
。
。
。
。
column#9
publicParamTableDataDemo(){
//定义tableName参数
this.parameters=newParameter[]{newParameter("tableName")};
//定义程序数据集列名
columnNames=newString[columnNum];
for(inti=0;i columnNames[i]="column#"+String.valueOf(i);
}
}
//实现其他四个方法
publicintgetColumnCount(){
returncolumnNum;
}
publicStringgetColumnName(intcolumnIndex){
returncolumnNames[columnIndex];
}
publicintgetRowCount(){
init();
returnvalueList.size();
}
publicObjectgetValueAt(introwIndex,intcolumnIndex){
init();
if(columnIndex>=colNum){
returnnull;
}
return((Object[])valueList.get(rowIndex))[columnIndex];
}
//准备数据
publicvoidinit(){
//确保只被执行一次
if(valueList!
=null){
return;
}
//保存得到的数据库表名
StringtableName=parameters[0].getValue().toString();
//构造SQL语句,并打印出来
Stringsql="select*from"+tableName+";";
FRContext.getLogger().log(Level.INFO,
"QuerySQLofParamTableDataDemo:
\n"+sql);
//保存得到的结果集
valueList=newArrayList();
//下面开始建立数据库连接,按照刚才的SQL语句进行查询
Connectionconn=this.getConnection();
try{
Statementstmt=conn.createStatement();
ResultSetrs=stmt.executeQuery(sql);
//获得记录的详细信息,然后获得总列数
ResultSetMetaDatarsmd=rs.getMetaData();
colNum=rsmd.getColumnCount();
//用对象保存数据
Object[]objArray=null;
while(rs.next()){
objArray=newObject[colNum];
for(inti=0;i objArray[i]=rs.getObject(i+1);
}
//在valueList中加入这一行数据
valueList.add(objArray);
}
//释放数据库资源
rs.close();
stmt.close();
conn.close();
//打印一共取到的数据行数量
FRContext.getLogger().log(
Level.INFO,
"QuerySQLofParamTableDataDemo:
\n"+valueList.size()
+"rowsselected");
}catch(Exceptione){
e.printStackTrace();
}
}
//获取数据库连接driverName和url可以换成您需要的
publicConnectiongetConnection(){
StringdriverName="sun.jdbc.odbc.JdbcOdbcDriver";
Stringurl="jdbc:
odbc:
Driver={MicrosoftAccessDriver(*.mdb)};DBQ=C:
\\FineReport6.5\\WebReport\\FRDemo.mdb";
Stringusername="";
Stringpassword="";
Connectioncon=null;
try{
Class.forName(driverName);
con=DriverManager.getConnection(url,username,password);
}catch(Exceptione){
e.printStackTrace();
returnnull;
}
returncon;
}
//释放一些资源,因为可能会有重复调用,所以需释放valueList,将上次查询的结果释放掉
publicvoidrelease()throwsException{
super.release();
this.valueList=null;
}
}
4.1.1 把上面代码复制到txt文档重命名为ParamTableDataDemo.java
放到报表工程\WebReport\WEB-INF\classes\com\demo这个目录下
5.1.2 编译ParamTableDataDemo.java
将生成的ParamTableDataDemo.class类文件拷贝到报表工程/WEB-INF/classes目录下。
由于该类是在com.fr.data包中的,因此最终应该将该类放在/WEB-INF/classes/com/fr/data下面。
此时该程序数据源便定义好了。
6.2.配置程序数据源
新建报表
在报表数据集中新建程序数据源,选择我们定义好的程序数据集,如下图
名字可以自定义,如divtable
7.3.使用程序数据集
配置好程序数据源后便可以使用定义的divtable程序数据集了,选中该数据集点击预览按钮,即可以输入表名动态地获取相应的数据表,并制作模板,如下图
可以看到,我们已经将stscore表中的数据提取至程序数据集表中,像其他类型的数据集一样,可以通过拖拽方法实现单元格数据列绑定。
自定义函数
8.函数定义规则
FineReport已经提供了大量的自带函数,在正常情况下足够满足用户的报表制作需求,但是在一些特殊领域,可能需要一些特殊的函数,在这种情况下,FineReport提供了自定义函数机制,可以由用户根据业务需要自己来定义一些函数,但这些函数必须满足FineReport函数定义规则。
FineReport函数定义规则:
Functionname(Para,Para,...),其中Functionname为函数名,Para为参数。
9.函数原理
在FineReport中,每一个函数都被定义成一个类,这个类必须要实现Function这个接口,在运算的时候首先通过函数名反射取得这个类,然后调用它的run(Object[]agrs)方法。
下面以SUM这个函数为例。
packagecom.fr.report.script;
importcom.fr.report.script.core.FArray;
importcom.fr.report.script.core.FunctionHelper;
publicclassSUMextendsNormalFunction{
publicObjectrun(Object[]args){
doubleresult=0;
for(inti=0;i if(args[i]==null){
continue;
}
result+=parseObject(args[i]);
}
returnFunctionHelper.parsePrimitiveDouble(result);
}
privated