一个轻量级的类java语法规则引擎,作为一个嵌入式规则引擎在业务系统中使用。让业务规则定义简便而不失灵活。让业务人员就可以定义业务规则。支持标准的JAVA语法,还可以支持自定义操作符号、操作符号重载、函数定义、宏定义、数据延迟加载等

QLExpress的特性

1、编译执行:

编译生成基础指令后执行,性能能得到基本保障。执行过程:单词分解-->单词类型分析-->语法分析-->生成运行期指令集合-->执行生成的指令集合

  1. runner.execute("10 * 10 + 1 + 2 * 3 + 5 * 2", null, true,null);
  2. 最后生成的指令:
  3. 1:LoadData 10
  4. 2:LoadData 10
  5. 3:OP : * OPNUMBER[2]
  6. 4:LoadData 1
  7. 5:OP : + OPNUMBER[2]
  8. 6:LoadData 2
  9. 7:LoadData 3
  10. 8:OP : * OPNUMBER[2]
  11. 9:OP : + OPNUMBER[2]
  12. 10:LoadData 5
  13. 11:LoadData 2
  14. 12:OP : * OPNUMBER[2]
  15. 13:OP : + OPNUMBER[2]

2、支持标准的java语法、JAVA运算符号和关键字

  1. import:引入一个包或者类,例如:import java.util.*;需要放在脚本的最前面
  2. new:创建一个对象,例如:new ArrayList();
  3. for:操作符号
  4. if:操作符号
  5. then:操作符号
  6. else:操作符号
  7. break: 终止循环
  8. continue: 绩效循环
  9. return: 返回
  1. A、四则运算 : 10 * 10 + 1 + 2 * 3 + 5 * 2
  2. Bboolean运算: 3 > 2 and 2 > 3
  3. C、创建对象,对象方法调用,静态方法调用:new com.ql.util.express.test.BeanExample("张三").unionName("李四")
  4. D、变量赋值:a = 3 + 5
  5. E、支持 in,max,min: (a in (1,2,4)) and (b in("abc","bcd","efg"))

3、自定义的关键字

  1. include:在一个表达式中引入其它表达式。例如: include com.taobao.upp.b; 资源的转载可以自定义接口IExpressResourceLoader来实现,缺省是从文件中装载
  2. []:匿名创建数组.int[][] abc = [[11,12,13],[21,22,23]];
  3. NewMap:创建HashMap. Map abc = NewMap(1:1,2:2);Map abc = NewMap("a":1,"b":2)
  4. NewList:串接ArrayList.List abc = NewList(1,2,3);
  5. exportDef: 将局部变量转换为全局变量,例如:exportDef long userId
  6. alias:创建别名,例如: alias 用户ID user.userId
  7. exportAlias: 创建别名,并转换为全局别名
  8. macro: 定义宏,例如: macro 降级 {level = level - 1}
  9. function: 定义函数,例如: function add(int a,int b){ return a+b; };
  10. in: 操作符号,例如: 3 in (3,4,5)
  11. mod:操作符号,例如: 7 mod 3
  12. like:操作符号,例如: "abc" like 'ab%'

4、自定义的系统函数,后续还会不断的添加

  1. max:取最大值max(3,4,5)
  2. min:最最小值min(2,9,1)
  3. round:四舍五入round(19.08,1)
  4. print:输出信息不换行print("abc")
  5. println:输出信息并换行 println("abc")

5、提供表达式上下文,属性的值不需要在初始的时候全部加入,而是在表达式计算的时候,需要什么信息才通过上下文接口获取。

避免因为不知道计算的需求,而在上下文中把可能需要的数据都加入。
runner.execute("三星卖家 and 消保用户",errorList,true,expressContext) "三星卖家"和"消保用户"的属性是在需要的时候通过接口去获取。

6、可以将计算结果直接存储到上下文中供后续业务使用。例如:

  1. runner.execute("c = 1000 + 2000",errorList,true,expressContext);
  2. 则在expressContext中会增加一个属性c=3000,也可以在expressContext实现直接的数据库操作等。

