需求: 简单的规则引擎(支持四则运算),scala 下运行。先尝试在java下测试demo。
资料
artifact :
github : https://github.com/alibaba/QLExpress
jar使用问题
官方仓库 http://maven.aliyun.com/nexus/content/repositories/public 下找不到的该jar;
在项目提供的mvn地址 http://mvnrepo.alibaba-inc.com/mvn 也无法打开。
下面就需要本地去尝试做mvn deploy。
1. 在github下载源码后解压到IDEA,
2. mvn compile 可以编译成功
mvn package 错误,BUILD FAILURE。
[ERROR] /C:/Users/.../QLExpress-master/src/test/java/com/ql/util/express/test/AClassDefineSingle.java:[12,40] unmappable character for encoding GBK
很明显由于IDE设置的encoding : utf-8, 而该项目应该是gbk的。
下一步去修改项目的编码-> GBK。
3.重新设置GBK(注意这里项目中文件可能存在多种编码)后, 会发现很多单元测试异常,依然无法通过打包。
4.放弃完整打包, 即只打包源码, 跳过项目的test阶段,需要加上-DskipTests
mvn package -Dmaven.test.skip=true
最后得到这个jar,可以选择丢在本地仓库, 或者用deploy丢到nuxus的远程库上面去, 在使用maven去引用它!
5. 测试:
public class Test {
public static void main(String[] args) throws Exception{
String express = "10 * 10 + 1 + 2 * 3 + 5 * 2";
ExpressRunner runner = new ExpressRunner(false,true);
Object r = runner.execute(express,null, null, true,true);
System.out.println("表达式计算:" + express + " = " + r);
}
}
附scala的运行结果:
scalaVersion := "2.10.4"
sbtVersion := "1.0.3"
因为我的qlexpress丢在了公司的库上面, 所以必须申明一下:
libraryDependencies += "com.taobao.util" % "taobao-express" % "3.1.7"
resolvers += " Maven Repository [nexus] " at "http://192.168.9.200:8002/nexus/content/groups/public/"
demo :
import com.ql.util.express.ExpressRunner
/**
*
*
* @author michael
* @version 1.0 Created on 2017/12/19 12:11
*/
object QlDemo {
def main(args: Array[String]): Unit = {
val express = "10 * 10 + 1 + 2 * 3 + 5 * 2"
val runner = new ExpressRunner(false, true)
val r = runner.execute(express, null, null, true, true)
System.out.println("表达式计算:" + express + " = " + r)
}
}
以上, 解决了引用的问题。
下面进入正题, 使用scala来操作简单的四则运算:
val runner = new ExpressRunner(false, true)
var context = new DefaultContext[String, AnyRef]
context.put("a", 23)
val r = runner.executeFloat(express, context, null, true, false)
System.out.println("表达式计算: " + express + " = " + r)
那么这里的context在java中是一个HashMap《K,V》, 泛型的指向对象V在scala中则会自动转成AnyRef。
scala中的int、long 、 float等都继承AnyVal, 只有String继承AnyRef,所以上面的demo中无法实现。所以下面强制转换String尝试
val runner = new ExpressRunner()
var context = new DefaultContext[String, AnyRef]
// context+=("a"->null)
context.put("a", 1.toString)
context.put("a", 2.toString)
context.put("c", 3.toString)
val express: String = "a+b*c"
val r = runner.execute(express, context, null, true, false, null)
System.out.println("表达式计算: " + express + " = " + r)
ERROR: String转换Number异常
了解一下源码中的参数解析:
* @param expressString 程序文本
* @param context 执行上下文
* @param errorList 输出的错误信息List
* @param isCache 是否使用Cache中的指令集
* @param isTrace 是否输出详细的执行指令信息
* @param aLog 输出的log
Error原因: qlExpress在上下文代入时会把参数值强制转换为Number, 因为scala的语言这里把数值内容包装成String,所以转换异常。
解决: 修改源码OperatorOfNumber.java(进入qlexpress项目中)
a.将文件中的所有 (Number)op1,(Number)op2 修改为new BigDecimal(op1.toString()),new BigDecimal(op2.toString())
例如:
修改前->
PreciseNumberOperator.addPrecise((Number)op1,(Number)op2)
修改后->
PreciseNumberOperator.addPrecise(new BigDecimal(op1.toString()),new BigDecimal(op2.toString()))
b. qlExpress对字符内容的 + 运算有特殊处理, 这里需要修改
public static Object add(Object op1, Object op2,boolean isPrecise) throws Exception {
if(op1 == null){
op1 = "null";
}
if(op2 == null){
op2 = "null";
}
//因为scala用字符串类型包装数据内容, 这里需要禁用
// if (op1 instanceof String || op2 instanceof String) {
// return op1.toString() + op2.toString();
// }
if(isPrecise==true){
return PreciseNumberOperator.addPrecise(new BigDecimal(op1.toString()),new BigDecimal(op2.toString()));
}else{
return NormalNumberOperator.addNormal(new BigDecimal(op1.toString()),new BigDecimal(op2.toString()));
}
}
修改完qlexpress, 重新打包测试
val runner = new ExpressRunner(false, true)
val express: String = "a+b*c-d/e"
var context1 = new DefaultContext[String, AnyRef]
var a: Any = 2.20
var b: Any = 2
var c: Any = 3
var d: Any = 3
var e: Any = 1
context1.put("a", a.toString)
context1.put("b", b.toString)
context1.put("c", c.toString)
context1.put("d", d.toString)
context1.put("e", e.toString)
val r1 = runner.execute(express, context1, null, true, true)
System.out.println("表达式计算: " + express + " = " + r1)
1: STAT_BLOCK:STAT_BLOCK STAT_BLOCK
2: STAT_SEMICOLON:STAT_SEMICOLON STAT_SEMICOLON
3: -:- -
4: +:+ +
5: a:ID ID
5: *:* *
6: b:ID ID
6: c:ID ID
4: /:/ /
5: d:ID ID
5: e:ID ID
表达式计算: a+b*c-d/e = 5.2
Process finished with exit code 0
测试通过!