什么是MVEL?
1. MVEL 是什么?
简单来说,MVEL 是一种强大的表达式解析器(Expression Language)。我们可以编写特定的表达式字符串,交给 MVEL 进行解析计算,从而得到结果。
概念可能比较抽象,我们通过示例来理解。
基本示例
比如我们要进行一个加法运算。在 Java 中通常这样写:
int res = 1 + 1; // 2若使用 MVEL,则可以这样写:
Object res = MVEL.eval("1 + 1"); // 2对比两者,第一种方式是硬编码实现的计算结果;而第二种方案直接向 MVEL.eval 函数传递一个表达式字符串,即可动态计算出结果。如果需要计算 1 - 1,只需传入不同的表达式字符串即可。
试想如果要计算 (2 + 2) * 3 + 5 / 2 或 2 > 1 ? 1 + 1 : 2 + 2 这样的复杂逻辑,硬编码需要编写多行代码且不便扩展,而 MVEL 仅需改变表达式字符串。
MVEL 的能力不仅限于此。它支持大量的语法结构,包括条件判断、循环等,还可以支持自定义函数。那么在工作中我们该如何使用它呢?
2. 在自定义数据流转中的使用
什么是数据流转
数据流转指的是不同对象间数据的转换。例如,将对象 A 的数据通过某些规则转化为对象 B 的数据。这听起来很像数据清洗,确实,数据清洗是其中的一个具体场景。
如下图所示:

由图可以看出,源对象和目标对象中 name 和 age 字段是一对一映射。但是目标对象不需要 sex 字段,却多了一个 birthYear(出生年)字段,且该字段是通过年龄计算而来的。
下面我们以代码模拟这个转换过程。为了简化演示,这里对象均使用 Map 来定义:
HashMap<Object, Object> srcMap = Maps.newHashMap();
srcMap.put("name", "zs");
srcMap.put("age", 10);
srcMap.put("sex", "女");
// 字段映射关系
HashMap<String, String> mapping = Maps.newHashMap();
mapping.put("name", "name");
mapping.put("age", "age");
// 这里先把当前年份写死为 2019
mapping.put("birthYear", "2019 - age");
// 目标对象
HashMap<Object, Object> targetMap = Maps.newHashMap();
// k 为目标表字段,v 为转换规则
mapping.forEach((k, v) -> {
Object reValue = MVEL.eval(v, srcMap);
targetMap.put(k, reValue);
});
System.out.println("源对象" + srcMap); // 源对象{sex=女,name=zs, age=10}
System.out.println("目标对象" + targetMap); // 目标对象{birthYear=2009, name=zs, age=10}实现过程非常简单。但上述代码中,计算出生年份时的当前年份被写死为 2019,这明显不是我们想要的通用方案。我们可以通过自定义函数来解决这个问题。
自定义函数扩展
1. 定义获取当前年份函数
首先定义一个 Java 方法来获取当前年份:
/**
* 获取当前年份方法
* @return 当前年份字符串
*/
public static Object getCurrentYear() {
Calendar date = Calendar.getInstance();
String year = String.valueOf(date.get(Calendar.YEAR));
return year;
}2. 注册自定义函数
将定义好的函数注册到 MVEL 的解析上下文中:
static ParserContext context = new ParserContext();
static {
// MvelTest 是 getCurrentYear 函数所在的类
Method[] declaredMethods = MvelTest.class.getDeclaredMethods();
for (Method method : declaredMethods) {
context.addImport(method.getName(), method);
}
}3. 使用编译后的表达式
在使用时,将原来的 MVEL.eval(v, srcMap) 替换为以下代码:
Object reValue = MVEL.executeExpression(MVEL.compileExpression(v, context), srcMap);compileExpression 的作用是将我们的规则编译成 MVEL 可以识别的执行过程。此时,将 birthYear 的规则替换为 mapping.put("birthYear", "getCurrentYear() - age"),执行后即可得到动态计算的正确结果。
有了这些基础,我们可以自定义更多的转换规则,还可以借此开发一套用户配置工具,根据用户自己的配置进行相应的资源映射,得到想要的目标数据。
3. 小结
本文只是展示了在工作中用到 MVEL 的一个小小尝试。关于 MVEL 更多的特性与研究,后续可进一步深入。
说明:文中示例代码基于 MVEL 2.x 版本及 Java 8 语法环境(使用了 Maps.newHashMap 需引入 Guava 依赖)。部分示例中的年份(如 2019)为写作时的硬编码演示,实际使用时请结合动态逻辑。 版权声明:本文为原创文章,版权归 戴老师的博客 所有,转载请联系博主获得授权。
本文地址:https://1diff.fun/archives/shen-me-shi-mvel.html
如果对本文有什么问题或疑问都可以在评论区留言,我看到后会尽量解答。