7、支持高精度浮点运算,只需要在创建执行引擎的时候指定参数即可:new ExpressRunner(true,false);
8、可以将Class和Spring对象的方法映射为表达式计算中的别名,方便其他业务人员的立即和配置。例如

  1. Math.abs() 映射为 "取绝对值"
  2. runner.addFunctionOfClassMethod("取绝对值", Math.class.getName(), "abs",new String[] { "double" }, null);
  3. runner.execute("取绝对值(-5.0)",null,true,null);

9、可以为已经存在的boolean运算操作符号设置别名,增加错误信息同步输出,在计算结果为false的时候,同时返回错误信息,减少业务系统相关的处理代码

  1. runner.addOperatorWithAlias("属于", "in", "用户$1不在允许的范围")。
  2. 用户自定义的函数同样也可以设置错误信息:例如:
  3. runner.addFunctionOfClassMethod("isOk", BeanExample?.class.getName(),"isOk", new String[] { "String" }, "$1 不是VIP用户");
  4. 则在调用:
  5. List errorList = new ArrayList?();
  6. Object result =runner.execute("( (1+1) 属于 (4,3,5)) and isOk("玄难")",errorList,true,null);
  7. 执行结果 result = false.同时在errorList中还会返回2个错误原因:
  8. 1"用户 2 不在允许的范围"
  9. 2、玄难 不是VIP用户

10、可以自定义函数,自定一个操作函数 group

  1. class GroupOperator extends Operator {
  2. public GroupOperator(String aName) {
  3. this.name= aName;
  4. }
  5. public Object executeInner(Object[] list)throws Exception {
  6. Object result = new Integer(0);
  7. for (int i = 0; i < list.length; i++) {
  8. result = OperatorOfNumber.Add.execute(result, list[i]);
  9. }
  10. return result;
  11. }
  12. }

则执行:

  1. runner.addFunction("累加", new GroupOperator("累加"));
  2. runner.addFunction("group", new GroupOperator("group"));
  3. //则执行:group(2,3,4) = 9 ,累加(1,2,3)+累加(4,5,6)=21

11、可以自定操作符号。自定义的操作符号优先级设置为最高。例如自定一个操作函数 love:

  1. class LoveOperator extends Operator {
  2. public LoveOperator(String aName) {
  3. this.name= aName;
  4. }
  5. public Object executeInner(Object[] list)
  6. throws Exception {
  7. String op1 = list[0].toString();
  8. String op2 = list[1].toString();
  9. String result = op2 +"{" + op1 + "}" + op2;
  10. return result;
  11. }
  12. }

然后增加到运算引擎:

  1. runner.addOperator("love", new LoveOperator("love"));
  2. //则执行:'a' love 'b' love 'c' love 'd' = "d{c{b{a}b}c}d"

12、可以重载已有的操作符号。例如替换“+”的执行逻辑。参见:com.ql.util.express.test.ReplaceOperatorTest
13、可以延迟运算需要的数据
14、一个脚本可以调用其它脚本定义的宏和函数.参见com.ql.util.express.test.DefineTest
15、可以类似VB的语法来使用操作符号和函数。print abc; 等价于 print(abc).参见 com.ql.util.express.test.OpCallTest
16、支持类定义
17、对 in 操作支持后面的是一个数组或者List变量义

最典型的应用场景

在业务系统中存在一些逻辑判断,例如"商品A"只能是三星卖家,而且已经开通淘宝店铺的用户才能订购。
那么我们期望业务人员看到的配置信息就是:"三星卖家 而且 已经开店"
则通过下列步骤可能实现这个功能:

1、定义一个用户信息对象:

  1. class UserInfo {
  2. long id;
  3. long tag;
  4. String name;
  5.  
  6. public UserInfo(long aId,String aName, long aUserTag) {
  7. this.id = aId;
  8. this.tag = aUserTag;
  9. this.name = aName;
  10. }
  11. public String getName(){
  12. return name;
  13. }
  14. public long getUserId() {
  15. return id;
  16. }
  17.  
  18. public long getUserTag() {
  19. return tag;
  20. }
  21. }

