利用JEXL实现动态表达式编译
转载自 利用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
利用JEXL实现动态表达式编译相关推荐
- 找不到编译动态表达式所需的一种或多种类型。是否缺少对 Microsoft.CSharp.dll 和 System.Core.dll 的引用?...
提示"找不到编译动态表达式所需的一种或多种类型.是否缺少对 Microsoft.CSharp.dll 和 System.Core.dll 的引用? "错误 解决方法: 将引入的 ...
- jboss fuse 教程_JBoss Fuse:使用JEXL的动态蓝图文件
jboss fuse 教程 在本文中,我将展示如何在Apache Aries Blueprint xml文件中添加一些内联脚本. 我不一定会称其为最佳实践,但我一直有这样的想法:这种能力可能有用. 可 ...
- JBoss Fuse:使用JEXL的动态蓝图文件
在本文中,我将展示如何在Apache Aries Blueprint xml文件中添加一些内联脚本. 我不一定会称其为最佳实践,但我一直认为这种功能可能有用. 可能当我被迫使用xml来模拟命令式编程结 ...
- 代码生成(Code Generation) 表达式编译
代码生成(Code Generation)技术广泛应用于现代的数据系统中.代码生成是将用户输入的表达式.查询.存储过程等现场编译成二进制代码再执行,相比解释执行的方式,运行效率要高得多.尤其是对于计算 ...
- 利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习)
原文:利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习) Mono.Cecil是一个强大的MSIL的注入工具,利用它可以实现动态创建程序集,也可以实现拦截器横向切入动态方法,甚至还 ...
- 解答网友提问:如何构建动态表达式实现高级查询服务
上次我们介绍了"一秒创建高级查询服务".前天,有网友在公众号后台问我,怎么使用动态表达式: 我想应该是客户提出了更高的要求,查询的条件不仅限于大于.小于,更加多样化,需要动态组合成 ...
- Unix/Linux操作系统分析实验二 内存分配与回收:Linux系统下利用链表实现动态内存分配
Unix/Linux操作系统分析实验一 进程控制与进程互斥 Unix/Linux操作系统分析实验三 文件操作算法: 实现在/proc目录下添加文件 Unix/Linux操作系统分析实验四 设备驱动: ...
- AICompiler动态shape编译框架
AICompiler动态shape编译框架 移动互联网的兴起,不仅产生了海量数据,也对人机交互有了新的定义.企业如何动态处理不同规格图片数据,如何更灵活处理不同长度的对话语料等等,提升企业运营效率,争 ...
- php 循环写入 缓冲,php利用缓冲实现动态输出(flush,ob_flush)
php利用缓冲实现动态输出通过 flush,ob_flush实现 print str_repeat(" ", 4096);//php.ini output_buffering默认是 ...
最新文章
- STD:Sparse-to-Dense 3D Object Detector for Point Cloud(腾讯香港大学)
- LINUX内核经典面试题30道及解答
- linux hadoop集群搭建,hadoop集群搭建
- C++宏定义中#与##的妙用
- 虚拟机下CentOS7开启SSH连接
- 数据结构---递归实现十进制装换为任意进制
- UVA10168 Summation of Four Primes【筛选法】
- C# UDP 发送 接收
- mysql_affected_rows()、mysql_fetch_row、mysql_fetch_assoc
- 记redis的一个测试
- 古希腊神话故事1 :普罗米修斯
- 杭州计算机及应用不可以落户,90%的城市取消落户限制!附杭州落户超详细攻略...
- 什么是代理IP(代理服务器)如何正确使用代理IP(代理服务器)
- MAX9286+MAX96705高级辅助驾驶系统ADAS方案
- Android 快别用Toast了,来试试Snackbar
- 网页聊天框发送表情图片实现方法
- 基于Matlab的开环Buck降压斩波电路Simulink仿真电路模型搭建
- 阅读笔记--操作系统(清华大学公开课)
- 属性表中的 <空> 空格 和 空白
- 宇视2016c语言招聘试题,宇视科技2016招聘试题.docx
热门文章
- leetcode406. 根据身高重建队列
- leetcode18. 四数之和(双指针)
- PHP做二次开发:本机安装ThinkCMF系统
- python注入进程_向进程中注入Python代码
- matlab中scrsz的意思,matlab图片c存储方法
- Codeforces Round #538 (Div. 2) F. Please, another Queries on Array? 线段树 + 欧拉函数
- Educational Codeforces Round 80 (Rated for Div. 2) E. Messenger Simulator 思维 + 树状数组
- Codeforces Round #717 (Div. 2) D(倍增dp)
- P3825 [NOI2017]游戏
- P2257 YY的GCD