QLExpress使用问题

QLExpress在Java&Scala中使用问题

需求: 简单的规则引擎(支持四则运算),scala 下运行。先尝试在java下测试demo。

  • 资料
    artifact :

    com.taobao.util
    taobao-express
    3.0.17

    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);

    }
}

QLExpress使用问题_第1张图片

附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)
  }
}

QLExpress使用问题_第2张图片

以上, 解决了引用的问题。

下面进入正题, 使用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。
QLExpress使用问题_第3张图片
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

测试通过!

你可能感兴趣的:(规则引擎)