为了增加更多的常用方法,如 sum
、max
和 min
等等,我们可以扩展 Helper
类以包含这些方法。这样,MVEL 表达式就可以直接调用这些方法来执行相应的计算。我们将确保这些方法可以处理多种数值类型,并且返回适当的数值类型(如 BigDecimal
)以保证高精度。
扩展 Helper 类
我们将为 Helper
类添加 sum
、max
和 min
方法,并确保它们能够处理不同类型的数值输入(如 int
、double
和 BigDecimal
),同时保持与 avg
方法相同的转换逻辑。
定义 Helper 类
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;public class Helper {// 将 Number 转换为 BigDecimalprivate BigDecimal toBigDecimal(Number number) {if (number instanceof BigDecimal) {return (BigDecimal) number;} else if (number instanceof Double || number instanceof Float) {return new BigDecimal(number.toString());} else {return BigDecimal.valueOf(number.longValue());}}// 计算平均值的方法,接受多个 Number 类型参数public BigDecimal avg(Number... numbers) {if (numbers.length == 0) return null;List<BigDecimal> bigDecimals = Arrays.stream(numbers).map(this::toBigDecimal).collect(Collectors.toList());BigDecimal sum = bigDecimals.stream().reduce(BigDecimal.ZERO, BigDecimal::add);return sum.divide(BigDecimal.valueOf(numbers.length), BigDecimal.ROUND_HALF_UP);}// 计算总和的方法,接受多个 Number 类型参数public BigDecimal sum(Number... numbers) {List<BigDecimal> bigDecimals = Arrays.stream(numbers).map(this::toBigDecimal).collect(Collectors.toList());return bigDecimals.stream().reduce(BigDecimal.ZERO, BigDecimal::add);}// 计算最大值的方法,接受多个 Number 类型参数public BigDecimal max(Number... numbers) {if (numbers.length == 0) return null;List<BigDecimal> bigDecimals = Arrays.stream(numbers).map(this::toBigDecimal).collect(Collectors.toList());return bigDecimals.stream().max(BigDecimal::compareTo).orElse(null);}// 计算最小值的方法,接受多个 Number 类型参数public BigDecimal min(Number... numbers) {if (numbers.length == 0) return null;List<BigDecimal> bigDecimals = Arrays.stream(numbers).map(this::toBigDecimal).collect(Collectors.toList());return bigDecimals.stream().min(BigDecimal::compareTo).orElse(null);}
}
主程序代码
下面是完整的示例代码,展示了如何使用 Map<String, Object>
来构建和评估复杂的 MVEL 表达式,并兼容不同的数值类型:
import org.mvel2.MVEL;import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;public class ComplexMVELExpression {public static void main(String[] args) {// 创建一个映射来保存我们的函数和变量Map<String, Object> vars = new HashMap<>();// 创建 Helper 类的实例Helper helper = new Helper();// 将 Helper 实例添加到变量映射中vars.put("helper", helper);// 创建示例数据:inputMap 和 flavorMap,使用 Object 类型以支持多种数值类型Map<String, Object> inputMap = new HashMap<>();inputMap.put("vCPU", 8); // 示例 vCPU 值,int 类型inputMap.put("内存", 16.0); // 示例 内存值,double 类型Map<String, Object> flavorMap = new HashMap<>();flavorMap.put("CPU数量", 4); // 示例 CPU 数量,int 类型flavorMap.put("CPU型号", new BigDecimal("3.5")); // 示例 CPU 型号,BigDecimal 类型flavorMap.put("内存数量", 2); // 示例 内存 数量,int 类型flavorMap.put("内存型号", new BigDecimal("2.66")); // 示例 内存 型号,BigDecimal 类型// 将示例数据也添加到变量映射中vars.put("input", inputMap);vars.put("flavor", flavorMap);// 复杂表达式字符串String complexExpression = "helper.avg(input['vCPU'] / (3 * flavor['CPU数量'] * flavor['CPU型号']), " +"input['内存'] / (flavor['内存数量'] * flavor['内存型号']))";// 使用 eval 直接执行表达式并传入变量映射try {// 由于我们返回的是 BigDecimal,所以这里直接强转BigDecimal result = (BigDecimal) MVEL.eval(complexExpression, vars);// 输出结果System.out.println("Average Result: " + result);} catch (Exception e) {e.printStackTrace();}// 测试其他方法String sumExpression = "helper.sum(input['vCPU'], flavor['CPU数量'])";String maxExpression = "helper.max(input['vCPU'], flavor['CPU数量'])";String minExpression = "helper.min(input['vCPU'], flavor['CPU数量'])";try {BigDecimal sumResult = (BigDecimal) MVEL.eval(sumExpression, vars);BigDecimal maxResult = (BigDecimal) MVEL.eval(maxExpression, vars);BigDecimal minResult = (BigDecimal) MVEL.eval(minExpression, vars);// 输出结果System.out.println("Sum Result: " + sumResult);System.out.println("Max Result: " + maxResult);System.out.println("Min Result: " + minResult);} catch (Exception e) {e.printStackTrace();}}
}
在这个例子中,我们做了以下几件事:
定义了 Helper 类:它包含了 avg、sum、max 和 min 方法,可以接受多个 Number 类型参数,并将其转换为 BigDecimal 进行高精度计算。
设置了变量映射:将 Helper 实例、inputMap 和 flavorMap 都添加到了变量映射中,这样 MVEL 表达式就可以访问它们。注意,inputMap 和 flavorMap 中的值使用 Object 类型,以支持多种数值类型(如 int、double 和 BigDecimal)。
构建了复杂的 MVEL 表达式:使用了方括号符号来访问映射中的键(例如 input['vCPU']),以及数学运算符来进行计算。
测试其他方法:除了复杂表达式外,还测试了 sum、max 和 min 方法,以确保它们能够正确工作。
通过这种方式,你可以使用 Map<String, Object> 来构建和评估更加复杂的 MVEL 表达式,并且确保表达式能够兼容多种数值类型。如果有其他问题或需要更多帮助,请随时告知!