自定义报表函数
自定义报表表达式
积木报表支持用户自定义编写表达式,并应用在报表中。
示例:新增函数->将字母转成大写
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的城市数量并不能使用系统函数实现,但是默认情况下,系统是不会给自定义函数进行上述的参数更新;在编写自定义函数时需要满足以下要求,系统才会为自定义函数更新动态行参数。
要求:
-
自定义表达式继承自
com.googlecode.aviator.runtime.function.AbstractVariadicFunction
-
自定义表达式实现
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、保存预览如果是纵向分组或者列表数据,是不需要设置跟随横向分组扩展的