2、定义两个基础的功能函数:

  1. /**
  2. * 判断一个用户TAG的第X位是否为1。这个的demo,其实现合理性不考虑
  3. * @param user
  4. * @param tagBitIndex
  5. * @return
  6. */
  7. public boolean userTagJudge(UserInfo user,int tagBitIndex){
  8. boolean r = (user.getUserTag() & ((long)Math.pow(2, tagBitIndex))) > 0;
  9. return r;
  10. }
  11.  
  12. /**
  13. * 判断一个用户是否订购过某个商品
  14. * @param user
  15. * @param goodsId
  16. * @return
  17. */
  18. public boolean hasOrderGoods(UserInfo user,long goodsId){
  19. //随机模拟一个
  20. if(user.getUserId() % 2 == 1){
  21. return true;
  22. }else{
  23. return false;
  24. }
  25. }

3、初始化语句执行器

  1. public void initial() throws Exception{
  2. runner.addOperatorWithAlias("而且","and",null);
  3. runner.addFunctionOfClassMethod("userTagJudge", Demo.class.getName(), "userTagJudge",
  4. new String[] {UserInfo.class.getName(),"int"}, "你不是三星卖家");
  5. runner.addFunctionOfClassMethod("hasOrderGoods", Demo.class.getName(), "hasOrderGoods",
  6. new String[] {UserInfo.class.getName(),"long"}, "你没有开通淘宝店铺");
  7. runner.addMacro("三星卖家", "userTagJudge(userInfo,3)");//3表示三星卖家的标志位
  8. runner.addMacro("已经开店", "hasOrderGoods(userInfo,100)");//100表示旺铺商品的ID
  9. }

4、定义一个逻辑判断函数:

  1. /**
  2. * 判断逻辑执行函数
  3. * @param userInfo
  4. * @param expression
  5. * @return
  6. * @throws Exception
  7. */
  8. public String hasPermission(UserInfo userInfo,String expression) throws Exception {
  9. IExpressContext<String,Object> expressContext = new DefaultContext<String,Object>();
  10. expressContext.put("userInfo",userInfo);
  11. List<String> errorInfo = new ArrayList<String>();
  12. Boolean result = (Boolean)runner.execute(expression, expressContext, errorInfo, true, false);
  13. String resultStr ="";
  14. if(result.booleanValue() == true){
  15. resultStr = "可以订购此商品";
  16. }else{
  17. for(int i=0;i<errorInfo.size();i++){
  18. if(i > 0){
  19. resultStr = resultStr + "," ;
  20. }
  21. resultStr = resultStr + errorInfo.get(i);
  22. }
  23. resultStr = resultStr + ",所以不能订购此商品";
  24. }
  25. return "亲爱的" + userInfo.getName() + " : " + resultStr;
  26. }

