跳到主要内容

自定义报表函数

自定义报表表达式

积木报表支持用户自定义编写表达式,并应用在报表中。

示例:新增函数->将字母转成大写

1.定义函数

import com.googlecode.aviator.runtime.function.AbstractFunction;
import com.googlecode.aviator.runtime.type.AviatorObject;
import com.googlecode.aviator.runtime.type.AviatorRuntimeJavaType;
import org.jeecg.modules.jmreport.desreport.express.ExpressUtil;
import java.util.Map;


/**
* 定义函数:
* 1.定义getName方法,返回一个字符串
* 2.如果函数参数个数已知,继承AbstractFunction,重写call方法,call是一个多态方法,参数AviatorObject arg可以传多个
* 3.如果函数参数个数未知,继承AbstractVariadicFunction,重写variadicCall方法
**/
public class UpcaseFun extends AbstractFunction {

@Override
public String getName() {
return "upCase";
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1) {
// 参数用此方法获取 数字也这么获取 然后自己转
String str = ExpressUtil.getArgString(arg1, env);
return AviatorRuntimeJavaType.valueOf(str.toUpperCase());
}

}

2.注册函数

import com.googlecode.aviator.AviatorEvaluatorInstance;
import org.jeecg.modules.jmreport.desreport.express.enhance.IJmExpressCustom;
import org.springframework.stereotype.Component;

/**
* 注册函数:
* 1.添加类注解@Component
* 2.实现接口 IJmExpressCustom,重写方法 addFunction
* 3.instance.addFunction(fun.getName(), fun);
* 4.如果是运算函数(如:加减乘除),调用instance.addOpFunction
*/
@Component
public class JmExpressCustomImpl implements IJmExpressCustom {

@Override
public void addFunction(AviatorEvaluatorInstance instance) {
UpcaseFun fun = new UpcaseFun();
instance.addFunction(fun.getName(), fun);
instance.addFunction(fun.getName().toUpperCase(),fun);
instance.addFunction(fun.getName().toLowerCase(),fun);
//OtherFun fun1 = new OtherFun ();
//instance.addFunction(fun1.getName(), fun1);
//instance.addFunction(fun1.getName().toUpperCase(), fun1);
//instance.addFunction(fun1.getName().toLowerCase(), fun1);
}
}

3.测试效果:

  • 设计页面:

  • 预览页面:

自定义报表函数支持动态行的聚合计算

版本支持version 1.8.0+ date 20240802

使用场景

有如下所示报表:

现需要统计表格中每月的销售额总和以及每月销售额小于10000的城市数量

分析

每月的销售额总和: 可以使用系统自带函数SUM(),当SUM函数在动态扩展行下方时,系统会自动将动态扩展的列都添加到SUM的参数中,比如下图所示的设计中,SUM(D5)在预览时系统会自动更新参数为:SUM(D5:Dn)

每月销售额小于10000的城市数量并不能使用系统函数实现,但是默认情况下,系统是不会给自定义函数进行上述的参数更新;在编写自定义函数时需要满足以下要求,系统才会为自定义函数更新动态行参数。

要求:

  1. 自定义表达式继承自com.googlecode.aviator.runtime.function.AbstractVariadicFunction

  2. 自定义表达式实现AviatorObject variadicCall(Map<String, Object> var1, AviatorObject... var2);方法

实现方式

1、准备数据

2、编写自定义函数

import com.googlecode.aviator.runtime.function.AbstractVariadicFunction;
import com.googlecode.aviator.runtime.type.AviatorJavaType;
import com.googlecode.aviator.runtime.type.AviatorObject;
import com.googlecode.aviator.runtime.type.AviatorRuntimeJavaType;
import com.googlecode.aviator.runtime.type.AviatorType;
import org.jeecg.modules.jmreport.common.util.OkConvertUtils;
import org.jeecg.modules.jmreport.desreport.express.ExpressUtil;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

/**
* 自定义函数,统计小于1000的数量
* @Author: jmreport
* @Date: 2024/8/02 18:53
*/
public class CustomCount extends AbstractVariadicFunction {
@Override
public String getName() {
return "custom_count".toLowerCase();
}

@Override
public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
int result = 0;
List<String> ignoreCells = (List<String>) env.get("ignore");
for (int i = 0; i < args.length; i++) {
if (args[i].getAviatorType().equals(AviatorType.JavaType)) {
Object cell = ((AviatorJavaType) args[i]).getName();
if (ignoreCells != null && ignoreCells.indexOf(cell.toString()) >= 0) {
continue;
}
}
Object temp = args[i].getValue(env);
if (OkConvertUtils.isEmpty(temp)) {
continue;
}
BigDecimal value = new BigDecimal(temp.toString());
if (value.compareTo(BigDecimal.valueOf(10000)) < 0) {
result++;
}
}
return AviatorRuntimeJavaType.valueOf(result);
}
}

一定要继承AbstractVariadicFunction

3、注册自定义函数

import com.googlecode.aviator.AviatorEvaluatorInstance;
import org.jeecg.modules.jmreport.desreport.express.enhance.IJmExpressCustom;
import org.springframework.stereotype.Component;

@Component
public class JmExpressCustomImpl implements IJmExpressCustom {

@Override
public void addFunction(AviatorEvaluatorInstance instance) {
CustomCount fun = new CustomCount();
instance.addFunction(fun.getName(), fun);
instance.addFunction(fun.getName().toUpperCase(), fun);
instance.addFunction(fun.getName().toLowerCase(), fun);
}
}

4、绘制报表

本例使用的是组合动态列分组报表,所以需要设置跟随横向分组扩展

如果是纵向分组或者列表数据,是不需要设置跟随横向分组扩展

5、保存预览