QLExpress在Java 阿里

QLExpress在Java&Scala中使用问题
需求: 简单的规则引擎(支持四则运算),scala 下运行。先尝试在java下测试demo。

资料 
artifact : 

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>QLExpress</artifactId>
  <version>3.2.0</version>
</dependency>


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
1
很明显由于IDE设置的encoding : utf-8, 而该项目应该是gbk的。 
下一步去修改项目的编码-> GBK。 
3.重新设置GBK(注意这里项目中文件可能存在多种编码)后, 会发现很多单元测试异常,依然无法通过打包。 
4.放弃完整打包, 即只打包源码, 跳过项目的test阶段,需要加上-DskipTests

    mvn package -Dmaven.test.skip=true  
1
最后得到这个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);

    }
}
1
2
3
4
5
6
7
8
9
10


附scala的运行结果:

scalaVersion := "2.10.4"
sbtVersion := "1.0.3"
1
2
因为我的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/"
1
2
3
4
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)
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16


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

下面进入正题, 使用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)
1
2
3
4
5
6
那么这里的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)
1
2
3
4
5
6
7
8
9
ERROR: String转换Number异常

了解一下源码中的参数解析:

 * @param expressString 程序文本
 * @param context 执行上下文
 * @param errorList 输出的错误信息List
 * @param isCache 是否使用Cache中的指令集
 * @param isTrace 是否输出详细的执行指令信息
 * @param aLog 输出的log
1
2
3
4
5
6
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)
1
2
修改后->
PreciseNumberOperator.addPrecise(new BigDecimal(op1.toString()),new BigDecimal(op2.toString()))
1
2
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()));
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
修改完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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
测试通过!
--------------------- 
作者:c343500263 
来源:CSDN 
原文:https://blog.csdn.net/c343500263/article/details/78839766 
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/rainyear/article/details/85133840