5、调用执行器执行判断逻辑:

  1. public static void main(String args[]) throws Exception{
  2. Demo demo = new Demo();
  3. demo.initial();
  4. System.out.println(demo.hasPermission(new UserInfo(100,"xuannan",7), "三星卖家 而且 已经开店"));
  5. System.out.println(demo.hasPermission(new UserInfo(101,"qianghui",8), "三星卖家 而且 已经开店"));
  6. System.out.println(demo.hasPermission(new UserInfo(100,"张三",8), "三星卖家 and 已经开店"));
  7. System.out.println(demo.hasPermission(new UserInfo(100,"李四",7), "三星卖家 and 已经开店"));

参考资料

http://code.taobao.org/p/QLExpress/wiki/index/

QLExpress 规则引擎使用介绍的更多相关文章

  1. SNF快速开发平台--规则引擎整体介绍及使用说明书

    一.设计目标 a)规则引擎语法能够满足分单,计费,WMS策略的配置要求.语法是一致和统一的 b)能够在不修改规则引擎模块的情况下,加入任意一个新的规则:实现上述需求之外的规则配置需求 c)运算速度快 ...

  2. SNF快速开发平台--规则引擎介绍和使用文档

    设计目标: a) 规则引擎语法能够满足分单,计费,WMS策略的配置要求.语法是一致和统一的 b) 能够在不修改规则引擎模块的情况下,加入任意一个新的规则:实现上述需求之外的规则配置需求 c) 运算速度 ...

  3. 规则引擎以及blaze 规则库的集成初探之三——Blaze规则引擎和SRL

    原文地址:http://jefferson.iteye.com/blog/68604 在上面介绍利用JSR94的api使用的章节中,我们使用的具体引擎的实现是一个商业产品,如果想了解Drools的使用 ...

  4. 小明历险记:规则引擎drools教程一

    小明是一家互联网公司的软件工程师,他们公司为了吸引新用户经常会搞活动,小明常常为了做活动加班加点很烦躁,这不今天呀又来了一个活动需求,我们大家一起帮他看看. 小明的烦恼 活动规则是根据用户购买订单的金 ...

  5. SNF快速开发平台--规则引擎在程序当中如何调用

    规则定义完如何在程序当中进行使用呢? 其时很简单,只需要如下代码就可以调用程序: 规则定义: 调用代码: #region 演示2:生成左表数据(规则) POST: /api/DEMO/DemoSing ...

  6. 规则引擎drools封装

    一.前言 网上规则引擎drools介绍很多,并且有很多细致的说明,作者也不敢托大说自己的好用,但作者经过2个项目使用过规则引擎后,自己对规则引擎的理解并进行封装,对规则内容及如何使用,有自己的一番实践 ...

  7. .Net规则引擎介绍 - REngine

    规则引擎 规则引擎由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策.接受数据输入,解释业务规则,并根据业务规则做出业务决策 ...

  8. 规则引擎QLExpress的简单应用

    QLExpress 是一个轻量级的类java语法规则引擎,作为一个嵌入式规则引擎在业务系统中使用.让业务规则定义简便而不失灵活.让业务人员就可以定义业务规则.支持标 准的JAVA语法,还可以支持自定义 ...

  9. Devs--开源规则引擎介绍

    Devs Devs是一款轻量级的规则引擎. 开源地址:https://github.com/CrankZ/devs 基础概念 此规则引擎的基础概念有字段.条件.规则等. 其中字段组成条件,条件组成规则 ...

随机推荐

  1. php基础-6

    类的继承和方法重写 <?php class people{ public function __construct($name, $age, $sex) { $this->age = $a ...

  2. url参数和字典的相互转化

    目标url:https://www.baidu.com/s?&wd=python&ie=utf-8 将字典转成url参数 使用urllib.parse的urlencode方法,将字典对 ...

  3. 将本地项目上传到git/码云

    idea查看任意项目的远程仓库地址: git remote -v git branch -v git branch -d  分支名          删除本地分支 git branch -D  分支名 ...

  4. LeetCode - Number of Distinct Islands

    Given a non-empty 2D array grid of 0's and 1's, an island is a group of 1's (representing land) conn ...

  5. ios-UITableView无内容时,不显示多余的分隔线

    效果如上. 只要补上以下方法: //设置多于的分割线 -(void)setExtraCellLineHidden: (UITableView *)tableView { UIView *view = ...

  6. POI事件模型处理execl导入功能(只支持07版本的execl)

    由于通过new XSSFWorkbook 这种方式导入导致生产环境端口宕机.通过dump文件和javacore文件分析是导入功能导致的.解决办法:自己通过网上写的工具类,不知道是否存在bug. pac ...

  7. S老师 破坏神学习

    代码质量不高 就不整理了 发上来留个纪念 表示自己写过了 数据库:MySQL,服务端:PhotonServer 视频:https://pan.baidu.com/s/1i4ROaRr 客户端:http ...

  8. powerdesigner16.5 破解

    powerdesigner16.5 破解 方法: 破解方法 1.将下载下来的PowerDesigner165_破解文件.rar进行解压,之后找到pdflm16.dll破解文件,并将pdflm16.dl ...

  9. C#获取当前路径的七种方法 【转载】

    //1.获取模块的完整路径. string path1 = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName; // ...

  10. Ajax 异步请求返回集合遍历问题

    for(var i = 0;data.length;I++){ var value = data[i]; } 这种遍历,如果方法体没有取值,则页面会卡死,具体原因待解,如果有方法体取值,则所取值val ...