历史版本12 :自定义函数实现表间校验 返回文档
编辑时间:
内容长度:图片数:目录数:
修改原因:
1. 描述编辑
对于在填报提交时,编辑单元格的值需要与另一报表中某个参数或者某一单元格的值进行校验的需求,FineReport可以通过自定义函数来实现。
2. 原理编辑
在java实现的自定义函数中,读取报表,传入参数值并执行,从执行后的报表结果中取某个单元格值的并返回,在填报表中便可以使用返回的值进行数据校验了。
对模板reportcheck2.cpt中单元格D2输入的成绩进行校验,比较对象是reportcheck1.cpt中的值,如下图:
D2输入的值不能大于reportcheck1.cpt中的最大值,也不能小于reportcheck1.cpt中的最小值。
其中reportcheck1的最大值最小值是通过参数最终计算而来的。
该例子仅作为原理介绍,因此比较的对象直接引用参数的值,实际情况中可能是报表通过传入的参数,根据参数取得数据,执行报表后某些格子的值,与该例子是一样的。
其中reportcheck1的最大值最小值是通过参数最终计算而来的。
该例子仅作为原理介绍,因此比较的对象直接引用参数的值,实际情况中可能是报表通过传入的参数,根据参数取得数据,执行报表后某些格子的值,与该例子是一样的。
此时在reportcheck2.cpt中我们怎么获取另一模板的值呢?
可以通过自定义函数ReportCheck获取。
可以通过自定义函数ReportCheck获取。
ReportCheck函数:ReportCheck(para1,para2,para3,para4) ,获取报表中某一单元格的值
参数 | 说明 |
---|---|
para1 | 报表名称 |
para2 | 传递给报表的参数值列表,格式如"[{name:para1name,value:para1value},{name:para2name,value:para2value},......]" |
para3 | 获取单元格列号,从0开始 |
para4 | 获取单元格行号,从0开始 |
实例:
ReportCheck("reportcheck1.cpt","[{name:max,value:100},{name:min,value:0}]",1,0) :获取报表reportcheck1通过传入参数计算后的B1单元格的值
ReportCheck("reportcheck1.cpt","[]",0,0) :若没有参数,则第二个参数值设为"[]"获取报表reportcheck1的A1单元格的值
2. 步骤编辑
2.1 编写自定义函数
ReportCheck函数代码如下:
// 自定义函数实现表间校验
package com.fr.function;
import java.util.HashMap;
import com.fr.base.ResultFormula;
import com.fr.base.operator.common.CommonOperator;
import com.fr.chart.activator.ChartBaseActivator;
import com.fr.config.activator.BaseDBActivator;
import com.fr.config.activator.ConfigurationActivator;
import com.fr.data.impl.config.activator.RestrictionActivator;
import com.fr.env.operator.CommonOperatorImpl;
import com.fr.io.TemplateWorkBookIO;
import com.fr.json.JSONArray;
import com.fr.json.JSONObject;
import com.fr.main.impl.WorkBook;
import com.fr.main.workbook.ResultWorkBook;
import com.fr.module.Module;
import com.fr.module.tool.ActivatorToolBox;
import com.fr.report.ReportActivator;
import com.fr.report.cell.CellElement;
import com.fr.report.module.ReportBaseActivator;
import com.fr.report.report.ResultReport;
import com.fr.script.AbstractFunction;
import com.fr.stable.WriteActor;
import com.fr.store.StateServerActivator;
import com.fr.workspace.simple.SimpleWork;
import com.fr.write.cal.WB;
public class ReportCheck extends AbstractFunction {
private static HashMap wMap = new HashMap();
public Object run(Object[] args) {
// 获取公式中的参数
String cptname = args[0].toString(); // 获取报表名称
int colnumber = Integer.parseInt(args[2].toString()); // 所取单元格所在列
int rownumber = Integer.parseInt(args[3].toString()); // 所取单元格所在行
// 定义返回的值
Object returnValue = null;
// 定义报表运行环境,用于执行报表
Module module = ActivatorToolBox.simpleLink(new BaseDBActivator(),
new ConfigurationActivator(),
new StateServerActivator(),
new ReportBaseActivator(),
new RestrictionActivator(),
new ReportActivator(),
new ChartBaseActivator());
SimpleWork.supply(CommonOperator.class, new CommonOperatorImpl());
String envpath= "//Applications//FineReport10_325//webapps//webroot//WEB-INF"; //工程路径
SimpleWork.checkIn(envpath);
module.start();
try {
ResultWorkBook rworkbook = null;
// 读取模板
WorkBook workbook = (WorkBook)TemplateWorkBookIO
.readTemplateWorkBook(cptname);
// 获取需要传递给报表的参数名与参数值,格式如[{"name":para1name,"value":para1value},{"name":para2name,"value":para2value},......]
JSONArray parasArray = new JSONArray(args[1].toString());
// 需要判断是否是5秒内执行过的
// 取出保存的resultworkbook;
Object tempWObj = wMap.get(cptname + parasArray.toString());
if (tempWObj != null) {
// 取出hashmap里面保存的TpObj;
TpObj curTpObj = (TpObj) tempWObj;
if ((System.currentTimeMillis() - curTpObj.getExeTime()) < 8000) {
rworkbook = curTpObj.getRworkbook();
} else {
wMap.remove(cptname + parasArray.toString());
}
}
// 如果没有设置,需要生成
if (rworkbook == null) {
JSONObject jo = new JSONObject();
// 定义报表执行时使用的paraMap,保存参数名与值
java.util.Map parameterMap = new java.util.HashMap();
if (parasArray.length() > 0) {
for (int i = 0; i < parasArray.length(); i++) {
jo = parasArray.getJSONObject(i);
parameterMap.put(jo.get("name"), jo.get("value"));
}
}
// 执行报表
rworkbook = workbook.execute(parameterMap, new WriteActor());
// 保存下来
wMap.put(cptname + parasArray.toString(), new TpObj(rworkbook,
System.currentTimeMillis()));
}
// 获取报表结果中对应Cell的值
ResultReport report = rworkbook.getResultReport(0);
CellElement cellElement = ((WB) report).getCellElement(colnumber, rownumber);
returnValue = cellElement.getValue().toString();
if(cellElement.getValue() instanceof ResultFormula) {
returnValue = ((ResultFormula)cellElement.getValue()).getResult().toString();
}
} catch (Exception e) {
e.printStackTrace();
}
return returnValue;
}
class TpObj {
private ResultWorkBook rworkbook = null;
private long exeTime = System.currentTimeMillis();
public TpObj(ResultWorkBook rworkbook, long exeTime) {
this.setRworkbook(rworkbook);
this.setExeTime(exeTime);
}
public ResultWorkBook getRworkbook() {
return rworkbook;
}
public void setRworkbook(ResultWorkBook rworkbook) {
this.rworkbook = rworkbook;
}
public long getExeTime() {
return exeTime;
}
public void setExeTime(long exeTime) {
this.exeTime = exeTime;
}
}
}
2.2 编译自定义函数
编译ReportCheck.java,生成类ReportCheck.class、ReportCheck$TpObj.class,由于我们的类定义在包com.fr.function下,因此将最终生成的类文件拷贝至%FR_HOME%\webapps\webroot\WEB-INF\classes\com\fr\function文件夹下,没有这个路径的话可以手动创建。
2.3 注册自定义函数
启动设计器,选择服务器>函数管理器,增加一自定义函数,选择刚保存的类,如下图:
这样,这个自定义函数便注册好了,您可以在工程里的所有模板中使用这个自定义函数。
2.4 使用自定义函数
打开reportcheck2.cpt模板,点击模板>报表填报属性>数据校验,我们来设置校验公式。
reportcheck2.cpt设置的数据校验如下:
添加校验信息分别为:
D2 <= ReportCheck("reportcheck1.cpt","[{name:max,value:90},{name:min,value:0}]",1,0),校验出错信息:"成绩太高,超过最高分"
D2 >= ReportCheck("reportcheck1.cpt","[{name:max,value:90},{name:min,value:0}]",1,1),校验出错信息:"成绩太低,低于最低分"
校验公式说明:给reportcheck1传入两个参数,max值为90,min值为0,取执行后结果中第2列第1行和第2列第2行,即B1和B2单元格的值
保存,点击填报预览
3. 预览效果编辑
成绩输入100,点击数据校验,提示“成绩太高,超过最高分”
成绩输入-10,提示“成绩太低,低于最低分”
成绩输入80,校验成功
4. 已完成模板编辑
已完成模板,参见:%FR_HOME%\webapps\webroot\WEB-INF\reportlets\doc\SpecialSubject\function\reportcheck1.cpt,点击下载模板