本文将介绍QlExpress中自定义操作符Operator
+ Micro
的使用姿势,通过扩展Operator,可以为规则脚本赋能,提供更友好的使用姿势
1. 自定义Opeartor 通常需要实现一个自定义的Operator
时,可以考虑通过继承Opeartor
类,实现executeInner
方法
如实现一个字符串拆分操作符 split
要实现上面这种脚本的支持,首先是定义一个自定义的Split
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public static class Split extends Operator { @Override public Object executeInner (Object[] objects) { String base = String.valueOf(objects[0 ]); String dot = "," ; if (objects.length > 1 ) { dot = String.valueOf(objects[1 ]); } String[] cells = StringUtils.split(base, dot); java.util.List<String> result = new java.util.ArrayList<>(); for (int i = 0 ; i < cells.length; i++) { String cell = cells[i].trim(); if (cell.length() == 0 ) { continue ; } result.add(cell); } return result; } }
接下来注册Operator
1 2 3 4 5 6 7 ExpressRunner expressRunner = new ExpressRunner(); DefaultContext<String, Object> context = new DefaultContext<>(); expressRunner.addOperator("split" , new Split()); Object ans = expressRunner.execute("\"1,2,3,4,5\" split ','" , context, null , true , false ); System.out.println(ans);
执行之后输出结果如下
从上面Operator的实现可以看到,第二个参数不传时,默认采用英文逗号进行分隔,那么表达式应该怎么写呢?
1 2 3 expressRunner.execute("split '1,2,3,'" , context, null , true , false ); expressRunner.execute("'1,2,3,' split" , context, null , true , false )
目前从有限的使用姿势获取渠道上,使用Operator时,左右参数都需要有
当然如果只需要传入一个参数时,可以考虑下面的方式
注册Operator为方法
1 2 3 expressRunner.addFunction("splitFunc" , new Split()); System.out.println(expressRunner.execute("splitFunc(\"1,2,3,4,,5,\")" , context, null , true , false ));
上面有拆分,接下来添加一个配套的Joiner
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public static class Join extends Operator { @Override public Object executeInner (Object[] list) throws Exception { List target = (List) list[0 ]; String dot = "," ; if (list.length > 1 ) { dot = String.valueOf(list[1 ]); } return Stream.of(target).map(String::valueOf).collect(Collectors.joining(dot)); } }
测试case
1 2 3 4 5 6 7 8 expressRunner.addOperator("join" , new Join()); expressRunner.addFunction("joinFunc" , new Join()); List list = Arrays.asList("hello" , 1 , 2 , 3 , "world" ); context.put("list" , list); System.out.println("join:" + expressRunner.execute("list join ','" , context, null , true , false )); System.out.println("joinFunc:" + expressRunner.execute("joinFunc(list, \";\")" , context, null , true , false ));
输出结果如
1 2 join:[hello, 1, 2, 3, world] joinFunc:[hello, 1, 2, 3, world]
2. OperatorBase 自定义Operator除了上面这种姿势之外,还可以通过继承OperatorBase
来实现更富有想象力的玩法
比如实现一个编辑上下文信息的Operator
1 2 3 4 5 6 7 8 9 10 11 12 13 public class OperatorContextPut extends OperatorBase { public OperatorContextPut (String aName) { this .name = aName; } @Override public OperateData executeInner (InstructionSetContext parent, ArraySwap list) throws Exception { String key = list.get(0 ).toString(); Object value = list.get(1 ); parent.put(key, value); return null ; } }
通过上面这个来实现编辑上下文内容(当然也是可以直接通过变量赋值,来修改上下文)
3. Mciro 宏定义,学过c的小伙伴多半不会陌生这个东西,QlExpress可以通过addMacro
来实现宏定义
如定义一个计数
的宏
1 2 3 4 5 6 7 8 9 10 11 12 13 ExpressRunner runner = new ExpressRunner(); DefaultContext<String, Object> context = new DefaultContext<>(); runner.addMacro("计数" , "cnt = map.get(key); cnt = cnt == null ? 1: cnt + 1; map.put(key, cnt);" ); Map<String, Object> map = new HashMap<>(); map.put("kk" , 10 ); context.put("map" , map); runner.execute("String key = \"kk\"; 计数" , context, null , true , false ); context.put("key" , "cc" ); runner.execute("计数" , context, null , true , false ); System.out.println("计数之后:" + map);
上面这个计数非常有意思,表达式就是一个 计数
, 就可以实现map中key对应的value自增+1
如上面的输出结果如下
4. 小结 本文主要介绍QlExpress中自定义Operator的使用姿势,以及Micro宏的简单示例
对于Opeartor,可以注册为Operator操作符,也可以注册为function;需要注意的是命名需要全局唯一
系列博文:
II. 其他 一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
2. 声明 尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
3. 扫描关注 一灰灰blog