历史版本1 :自定义函数实现表间校验 返回文档
编辑时间: 内容长度:图片数:目录数: 修改原因:
对于在填报提交时,编辑单元格的值需要与另一报表中某一单元格的值进行校验的需求,FineReport可以通过自定义函数来实现。

1. 实现原理编辑

在java实现的自定义函数中,读取报表,传入参数值并执行,从执行后的报表结果中取某个单元格值的并返回,在填报表中便可以使用返回的值进行数据校验了。
对模板reportcheck2.cpt中单元格D2输入的成绩进行校验,比较对象是reportcheck1.cpt中的值,如下如
D2输入的值不能大于另一模板中的最大值,也不能小于另一模板中的最小值。其中reportcheck1的最大值最小值是通过参数最终计算而来的。该例子仅作为原理介绍,因此比较的对象直接引用参数的值,实际情况中可能是报表通过传入的参数,根据参数取得数据,执行报表后某些格子的值,与该例子是一样的。
此时在reportcheck2.cpt中我们怎么获取另一模板的值呢?可以通过自定义函数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函数代码如下:
HTML/XML代码
// 自定义函数实现表间校验   
package com.fr.function;    
    
import java.io.File;    
import java.util.HashMap;   
import com.fr.base.Env;  
import com.fr.base.FRContext;  
import com.fr.dav.LocalEnv;  
import com.fr.general.ModuleContext;  
import com.fr.io.TemplateWorkBookIO;  
import com.fr.json.JSONArray;  
import com.fr.json.JSONObject;  
import com.fr.main.TemplateWorkBook;  
import com.fr.main.impl.WorkBook;  
import com.fr.main.workbook.ResultWorkBook;  
import com.fr.report.cell.CellElement;  
import com.fr.report.cell.TemplateCellElement;  
import com.fr.report.elementcase.TemplateElementCase;   
import com.fr.report.module.EngineModule;  
import com.fr.report.report.Report;  
import com.fr.report.worksheet.WorkSheet;  
import com.fr.script.AbstractFunction;    
import com.fr.stable.WriteActor;  
    
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;    
        // 定义报表运行环境,才能运行读取的报表    
        Env oldEnv = FRContext.getCurrentEnv();    
        String envPath = oldEnv.getPath();    
        try {    
            ResultWorkBook rworkbook = null;    
            // 读取模板    
            WorkBook workbook = (WorkBook)TemplateWorkBookIO    
                    .readTemplateWorkBook(oldEnv, 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的值    
            Report report = workbook.getReport(0);  
            WorkSheet sheet = (WorkSheet) report;  
            TemplateCellElement cellElement = sheet.getTemplateCellElement(colnumber, rownumber);  
              
            returnValue = cellElement.getValue().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;    
        }    
    }   
  
}  
注:最新的代码链接fine-help
2.2 编译自定义函数
编译ReportCheck.java,生成类ReportCheck.class,由于我们的类定义在包com.fr.function下,因此将最终生成的类文件拷贝至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)
给reportcheck1传入两个参数,max值为90,min值为0,取执行后结果中第2列第1行即B1单元格的值
D2 >= ReportCheck("reportcheck1.cpt","[{name:max,value:90},{name:min,value:0}]",1,1)
取B2单元格的值
保存,点击填报预览
成绩输入100,点击数据校验,提示“成绩太高,超过最高分”
成绩输入-10,提示“成绩太低,低于最低分”

成绩输入80,校验成功