1. 概述
1.1 预期效果
在填报提交时,编辑单元格的值需要与另一报表中某个参数或单元格的值进行对比校验,可以通过自定义函数来实现。
例如:对模板 reportcheck2.cpt 中单元格 D2 输入的成绩进行校验,比较对象是 reportcheck1.cpt 中的值。
D2 输入的值不能大于 reportcheck1.cpt 中的最大值,也不能小于 reportcheck1.cpt 中的最小值。如下图所示:
1.2 实现思路
在 Java 实现的自定义函数中,读取报表、传入参数值并执行。从执行后的报表结果中取某个单元格的值并返回,在填报表中便可以使用返回的值进行数据校验了。
1.3 函数简介
本方法通过自定义函数 ReportCheck 实现。
ReportCheck 函数:ReportCheck(para1,para2,para3,para4) ,获取报表中某一单元格的值
注:仅支持 Tomcat 服务器下使用。
参数 | 说明 |
---|---|
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','[ {name:max,value:"+$a+"} , {name:min,value:"+$b+"} ]',1,0) | 支持 value 动态变化 |
ReportCheck("reportcheck1.cpt","[]",0,0) | 若无参数,第二个参数值设为 "[]" 获取报表 reportcheck1 的 A1 单元格的值 |
2. 示例
注1:自定义函数 ReportCheck 仅支持在Tomcat 服务器下使用。
注2:该例子仅作为原理介绍,因此比较的对象直接引用参数的值。实际情况中可能是报表通过传入的参数,根据参数取得数据,执行报表后某些格子的值,与该例子是一样的。
2.1 编写自定义函数
编写ReportCheck.java, 函数代码如下:
package com.fr.function;
import com.fr.base.ResultFormula;
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.report.cell.CellElement;
import com.fr.report.report.ResultReport;
import com.fr.script.AbstractFunction;
import com.fr.stable.WriteActor;
import com.fr.write.cal.WB;
import java.util.HashMap;
import java.util.Map;
public class ReportCheck extends AbstractFunction {
private static final Map<String, TpObj> 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;
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());
// 需要判断是否是8秒内执行过的
TpObj tempWObj = wMap.get(cptname + parasArray);
if (tempWObj != null) {
if ((System.currentTimeMillis() - tempWObj.getExeTime()) < 8000) {
rworkbook = tempWObj.getRworkbook();
} else {
wMap.remove(cptname + parasArray);
}
}
// 如果没有设置,需要生成
if (rworkbook == null) {
JSONObject jo;
// 定义报表执行时使用的paraMap,保存参数名与值
Map parameterMap = new HashMap<>();
if (!parasArray.isEmpty()) {
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, 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;
}
static 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 编译自定义函数
2.2.1 生成 class 文件
编译 ReportCheck.java,生成类 ReportCheck.class、ReportCheck$TpObj.class。
注:编译时需导入 FineReport 工程 JAR 包,包括安装工程包%FR_HOME%/lib下面的所有的包,%FR_HOME%/server/lib下面的所有包,%FR_HOME%/webapps/webroot/WEB-INF/lib下面的所有包,还要引入 JDK 的tools.jar,详情请参见 编译Java程序
2.2.2 导入 class 文件
该类定义在包 com.fr.function 下,将生成的 class 类文件拷贝至%FR_HOME%\webapps\webroot\WEB-INF\classes\com\fr\function 文件夹下,如下图所示:
2.3 注册自定义函数
打开设计器,选择服务器>函数管理器,增加一个自定义函数ReportCheck,选择类com.fr.function.ReportCheck,如下图所示:
这样,自定义函数ReportCheck便注册好了,用户可以在工程里的所有模板中使用这个自定义函数。
2.4 模板设置
2.4.1 新建模板 reportcheck1
新建普通报表:%FR_HOME%\webapps\webroot\WEB-INF\reportlets\doc\SpecialSubject\function\reportcheck1.cpt
报表样式如下图所示:
2.4.2 新建模板 reportcheck2
新建普通报表:%FR_HOME%\webapps\webroot\WEB-INF\reportlets\doc\SpecialSubject\function\reportcheck2.cpt
报表样式如下图所示:
2.5 使用自定义函数
打开 reportcheck2.cpt 模板,点击模板>报表填报属性>数据校验,设置校验公式,如下图所示:
添加校验信息如下表所示:
校验公式 | 校验出错信息 | 公式说明 |
---|---|---|
D2 <= ReportCheck("reportcheck1.cpt","[{name:max,value:90},{name:min,value:0}]",1,0) | "成绩太高,超过最高分" | 给 reportcheck1 传入两个参数,max 值为 90,min 值为 0,取执行后结果中第 2 列第 1 行和第 2 列第 2 行,即 B1 和 B2 单元格的值。 |
D2 >= ReportCheck("reportcheck1.cpt","[{name:max,value:90},{name:min,value:0}]",1,1) | "成绩太低,低于最低分" |
2.6 效果预览
保存模板,重启 Tomcat 服务器,在浏览器端输入:http://localhost:8080/webroot/decision/view/report?viewlet=doc/SpecialSubject/function/reportcheck2.cpt&op=write
成绩输入 100,点击数据校验,提示:成绩太高,超过最高分。如下图所示:
成绩输入 -10,提示:成绩太低,低于最低分。如下图所示:
成绩输入 80,校验成功。如下图所示:
注1:不支持移动端。
注2:仅支持 Tomcat 服务器。
注3:仅支持填报预览。
4. 已完成模板
已完成模板,请参见:
%FR_HOME%\webapps\webroot\WEB-INF\reportlets\doc\SpecialSubject\function\reportcheck1.cpt
%FR_HOME%\webapps\webroot\WEB-INF\reportlets\doc\SpecialSubject\function\reportcheck2.cpt
点击下载模板: