专业小程序网站开发,免费网络游戏大全,WordPress按评论时间排序,两个相同的网站对做优化有帮助1. 前言
小伙伴大家好#xff0c;在上一篇文章我们简单初探了QLExpress表达式引擎#xff0c;我们简单写了一个HelloWorld的程序#xff0c;并成功的运行期望的结果。在本篇文章中我们来熟悉一下QLExpress的语法#xff0c;因为我们在后面简道云公式实战的时候#xff0c…1. 前言
小伙伴大家好在上一篇文章我们简单初探了QLExpress表达式引擎我们简单写了一个HelloWorld的程序并成功的运行期望的结果。在本篇文章中我们来熟悉一下QLExpress的语法因为我们在后面简道云公式实战的时候需要用到这些语法。废话少说直接开始。
2. 基础语法
相信大家也下载了QLExpress的源码在下载的源码中有一个readme文件在这个文件中源码作者已经介绍了语法以及QLExpress的用法。大家可以详细阅读以及运行相应的测试文件。如图所示 2.1 操作符和java对象
2.1.1 操作符
在readme说明文件中我们知道QLExpress支持的操作符有 ,-,*,/,,,,,,!,,%,,–-
in 【类似sql】,like【sql语法】,,||
支持forbreak、continue、if then else 等标准的程序控制逻辑 上述的的操作符笔者都会写测试用例。我们先从简单的四则运算开始:
2.1.1.1 四则运算 四则运算需求提出
需求1编写java程序使用QLExpress表达式引擎计算12-3*4/5 表达式的结果并在控制台打印结果
需求2编写java程序使用QLExpress表达式引擎计算1 加 2 减 3 乘 4 除 5表达式的结果并在控制台打印结果 当我们拿到需求的时候首先第一步我们要明确需求需求是让我们借助QLExpress表达式引擎来计算表达式的结果。
表达式中包括英文-*/和中文加 减 乘 除。需求中并没有提出计算结果精度的问题(虽然需求没有定下来我们要支持高精度计算)。
基于上述的讨论后码农就拿起键盘一头扎进了QLExpress代码学习中以及各种百度CSDN搜索解决方案。最终码农A编写了需求1如下代码 /**** 12-3*4/5*/
Test
public void test1() throws Exception{// param isPrecise 是否需要高精度计算支持// param isTrace 是否跟踪执行指令的过程ExpressRunner runner new ExpressRunner(true, true);String expressStr 12-3*4/5;// isTrace rst runner.execute(expressStr, null, null, true, true);System.out.println(rst);
} 码农A很自豪的讲起了自己的解决方案QLExpress引擎提供了isPrecise 和 isTrace两个属性在ExpressRunner 初始化的时候可以指定isPrecise 是否需要高精度计算支持和isTrace 是否跟踪执行指令的过程。isTrace在调试阶段很有用可以查看表达式执行指令的整个过程在程序上线时建议设置为false避免浪费资源。
如果isPrecisetrue代码运行的结果为0.6000000000如果isPrecise false代码运行结果为1.代码运行如图所示 码农A沮丧的说我解决了需求1但是需求2没有找到解决方案。项目组中有人找到需求2的解决方案吗大家可以交流一下。一向低调的码农B开口了。
码农B说通过阅读QLExpress代码找到一个方法 addOperatorWithAlias(加,,null)。 /*** 添加操作符和关键字的别名同时对操作符可以指定错误信息。* 例如addOperatorWithAlias(加,,null)** param keyWordName* param realKeyWordName* param errorInfo* throws Exception*/
public void addOperatorWithAlias(String keyWordName, String realKeyWordName, String errorInfo) throws Exception {if (errorInfo ! null errorInfo.trim().length() 0) {errorInfo null;}//添加函数别名if (this.manager.isFunction(realKeyWordName)) {this.manager.addFunctionName(keyWordName);this.operatorManager.addOperatorWithAlias(keyWordName, realKeyWordName, errorInfo);return;}NodeType realNodeType this.manager.findNodeType(realKeyWordName);if (realNodeType null) {throw new QLException(关键字 realKeyWordName 不存在);}boolean isExist this.operatorManager.isExistOperator(realNodeType.getName());if (!isExist errorInfo ! null) {throw new QLException(关键字 realKeyWordName 是通过指令来实现的不能设置错误的提示信息errorInfo 必须是 null);}if (!isExist || errorInfo null) {//不需要新增操作符号只需要建立一个关键子即可this.manager.addOperatorWithRealNodeType(keyWordName, realNodeType.getName());} else {this.manager.addOperatorWithLevelOfReference(keyWordName, realNodeType.getName());this.operatorManager.addOperatorWithAlias(keyWordName, realNodeType.getName(), errorInfo);}
} 此方法作用就是添加操作符和关键字的别名于是就构思出来如下代码【test2方法运行报错】 Test
public void test2() throws Exception{ExpressRunner runner new ExpressRunner(true, true);String expressStr 1 加 2 减 3 乘 4 除 5;runner.addOperatorWithAlias(加,,加 的这个操作符有问题);runner.addOperatorWithAlias(减,-,减 的这个操作符有问题);runner.addOperatorWithAlias(乘,*,乘 的这个操作符有问题);runner.addOperatorWithAlias(除,/,除 的这个操作符有问题);// isTrace rst runner.execute(expressStr, null, null, true, true);System.out.println(rst);
} 经测试发现程序报错
com.ql.util.express.exception.QLException: * 不能被设置别名:com.ql.util.express.instruction.op.OperatorMultiplyDivide.init(java.lang.String, java.lang.String, java.lang.String) 如下图所示 通过报错信息可知OperatorMultiplyDivide.init方法有问题于是就进入OperatorMultiplyDivide源码模仿着写了
OperatorMultiply 类和 OperatorDivide类即把 OperatorMultiplyDivide类拆分成两个类。 /*** 类描述:乘操作** author admin* version 1.0.0* date 2023/11/13 17:17*/
public class OperatorMultiply extends Operator {Overridepublic executeInner([] list) throws Exception {return executeInner(list[0], list[1]);}public executeInner( op1, op2) throws Exception { result OperatorOfNumber.multiply(op1, op2, this.isPrecise);return result;}}/*** 类描述:除操作** author admin* version 1.0.0* date 2023/11/13 17:21*/
public class OperatorDivide extends Operator {Overridepublic executeInner([] list) throws Exception {return executeInner(list[0], list[1]);}public executeInner( op1, op2) throws Exception { result OperatorOfNumber.divide(op1, op2, this.isPrecise);return result;}} 基于上面两个类又写了test3方法该方法运行报错 Test
public void test3() throws Exception{ExpressRunner runner new ExpressRunner(true, true);String expressStr 1 加 2 减 3 乘 4 除 5;runner.addOperator(*,new OperatorMultiply());runner.addOperator(/,new OperatorDivide());runner.addOperatorWithAlias(加,,加 的这个操作符有问题);runner.addOperatorWithAlias(减,-,减 的这个操作符有问题);runner.addOperatorWithAlias(乘,*,乘 的这个操作符有问题);runner.addOperatorWithAlias(除,/,除 的这个操作符有问题);// isTrace rst runner.execute(expressStr, null, null, true, true);System.out.println(rst);
} 运行报错java.lang.RuntimeException: 节点类型定义重复:* 定义1*:TYPEKEYWORD 定义2*:TYPEKEYWORD 根据错误信息猜测应该是runner.addOperator(*,new OperatorMultiply());源码中已经有了于是就找到OperatorFactory工厂类笔者删减了其他代码发现确实在这个工厂类中已经添加addOperator(*, new OperatorMultiplyDivide(*));addOperator(/, new OperatorMultiplyDivide(/)); public OperatorFactory(boolean isPrecise) {this.isPrecise isPrecise;addOperator(!, new OperatorNot(!));addOperator(*, new OperatorMultiplyDivide(*));addOperator(/, new OperatorMultiplyDivide(/));
} 既然有了那我就直接用汉字 不就能满足需求了于是就又写了以下代码test4(运行通过) Test
public void test4() throws Exception{ExpressRunner runner new ExpressRunner(true, true);String expressStr 1 加 2 减 3 乘 4 除 5;runner.addOperator(乘,new OperatorMultiply());runner.addOperator(除,new OperatorDivide());runner.addOperatorWithAlias(加,,加 的这个操作符有问题);runner.addOperatorWithAlias(减,-,减 的这个操作符有问题);// isTrace rst runner.execute(expressStr, null, null, true, true);System.out.println(rst);
} 如果isPrecisetrue代码运行的结果为0.6000000000如果isPrecise false代码运行结果为1 2.1.1.2 其余操作符测试案例
取余操作 /**** 测试操作符mod* isTrace输出脚本的编译解析过程一般对于业务系统来说关闭之后会提高性能。*/
Test
public void mod() throws Exception{ExpressRunner runner new ExpressRunner(false, true);String expressStr 20 % 5;// isTraceObject rst runner.execute(expressStr, null, null, true, true);System.out.println(rst);
} 加加操作
注意这个操作分为前加加和后加加 如i 和i,在QLExpress中前加加会报错。 /**** 测试* throws Exception*/
Test
public void addPlusAfter() throws Exception{ExpressRunner runner new ExpressRunner(false, true);DefaultContextString, Object context new DefaultContext();context.put(a,11);context.put(b,12);String expressStr a;// isTraceObject rst runner.execute(expressStr, context, null, true, true);// 打印此时a的值是多少Object a_now context.get(a);System.out.println(a_now);System.out.println(rst);
}/**** 测试 反例* throws Exception com.ql.util.express.exception.QLCompileException: 程序错误不满足语法规范没有匹配到合适的语法,最大匹配致[0:-1]*/
Test
public void addPlusBefore() throws Exception{ExpressRunner runner new ExpressRunner(false, true);DefaultContextString, Object context new DefaultContext();context.put(a,11);context.put(b,12);String expressStr a;// isTraceObject rst runner.execute(expressStr, context, null, true, true);// 打印此时a的值是多少Object a_now context.get(a);System.out.println(a_now);System.out.println(rst);
} 减减操作
注意--这个操作分为前减减和后减减 如i-- 和--i,在QLExpress中前减减会报错。 /**** 测试--* throws Exception*/
Test
public void minusPlusAfter() throws Exception{ExpressRunner runner new ExpressRunner(false, true);DefaultContextString, Object context new DefaultContext();context.put(a,11);context.put(b,12);String expressStr a--;// isTraceObject rst runner.execute(expressStr, context, null, true, true);// 打印此时a的值是多少Object a_now context.get(a);System.out.println(a_now);System.out.println(rst);
}/**** 测试-- 反例* throws Exception com.ql.util.express.exception.QLCompileException: 程序错误不满足语法规范没有匹配到合适的语法,最大匹配致[0:-1]*/
Test
public void minusPlusBefore() throws Exception{ExpressRunner runner new ExpressRunner(false, true);DefaultContextString, Object context new DefaultContext();context.put(a,11);context.put(b,12);String expressStr --a;// isTraceObject rst runner.execute(expressStr, context, null, true, true);// 打印此时a的值是多少Object a_now context.get(a);System.out.println(a_now);System.out.println(rst);
} 不等于操作符
注意不等于符号是 ! 切记不要使用 /**** 测试 ! 符号* throws Exception*/
Test
public void ne() throws Exception{ExpressRunner runner new ExpressRunner(false, true);String expressStr 20 ! 5;// isTraceObject rst runner.execute(expressStr, null, null, true, true);System.out.println(rst);
}/**** 测试 符号 反例* throws Exception com.ql.util.express.exception.QLCompileException: 程序错误不满足语法规范没有匹配到合适的语法,最大匹配致[0:1]*/
Test
public void ne2() throws Exception{ExpressRunner runner new ExpressRunner(false, true);DefaultContextString, Object context new DefaultContext();context.put(a,11);context.put(b,12);String expressStr a b;// isTraceObject rst runner.execute(expressStr, null, null, true, true);System.out.println(rst);
} in操作 /**** in 测试*/
Test
public void in() throws Exception{ExpressRunner runner new ExpressRunner(false, false);String expressStr 34 in (83,7,9);Object rst runner.execute(expressStr, null, null, true, false);System.out.println(rst);
} like操作
注意 ab如果作为一个值的话要用引号包裹否则QLExpress会把ab当做一个变量 /**** like测试*/
Test
public void like() throws Exception{// 注意ab必须用字符串包裹不然会把ab当做变量ExpressRunner runner new ExpressRunner(false, false);String expressStr ab like %a%;Object rst runner.execute(expressStr, null, null, true, false);System.out.println(rst);
} 操作 /**** * throws Exception*/
Test
public void and() throws Exception{ExpressRunner runner new ExpressRunner(false, false);String expressStr false true;Object rst runner.execute(expressStr, null, null, true, false);System.out.println(rst);} ||操作 /**** ||* throws Exception*/
Test
public void or() throws Exception{ExpressRunner runner new ExpressRunner(false, false);String expressStr false || true;Object rst runner.execute(expressStr, null, null, true, false);System.out.println(rst);} 三目表达式测试 /**** 测试三目表达式*/
Test
public void san() throws Exception{ExpressRunner runner new ExpressRunner(false, false);String expressStr int a1;int b2;ab?a:b;;Object rst runner.execute(expressStr, null, null, true, false);System.out.println(rst);
} for 循环操作
注意while循环测试报错 /**** 测试循环* throws Exception*/
Test
public void loop() throws Exception{ExpressRunner runner new ExpressRunner(false, false);String expressStr int sum10; for(int i 0; i 1; i i 1){ println(i); sumsumi; } return sum;// isTraceObject rst runner.execute(expressStr, null, null, true, false);System.out.println(rst);System.out.println(--------------java for loop------------);int sum10;for (int i0;i1;i1) {System.out.println(i);sum sum i;}System.out.println(sum);
}/**** while 循环* throws Exception*/
Test
public void loop2() throws Exception {ExpressRunner runner new ExpressRunner(false, true);String expressStr while(true) {println(1)};Object rst runner.execute(expressStr, null, null, true, false);System.out.println(rst);
} if_then_else操作符 /**** if_then_else 测试*/
Test
public void if_then_else() throws Exception{ExpressRunner runner new ExpressRunner(false, false);String expressStr if 11 then {return 10}else{return 100};Object rst runner.execute(expressStr, null, null, true, false);System.out.println(rst);
}Test
public void if_() throws Exception{ExpressRunner runner new ExpressRunner(false, false);String expressStr if(11) { return 100;};Object rst runner.execute(expressStr, null, null, true, false);System.out.println(rst);
}Test
public void if_else() throws Exception{ExpressRunner runner new ExpressRunner(false, false);String expressStr if(12) { return 100;} else { return -1;};Object rst runner.execute(expressStr, null, null, true, false);System.out.println(rst);
}Test
public void if_then() throws Exception{ExpressRunner runner new ExpressRunner(false, false);String expressStr if(11) then{ return 100;};Object rst runner.execute(expressStr, null, null, true, false);System.out.println(rst);
} 2.1.1.3 java对象操作
在QLExpress表达式引擎中是支持操作java对象的比如我们在一个表达式中需要调用一个java对象的方法作为处理的函数。下面我们还是通过测试用例来说明java对象操作的知识点
1. 首先创建Bean对象 /*** 类描述:** author admin* version 1.0.0* date 2023/11/13 16:03*/
public class Student {// 学号private String sn;// 姓名private String name;// 年龄private int age;public Student(){}public Student(String sn, String name, int age) {this.sn sn;this.name name;this.age age;}public String getSn() {return sn;}public void setSn(String sn) {this.sn sn;}public String getName() {return name;}public void setName(String name) {this.name name;}public int getAge() {return age;}public void setAge(int age) {this.age age;}public static String print(String msg) {String rst Student print method exe::::::msg;return rst;}
} 2.我们都知道java对象的生命周期是从初始化开始的那么我们就用QLExpress表达式的形式初始化一个对象 /**** 测试java对象测试创建对象*/
Test
public void obj_init() throws Exception{ExpressRunner runner new ExpressRunner(false, false);String expressStr import com.ql.util.express.self.base.Student; Student stu new Student(000,tom,18); return stu.getName();Object rst runner.execute(expressStr, null, null, true, false);System.out.println(rst);
} 通过表达式我们可知QLExpress是支持import的关键字 3.测试调用Student对象的print方法 /**** 测试调用java对象 addFunctionOfClassMethod*/
Test
public void obj_method_addFunctionOfClassMethod() throws Exception{ExpressRunner runner new ExpressRunner(false, false);String expressStr 打印(jim);// 使用QLExpress用于将一个用户自己定义的对象(例如Spring对象)方法转换为一个表达式计算的函数runner.addFunctionOfClassMethod(打印,Student.class.getName(),print, new String[]{String},null);Object rst runner.execute(expressStr, null, null, true, false);System.out.println(rst);
} 说明addFunctionOfClassMethod方法含义为
用于将一个用户自己定义的对象(例如Spring对象)方法转换为一个表达式计算的函数。
该方法的源码为 /*** 添加一个类的函数定义例如Math.abs(double) 映射为表达式中的 取绝对值(-5.0)** param name 函数名称* param className 类名称* param functionName 类中的方法名称* param parameterTypes 方法的参数类型名称* param errorInfo 如果函数执行的结果是false需要输出的错误信息* throws Exception*/
public void addFunctionOfClassMethod(String name, String className, String functionName, String[] parameterTypes,String errorInfo) throws Exception {OperatorSelfDefineClassFunction operatorSelfDefineClassFunction new OperatorSelfDefineClassFunction(name,className, functionName, parameterTypes, null, null, errorInfo);this.addFunction(name, operatorSelfDefineClassFunction);
} 4.测试调用java对象的方法2 /**** 测试调用java对象 addFunctionOfClassMethod*/
Test
public void obj_method_addFunctionOfServiceMethod() throws Exception{ExpressRunner runner new ExpressRunner(false, false);String expressStr 打印(jim);// 使用QLExpressrunner.addFunctionOfServiceMethod(打印,new Student(),print, new String[]{String},null);Object rst runner.execute(expressStr, null, null, true, false);System.out.println(rst);
} addFunctionOfClassMethod 方法用于将用户定义的对象的方法转换为表达式计算的函数 /*** 用于将一个用户自己定义的对象(例如Spring对象)方法转换为一个表达式计算的函数** param name* param serviceObject* param functionName* param parameterTypes* param errorInfo* throws Exception*/
public void addFunctionOfServiceMethod(String name, Object serviceObject, String functionName,String[] parameterTypes, String errorInfo) throws Exception {OperatorSelfDefineServiceFunction operatorSelfDefineServiceFunction new OperatorSelfDefineServiceFunction(name, serviceObject, functionName, parameterTypes, null, null, errorInfo);this.addFunction(name, operatorSelfDefineServiceFunction);
} 总结
通过测试QLExpress操作java对象我们学习了addFunctionOfClassMethod 方法我们可以把一个java类中的方法转化为QLExpress表达式函数。
最近笔者创建了一个圈子https://pc.fenchuan8.com/#/index?forum58055yqm9HKS
欢迎大家加入一起交流学习。