时间过的好快,突然就发现,已经过去一两年了,这一两年博客也写的不多,快要进入中年了,最重要的就是自律。要好好睡觉,好好学习,好好工作。
废话不多说,这次给大家说的是 表达式语言解析Mvel2.0
MVEL为 MVFLEX Expression Language(MVFLEX表达式语言)的缩写,它是一种动态/静态的可嵌入的表达式语言和为Java平台提供Runtime(运行时)的语言。最初是作为一个应用程序框架实用程序的语言开始,该项目现已发展完全独立。
MVEL通常用于执行用户(程序员)通过配置XML文件或注释等定义的基本逻辑。它也可以用来解析简单的JavaBean表达式。Runtime(运行时)允许MVEL表达式通过解释执行或者预编译生成字节码后执行。
MVEL可以和drools 规则引擎配合使用
2.0版本,具有以下特性:
新的静态类型检查和属性支持,允许集成类型安全表达。
错误报告的改善。包括行和列的错误信息。
新的脚本语言特征。MVEL2.0 包含函数定义,如:闭包,lambda定义,标准循环构造(for, while, do-while, do-until…),空值安全导航操作,内联with-context运营 ,易变的(isdef)的测试运营等等。
改进的集成功能。迎合主流的需求,MVEL2.0支持基础类型的个性化属性处理器,集成到JIT中。
更快的模板引擎,支持线性模板定义,宏定义和个性化标记定义。
新的交互式shell(MVELSH)。
1:目前:MVEL拥有最快的解析器和编译器
2:MVEL优于其他嵌入式脚本语言的所有基准,除了算术性能基准方面:JEXL和MVEL并列( 12ms操作50000次迭代) 。
3:Groovy的编译器最慢,其次是JUEL然后OGNL 。
4:OGNL最差缓存反射性能,其次是JEXL 。
5:OGNL的嵌套map基准表现最差。这个基准包括解决从使用索引语法的Map中获取属性的问题(foo[‘bar’][‘something’]) 。
6:Groovy的编译器是目前使用一个特设的方式的时候速度太慢。
mvel2.x表达式包含以下部分的内容:属性表达式,布尔表达式,方法调用,变量赋值,函数定义。
我这边是做规则判断时用到此表达式语言,所以将自己用到的情况及例子贴出来。关于mvel 其他的一些用途和功能,大家可以下载文末的 mvel2.0文档,自行进行学习。
首先引入依赖
<dependency>
<groupId>org.mvel</groupId>
<artifactId>mvel2</artifactId>
<version>2.4.7.Final</version>
</dependency>
创建mvel引擎对象和方法
import java.io.Serializable;
import java.util.Map;
import org.mvel2.MVEL;
/**
* 脚本语言性能测试结果
* https://www.iteye.com/topic/361794
* https://www.iteye.com/blog/caoyaojun1988-163-com-2089726
*
* @author yyb
* @time 2020/8/12
*/
public class MvelEngine {
/**
* 执行表达式
*
* @param expr
* @param data
* @return
*/
public Object exec(String expr, Map<String, Object> data) {
try {
Object result = MVEL.eval(expr, data);
if (result != null) {
return result;
}
} catch (Exception e) {
System.out.println("表达式执行错误");
return false;
}
return null;
}
/**
* 编译表达式
*
* @param expr
* @return
*/
public Serializable compileExpr(String expr) {
try {
Serializable compiled = MVEL.compileExpression(expr);
return compiled;
} catch (Exception e) {
System.out.println("表达式编译错误:" + expr);
return null;
}
}
/**
* 执行编译后的表达式
*
* @param expr
* @param data
* @return
*/
public boolean execCompiled(Object expr, Map<String, Object> data) {
try {
Object result = MVEL.executeExpression(expr, data);
if (result instanceof Boolean) {
return (Boolean) result;
} else {
return false;
}
} catch (Exception e) {
System.out.println("表达式执行错误");
return false;
}
}
/**
* 执行有返回值的表达式
*
* @param expr
* @param data
* @return
*/
public Object execReturnCompiled(Object expr, Map<String, Object> data) {
try {
Object result = MVEL.executeExpression(expr, data);
if (result != null) {
return result;
}
} catch (Exception e) {
System.out.println("表达式执行错误");
return false;
}
return null;
}
private static MvelEngine engine;
/**
* 创建基于MVEL的表达式引擎。
*
* @return
*/
public synchronized static MvelEngine defaultEngine() {
if (engine == null) {
engine = new MvelEngine();
}
return engine;
}
}
测试代码
public class MvelTest {
public static void main(String[] args) {
ageTest();
containsTest();
startsWithTest();
emptyTest();
multipleTest();
returnTest();
execExprTest();
}
/**
* 布尔表达式:
* 大于小于 等于 以及 优先级
*/
public static void ageTest() {
String expr = "(age > 10 && age <= 20) || age == 11 ";
MvelEngine engine = MvelEngine.defaultEngine();
Object obj = engine.compileExpr(expr);
Map<String, Object> params = new HashedMap();
params.put("age", 12);
if (engine.execCompiled(obj, params)) {
//满足表达式
System.out.println("少年");
} else {
System.out.println("不满足条件");
}
}
/**
* 判断包含
*/
public static void containsTest() {
String expr = "name contains(\"张\")";
MvelEngine engine = MvelEngine.defaultEngine();
Object obj = engine.compileExpr(expr);
Map<String, Object> params = new HashedMap();
params.put("name", "张三");
params.put("age", 11);
if (engine.execCompiled(obj, params)) {
//满足表达式
System.out.println("包含张");
} else {
System.out.println("不满足条件");
}
}
/**
* 判断以xx开头
*/
public static void startsWithTest() {
String expr = "mobile.startsWith(136)";
MvelEngine engine = MvelEngine.defaultEngine();
Object obj = engine.compileExpr(expr);
Map<String, Object> params = new HashedMap();
params.put("mobile", "13643489802");
params.put("age", 11);
if (engine.execCompiled(obj, params)) {
//满足表达式
System.out.println("包含136开头手机号");
} else {
System.out.println("不满足条件");
}
}
/**
* 判空,多个表达式时,只有最后一个表达式的结果为返回
*/
public static void emptyTest() {
String expr = "foo == null ; foo1 == nil; foo2 == empty";
MvelEngine engine = MvelEngine.defaultEngine();
Object obj = engine.compileExpr(expr);
Map<String, Object> params = new HashedMap();
params.put("foo", 1);
params.put("foo1", 1);
params.put("foo2", " ");
if (engine.execCompiled(obj, params)) {
//满足表达式
System.out.println("true");
} else {
System.out.println("不满足条件");
}
}
/**
* 多个表达式时,只有最后一个表达式的结果为返回
* 您可以编写具有任意数量语句的脚本,使用分号表示语句的终止。这在所有情况下都是必需的,除非只有一条语句,或者脚本中的最后一条语句。
*/
public static void multipleTest() {
String expr = "age > 20; sex == 1; name contains(\"张2\")";
MvelEngine engine = MvelEngine.defaultEngine();
Object obj = engine.compileExpr(expr);
Map<String, Object> params = new HashedMap();
params.put("age", 10);
params.put("sex", 1);
params.put("name", "张三");
if (engine.execCompiled(obj, params)) {
//满足表达式
System.out.println("true");
} else {
System.out.println("不满足条件");
}
}
/**
* 有返回值的表达式
*/
public static void returnTest() {
String expr = "a = 10;b = (a = a * 2) + 10; a;";
MvelEngine engine = MvelEngine.defaultEngine();
Object obj = engine.compileExpr(expr);
Map<String, Object> params = new HashedMap();
params.put("a", 1);
Object r = engine.execReturnCompiled(obj, params);
if (null != r) {
//满足表达式
System.out.println("a = " + r);
} else {
System.out.println("不满足条件");
}
}
/**
* 不用编辑即可执行
*/
public static void execExprTest() {
String expr = "x * y";
MvelEngine engine = MvelEngine.defaultEngine();
Map vars = new HashMap();
vars.put("x", new Integer(5));
vars.put("y", new Integer(10));
Object r = engine.exec(expr, vars);
if (r != null) {
//满足表达式
System.out.println(r);
} else {
System.out.println("不满足条件");
}
}
}
mvel2.0语法指南文档点我下载
参考资料
https://blog.csdn.net/shichen2010/article/details/78466293
http://mvel.codehaus.org/
https://www.iteye.com/topic/361794