java利用JEXL实现动态表达式编译
背景
做项目突然遇到这样的需求:
系统要获取多个数据源的数据,并进行处理,最后输出多个字段。字段的计算规则一般是简单的取值最多加一点条件判断。
而且需要动态变动!!例如一个字段a的取值,如果a > 10的时候输出10,a <= 10则输出a。这里的10可能在一天后改成8,也可能在后天就改成了12。当然,如果只是一个数字的变动还好说,我们可以使用数据库进行存储。但是,万一哪天需求突然变成了a < 10的时候输出10,a >=10 则输出a,就需要对代码改动,再测试再发布才能到生产环境使用。
一两个这样的字段还没什么,如果整个系统所依赖的字段都有这样的属性,那么我们就需要找一种方法来实现动态的加载逻辑。
下面介绍的JEXL就可以解决这种问题
JEXL(Java Expression Language)介绍
JEXL – Apache Commons JEXL Overview
下面用一些实例来介绍JEXL的使用方法
实例
maven依赖:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-jexl</artifactId>
<version>2.0</version>
</dependency>
正则表达式匹配
首先写一个公共方法:
public class Util {
public static boolean regMatch(String regEx, String str) {
Pattern pattern = Pattern.compile(regEx);
return pattern.matcher(str).matches();
}
}
下面是使用JEXL调用的方法
public void RL() {
JexlContext jc = new MapContext();
String str = "一二三四五六七八九十";
jc.set("Util", new Util());
jc.set("str", str);
jc.set("ans", "");
String expression = "ans = Util.regMatch(\"[\u4e00-\u9fa5]{10,}\",str)";
Expression e = new JexlEngine().createExpression(expression);
e.evaluate(jc);
System.out.println(jc.get("ans"));
}
代码中的expression变量就是可以动态编译的表达式,这里要注意表达式中出现的所有变量,都需要事先set进JexlContext中,否则会报错。这里有多种形式的错误:
①如果没有set”Util”,程序运行中会抛出异常。
org.apache.commons.jexl2.JexlException: TmpTest.RL@40![13,40]: 'ans = QeUtil.regMatch('[一-龥]{10,}', str);' attempting to call method on null
②如果没有set”str”,程序不会抛出异常,并输出null。如果你的regMatch方法中有判空处理,就会输出判空的结果。如果没有判空处理,在控制台的输出如下:
警告: TmpTest.RL@39![36,39]: 'ans = QeUtil.regMatch('[一-龥]{10,}', str);' undefined variable str
二月 21, 2017 4:00:41 下午 org.apache.commons.jexl2.JexlEngine invocationFailed
警告: TmpTest.RL@39![13,40]: 'ans = QeUtil.regMatch('[一-龥]{10,}', str);' method invocation error
java.lang.NullPointerException
③如果没有set”ans”,程序会正常运行,并输出正确值
为了保险起见,建议表达式中出现的所有变量,都需要事先set进JexlContext中
循环
JEXL支持两种循环方式:
for(item : list) {
x = x + item;
}
和
while (x lt 10) {
x = x + 2;
}
下面是使用while的实例:
public void loop() {
JexlContext jc = new MapContext();
jc.set("a", 1);
jc.set("b", "0");
jc.set("ans", new StringBuffer());
Expression e = new JexlEngine().createExpression("while (a < 10) {a = a + 1;ans.append(b);}");
e.evaluate(jc);
System.out.println(jc.get("ans"));
}
get\set方法调用
JEXL支持传入对象,并调用对象的方法
下面的简单的get\set方法的实例:
public void getSet() {
TmpTest tmpTest = new TmpTest();
tmpTest.setA(1);
JexlContext jc = new MapContext();
jc.set("tmpTest", tmpTest);
jc.set("ans", "");
Expression e = new JexlEngine().createExpression("ans = tmpTest.getA()");
e.evaluate(jc);
System.out.println(jc.get("ans"));
e = new JexlEngine().createExpression("ans = tmpTest.setA(2)");
e.evaluate(jc);
TmpTest tmpTest1 = (TmpTest) jc.get("tmpTest");
System.out.println(tmpTest1.getA());
}
上面的用例会在控制台先输出1,再输出2
下面是其他网友的评论
ScriptEngine比这个方便n倍,能动态执行js function,了解一下
相关文章
springboot + devtools(热部署)实例教程
devtools是boot的一个热部署工具,当我们修改了classpath下的文件(包括类文件、属性文件、页面等)时,会重新启动应用。本文通过实例给大家介绍springboot+devtools热部署,感兴趣的朋友一起看看吧2017-04-04
JVM性能调优实战:让你的IntelliJ Idea纵享丝滑
这篇文章主要介绍了JVM性能调优实战:让你的IntelliJ Idea纵享丝滑的相关资料,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2021-01-01
老生常谈spring boot 1.5.4 日志管理(必看篇)
下面小编就为大家带来一篇老生常谈spring boot 1.5.4 日志管理(必看篇)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧2017-06-06
关于SpringBoot2.7.6连接nacos遇到的一些问题
这篇文章主要介绍了关于SpringBoot2.7.6连接nacos遇到的一些问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教2024-06-06
java中@EnableAutoConfiguration注解使用
在Spring Boot框架中,@EnableAutoConfiguration是一种非常重要的注解,本文就来介绍一下java中@EnableAutoConfiguration注解使用,感兴趣的可以了解一下2023-11-11
SpringBoot+MyBatis实现MD5加密数据库用户密码的方法
MD5技术主要用于对用户密码加密,增加账户的安全性,他具有不可逆的特性,不会被轻易解密,这篇文章给大家介绍SpringBoot+MyBatis实现MD5加密数据库用户密码的方法,感兴趣的朋友跟随小编一起看看吧2024-03-03


最新评论