文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2024-04-02 19:55

关注

背景

做项目突然遇到这样的需求:
系统要获取多个数据源的数据,并进行处理,最后输出多个字段。字段的计算规则一般是简单的取值最多加一点条件判断。
而且需要动态变动!!例如一个字段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,了解一下

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