java利用JEXL实现动态表达式编译

网友投稿 389 2022-10-29


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依赖:

org.apache.commons

commons-jexl

2.0

正则表达式匹配

首先写一个公共方法:

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![1ojBDl3,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,了解一下


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:克隆对象clone
下一篇:GNS3 V1.5.2 与IOU L2 L3的集成
相关文章

 发表评论

暂时没有评论,来抢沙发吧~