package org.jeecg.modules.mdc.util;
|
|
import org.apache.commons.jexl3.*;
|
import org.springframework.stereotype.Component;
|
import java.math.BigDecimal;
|
import java.util.Map;
|
|
/**
|
* @Author: Lius
|
* @CreateTime: 2025-08-19
|
* @Description: 自定义公式计算类
|
*/
|
@Component
|
public class JexlFormulaCalculator {
|
|
// 通过JexlBuilder创建JexlEngine实例
|
private static final JexlEngine jexl = new JexlBuilder().create();
|
|
/**
|
* 计算自定义公式,除数为0时返回0
|
* @param formula 公式字符串,如 "processLong/measureTime*1.0"
|
* @param variables 公式中的变量键值对
|
* @return 计算结果(BigDecimal类型,除数为0时返回0)
|
*/
|
public BigDecimal calculate(String formula, Map<String, Object> variables) {
|
try {
|
// 解析公式
|
JexlExpression expression = jexl.createExpression(formula);
|
|
// 创建上下文并注入变量
|
MapContext context = new MapContext();
|
for (Map.Entry<String, Object> entry : variables.entrySet()) {
|
String varName = entry.getKey();
|
Object value = entry.getValue();
|
// 确保变量为数字类型
|
if (value instanceof Number) {
|
context.set(varName, value);
|
} else {
|
throw new IllegalArgumentException("变量" + varName + "必须是数字类型");
|
}
|
}
|
|
// 执行计算
|
Object result = expression.evaluate(context);
|
|
// 转换为BigDecimal返回
|
if (result instanceof Number) {
|
return new BigDecimal(result.toString());
|
} else {
|
throw new RuntimeException("公式计算结果不是数字");
|
}
|
} catch (JexlException e) {
|
// 关键:不依赖内部类,直接通过异常消息判断除数为0
|
if (e.getMessage() != null && e.getMessage().contains("division by zero")) {
|
return BigDecimal.ZERO; // 除数为0返回0
|
}
|
// 其他JEXL异常正常抛出
|
throw new RuntimeException("公式计算失败: " + formula, e);
|
} catch (Exception e) {
|
throw new RuntimeException("公式计算失败: " + formula, e);
|
}
|
}
|
}
|