精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

告別硬編碼:阿里開源的動態(tài)腳本引擎 QLExpress ,真香!

開發(fā) 開發(fā)工具
本文全面介紹了 ??QLExpress?? 作為阿里巴巴開源的一款輕量級動態(tài)腳本引擎的主要功能和應(yīng)用場景,并深入講解了其在規(guī)則引擎和業(yè)務(wù)場景中的使用優(yōu)勢。

現(xiàn)代業(yè)務(wù)系統(tǒng)中,如何實現(xiàn)快速、靈活的規(guī)則配置和動態(tài)決策,成為了企業(yè)提升響應(yīng)速度和智能化水平的關(guān)鍵。阿里巴巴開源的 QLExpress 引擎,以其輕量、高效、簡潔的優(yōu)勢,為復(fù)雜業(yè)務(wù)邏輯的動態(tài)處理提供了一種創(chuàng)新的解決方案。

無論是需要實時調(diào)整規(guī)則的電商促銷,還是依賴規(guī)則動態(tài)性的金融風(fēng)控,QLExpress 都能以其靈活的表達(dá)式和易用的規(guī)則配置,實現(xiàn)高效而精準(zhǔn)的業(yè)務(wù)決策。

如果你正在尋找一款強(qiáng)大、靈活的動態(tài)腳本引擎,那么 QLExpress 可能正是你需要的工具!

一、QLExpress快速了解

QLExpress(Quick Language Express)是阿里巴巴開源的一門動態(tài)腳本引擎解析工具,起源于阿里巴巴的電商業(yè)務(wù),旨在解決業(yè)務(wù)規(guī)則、表達(dá)式、數(shù)學(xué)計算等動態(tài)腳本的解析問題。其具有以下基本特點:

  • 線程安全: QLExpress被設(shè)計為線程安全的動態(tài)腳本引擎,它使用threadlocal類型的臨時變量,確保在引擎運(yùn)算過程中的并發(fā)場景下的線程安全性。
  • 高效執(zhí)行: 為了提高執(zhí)行效率,QLExpress在編譯過程中可以將比較耗時的腳本編譯結(jié)果緩存到本地機(jī)器。此外,運(yùn)行時的臨時變量創(chuàng)建采用了緩沖池技術(shù),以確保高效的運(yùn)行時性能,使其與一些性能優(yōu)秀的腳本引擎(如Groovy)相當(dāng)。
  • 弱類型腳本語言: QLExpress采用弱類型腳本語言,語法類似于Groovy和JavaScript。這使得業(yè)務(wù)規(guī)則的表達(dá)更加靈活,雖然相對于強(qiáng)類型腳本語言可能略慢,但在業(yè)務(wù)的靈活性方面提供了很大的優(yōu)勢。
  • 安全控制: QLExpress提供了一些運(yùn)行時參數(shù)的設(shè)置,以進(jìn)行安全控制。通過這些參數(shù),可以預(yù)防一些潛在的安全問題,如死循環(huán)或?qū)Ω呶O到y(tǒng)API的調(diào)用。
  • 代碼精簡、依賴最小: QLExpress的設(shè)計追求代碼的精簡和最小依賴,其jar包大小為250k,適用于所有Java的運(yùn)行環(huán)境。這使得它在各種環(huán)境中都能輕松部署和運(yùn)行,包括在Android系統(tǒng)的低端POS機(jī)上廣泛應(yīng)用。

總體而言,這些特性使QLExpress成為一個在阿里電商業(yè)務(wù)場景中得到廣泛應(yīng)用的強(qiáng)大工具,具有高效、靈活和安全的特點。

二、QLExpress與常用規(guī)則引擎對比

圖片圖片

Drools適用于復(fù)雜的業(yè)務(wù)規(guī)則,而Aviator和QLExpress適用于相對簡單的表達(dá)式計算和規(guī)則。EasyRule更適合簡單規(guī)則場景,特別是面向非專業(yè)開發(fā)人員的情況。最終選擇取決于具體需求,包括業(yè)務(wù)規(guī)則的復(fù)雜性、性能要求、開發(fā)人員技能水平以及項目的特定場景。

三、快速引用和一般工作原理簡訴

1.引用與基本演示

在 Maven 項目中引入 QLExpress,需要在項目的 pom.xml 文件中添加相關(guān)的依賴:

<dependencies>
    <dependency>
        <groupId>com.ql</groupId>
        <artifactId>qlExpress</artifactId>
        <version>3.2.2</version> <!-- 使用實際版本號 -->
    </dependency>
</dependencies>

以下展示簡單演示如何使用 QLExpress 計算折扣后的金額。在實際項目中,可能需要更復(fù)雜的腳本和上下文,以適應(yīng)業(yè)務(wù)需求。

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

/**
 * @program: zyfboot-javabasic
 * @description: 演示如何使用 QLExpress 計算折扣后的金額
 * @author: zhangyanfeng
 **/
publicclass QLExpressExample {
    public static void main(String[] args) {
        try {
            // 創(chuàng)建 QLExpress 引擎
            ExpressRunner runner = new ExpressRunner();

            // 創(chuàng)建上下文并設(shè)置變量
            DefaultContext<String, Object> context = new DefaultContext<>();
            context.put("amount", 1000);
            context.put("discount", 0.1);

            // 執(zhí)行腳本
            String expression = "amount * (1 - discount)";
            Object result = runner.execute(expression, context, null, true, false);

            // 輸出結(jié)果
            System.out.println("Result: " + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.一般工作原理說明

QLExpress的一般工作原理,包括語法樹分析、上下文和執(zhí)行過程。

圖片圖片

  • 語法樹分析: QLExpress會先將輸入的腳本進(jìn)行詞法分析和語法分析,生成一棵語法樹。這個語法樹表示了腳本的結(jié)構(gòu),將其組織成可以被執(zhí)行的形式。
  • 上下文: 在QLExpress中,上下文是一個關(guān)鍵概念。它是腳本執(zhí)行時的環(huán)境,包含變量、函數(shù)等信息。在執(zhí)行腳本之前,你可以向上下文中添加變量,定義函數(shù),設(shè)置一些執(zhí)行參數(shù)等。這樣,腳本執(zhí)行時可以引用上下文中的內(nèi)容。
  • 執(zhí)行過程: QLExpress的執(zhí)行過程包括編譯和運(yùn)行兩個主要階段。在編譯階段,腳本被解析并生成可以執(zhí)行的指令序列。在運(yùn)行階段,這些指令被執(zhí)行,從而實現(xiàn)腳本的功能。

在這個框架下,二次定制的功能擴(kuò)展可以包括:

  • 自定義操作符和函數(shù): 可以通過實現(xiàn)自定義的操作符和函數(shù),使得腳本能夠執(zhí)行特定的業(yè)務(wù)邏輯。
  • 修改執(zhí)行流程: 可以在執(zhí)行階段插入自定義的邏輯,改變腳本執(zhí)行的流程。
  • 定制編譯過程: 在編譯階段定制特定的優(yōu)化或變換,以滿足特殊需求。
  • 擴(kuò)展上下文功能: 可以添加一些上下文的攔截器,使得在腳本執(zhí)行前后可以執(zhí)行額外的邏輯。

這樣的擴(kuò)展點允許更好地適應(yīng)特定的業(yè)務(wù)場景和需求。

四、基本語法學(xué)習(xí)

1.操作符

QLExpress 支持一系列操作符,包括算術(shù)運(yùn)算符、比較運(yùn)算符、邏輯運(yùn)算符等。

圖片圖片

定義一個 Calculator 類,其中包含一些數(shù)字和一個用戶對象,然后使用 QLExpress 進(jìn)行一些簡單的運(yùn)算和條件判斷。

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

/**
 * @program: zyfboot-javabasic
 * @description: 一些簡單的運(yùn)算和條件判斷
 * @author: zhangyanfeng
 **/
publicclass Calculator {
    public static void main(String[] args) {
        try {
            ExpressRunner runner = new ExpressRunner();
            DefaultContext<String, Object> context = new DefaultContext<>();

            // 設(shè)置變量
            context.put("a", 10);
            context.put("b", 5);

            // 算術(shù)運(yùn)算示例
            executeAndPrint(runner, context, "a + b", "Addition");

            // 比較運(yùn)算示例
            executeAndPrint(runner, context, "a > b", "Greater than");

            // 邏輯運(yùn)算示例
            executeAndPrint(runner, context, "a > 0 && b > 0", "Logical AND");

            // 三元運(yùn)算示例
            executeAndPrint(runner, context, "a > b ? 'a is greater' : 'b is greater'", "Ternary Operator");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void executeAndPrint(ExpressRunner runner, DefaultContext<String, Object> context, String expression, String operation) throws Exception {
        // 執(zhí)行腳本
        Object result = runner.execute(expression, context, null, true, false);

        // 輸出結(jié)果
        System.out.println(operation + ": " + result);
    }
}

2.Java對象操作

基本的 Java 語法和對象操作在 QLExpress 中同樣適用,演示在 QLExpress 中使用 Java 語法和進(jìn)行對象操作:

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

/**
 * @program: zyfboot-javabasic
 * @description: 基本的 Java 語法和對象操作
 * @author: zhangyanfeng
 **/
publicclass QLExpressJavaSyntaxExample {
    public static void main(String[] args) {
        try {
            ExpressRunner runner = new ExpressRunner();
            DefaultContext<String, Object> context = new DefaultContext<>();

            // 創(chuàng)建一個用戶對象
            User user = new User("John", 25);
            context.put("user", user);

            // 使用 Java 語法訪問對象屬性和調(diào)用方法
            executeAndPrint(runner, context, "user.getName()", "Accessing Object Property");
            executeAndPrint(runner, context, "user.getAge() + 5", "Performing Arithmetic with Object Property");

            // 使用 Java 語法進(jìn)行對象操作
            executeAndPrint(runner, context, "user.age = 30", "Modifying Object Property");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void executeAndPrint(ExpressRunner runner, DefaultContext<String, Object> context, String expression, String operation) throws Exception {
        // 執(zhí)行腳本
        Object result = runner.execute(expression, context, null, true, false);

        // 輸出結(jié)果
        System.out.println(operation + ": " + result);
    }

    // 用戶對象類
    staticclass User {
        private String name;
        privateint age;

        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public int getAge() {
            return age;
        }
    }
}

3.腳本中定義function

在QLExpress中,可以通過 function 關(guān)鍵字來定義函數(shù)。以下是一個簡單的示例:

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

/**
 * @program: zyfboot-javabasic
 * @description: 通過 function 關(guān)鍵字來定義函數(shù)
 * @author: zhangyanfeng
 **/
publicclass QLExpressFunctionExample {
    public static void main(String[] args) {
        try {
            final String express = "function add(int a, int b){\n" +
                    "  return a + b;\n" +
                    "};\n" +
                    "\n" +
                    "function sub(int a, int b){\n" +
                    "  return a - b;\n" +
                    "};\n" +
                    "\n" +
                    "a = 10;\n" +
                    "result = add(a, 4) + sub(a, 9);\n" +
                    "return result;";
            ExpressRunner runner = new ExpressRunner();
            DefaultContext<String, Object> context = new DefaultContext<>();

            // 執(zhí)行腳本
            Object result = runner.execute(express, context, null, true, false);

            // 輸出腳本執(zhí)行結(jié)果
            System.out.println("Result: " + result);

            // 輸出函數(shù)調(diào)用過程中的參數(shù)和返回值
            System.out.println("add function call: a + 4 = " + context.get("a") + " + 4 = " + context.get("result"));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4.擴(kuò)展操作符

在 QLExpress 中,可以通過自定義操作符(Operator)來擴(kuò)展語言的功能。

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

import java.util.ArrayList;
import java.util.List;

/**
 * @program: zyfboot-javabasic
 * @description: 自定義操作符(Operator)來擴(kuò)展語言的功能
 * @author: zhangyanfeng
 **/
publicclass QLExpressOperatorExample {
    public static void main(String[] args) {
        try {
            // 示例 1:替換 if then else 關(guān)鍵字
            ExpressRunner runner1 = new ExpressRunner();
            DefaultContext<String, Object> context1 = new DefaultContext<>();
            context1.put("語文",120);
            context1.put("數(shù)學(xué)",23);
            context1.put("英語",23);

            runner1.addOperatorWithAlias("如果", "if", null);
            runner1.addOperatorWithAlias("則", "then", null);
            runner1.addOperatorWithAlias("否則", "else", null);

            String express1 = "如果 (語文 + 數(shù)學(xué) + 英語 > 270) 則 {return 1;} 否則 {return 0;}";
            Object result1 = runner1.execute(express1, context1, null, false, false, 100L);
            System.out.println("Result 1: " + result1); // 輸出結(jié)果 1

            // 示例 2:自定義 Operator
            ExpressRunner runner2 = new ExpressRunner();
            DefaultContext<String, Object> context2 = new DefaultContext<>();

            // 自定義 Operator
            runner2.addOperator("join", new JoinOperator());

            // 示例 2.1:addOperator
            Object result2_1 = runner2.execute("1 join 2 join 3", context2, null, false, false);
            System.out.println("Result 2.1: " + result2_1); // 輸出結(jié)果 [1, 2, 3]

            // 示例 2.2:replaceOperator
            ExpressRunner runner2_2 = new ExpressRunner();
            runner2_2.replaceOperator("+", new JoinOperator());
            Object result2_2 = runner2_2.execute("1 + 2 + 3", context2, null, false, false);
            System.out.println("Result 2.2: " + result2_2); // 輸出結(jié)果 [1, 2, 3]

            // 示例 2.3:addFunction
            ExpressRunner runner2_3 = new ExpressRunner();
            runner2_3.addFunction("join", new JoinOperator());
            Object result2_3 = runner2_3.execute("join(1, 2, 3)", context2, null, false, false);
            System.out.println("Result 2.3: " + result2_3); // 輸出結(jié)果 [1, 2, 3]

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // JoinOperator 類的定義
    publicstaticclass JoinOperator extends com.ql.util.express.Operator {
        public Object executeInner(Object[] list) throws Exception {
            Object opdata1 = list[0];
            Object opdata2 = list[1];
            if (opdata1 instanceof List) {
                ((List) opdata1).add(opdata2);
                return opdata1;
            } else {
                List result = new ArrayList();
                for (Object opdata : list) {
                    result.add(opdata);
                }
                return result;
            }
        }
    }
}

5.綁定Java類或?qū)ο蟮膍ethon

在 QLExpress 中,可使用 addFunctionOfClassMethod 和 addFunctionOfServiceMethod 方法來綁定 Java 類或?qū)ο蟮姆椒ā?/p>

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

/**
 * @program: zyfboot-javabasic
 * @description: 可以使用 addFunctionOfClassMethod 和 addFunctionOfServiceMethod 方法來綁定 Java 類或?qū)ο蟮姆椒? * @author: zhangyanfeng
 * @create: 2023-11-19 16:13
 **/
publicclass QLExpressFunctionBindingExample {
    public static void main(String[] args) {
        try {
            ExpressRunner runner = new ExpressRunner();
            DefaultContext<String, Object> context = new DefaultContext<>();

            // 綁定 Math 類的 abs 方法
            runner.addFunctionOfClassMethod("取絕對值", Math.class.getName(), "abs", new String[]{"double"}, null);

            // 綁定 BeanExample 類的 upper 方法
            runner.addFunctionOfClassMethod("轉(zhuǎn)換為大寫", BeanExample.class.getName(), "upper", new String[]{"String"}, null);

            // 綁定 System.out 的 println 方法
            runner.addFunctionOfServiceMethod("打印", System.out, "println", new String[]{"String"}, null);

            // 綁定 BeanExample 對象的 anyContains 方法
            runner.addFunctionOfServiceMethod("contains", new BeanExample(), "anyContains", new Class[]{String.class, String.class}, null);

            String express = "取絕對值(-100); 轉(zhuǎn)換為大寫(\"hello world\"); 打印(\"你好嗎?\"); contains(\"helloworld\", \"aeiou\")";
            Object result = runner.execute(express, context, null, false, false);

            System.out.println("Result: " + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    publicstaticclass BeanExample {
        public static double abs(double value) {
            System.out.println("取絕對值結(jié)果: " + value);
            return Math.abs(value);
        }

        public static String upper(String abc) {
            System.out.println("轉(zhuǎn)換為大寫結(jié)果: " + abc.toUpperCase());
            return abc.toUpperCase();
        }

        public boolean anyContains(String str, String searchStr) {
            char[] s = str.toCharArray();
            for (char c : s) {
                if (searchStr.contains(c + "")) {
                    returntrue;
                }
            }
            returnfalse;
        }
    }
}

6.宏定義(macro)

在QLExpress中,宏定義(macro)允許將一個表達(dá)式片段命名為宏,并在其他地方引用這個宏。當(dāng)需要在多個地方使用相同的復(fù)雜表達(dá)式時非常有用,可以提高代碼的可讀性和維護(hù)性。

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

/**
 * @program: zyfboot-javabasic
 * @description: macro 宏定義
 * @author: zhangyanfeng
 **/
publicclass QLExpressMacroExample {
    public static void main(String[] args) {
        try {
            ExpressRunner runner = new ExpressRunner();
            DefaultContext<String, Object> context = new DefaultContext<>();

            // 定義宏
            runner.addMacro("計算平均成績", "(語文+數(shù)學(xué)+英語)/3.0");
            runner.addMacro("是否優(yōu)秀", "計算平均成績>90");

            // 設(shè)置變量值
            context.put("語文", 88);
            context.put("數(shù)學(xué)", 99);
            context.put("英語", 95);

            // 執(zhí)行表達(dá)式并打印結(jié)果
            Object result = runner.execute("是否優(yōu)秀", context, null, false, false);
            System.out.println("Result: " + result);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

7.編譯腳本查詢外部需要定義的變量和函數(shù)

在QLExpress中,編譯腳本并查詢外部需要定義的變量和函數(shù)可以通過 ExpressRunner 提供的一些方法來實現(xiàn)。

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

/**
 * @program: zyfboot-javabasic
 * @description: 編譯腳本,查詢外部需要定義的變量和函數(shù)。
 * @author: zhangyanfeng
 **/
publicclass QLExpressCompileExample {
    public static void main(String[] args) {
        try {
            ExpressRunner runner = new ExpressRunner(true, true);
            DefaultContext<String, Object> context = new DefaultContext<>();
            context.put("語文",120);
            context.put("數(shù)學(xué)",23);
            context.put("英語",23);
            context.put("綜合考試",235);

            // 定義腳本
            String express = "double 平均分 = (語文 + 數(shù)學(xué) + 英語 + 綜合考試) / 4.0; return 平均分";

            // 查詢外部需要定義的變量
            String[] variableNames = runner.getOutVarNames(express);
            System.out.println("外部需要定義的變量:");
            for (String variableName : variableNames) {
                System.out.println("var : " + variableName);
            }

            // 查詢外部需要定義的函數(shù)
            String[] functionNames = runner.getOutFunctionNames(express);
            System.out.println("\n外部需要定義的函數(shù):");
            for (String functionName : functionNames) {
                System.out.println("function : " + functionName);
            }

            // 編譯腳本并執(zhí)行
            Object result = runner.execute(express, context, null, false, false);
            System.out.println("\n腳本執(zhí)行結(jié)果: " + result);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

看下對應(yīng)打印結(jié)果:

執(zhí)行的表達(dá)式:double 平均分 = (語文 + 數(shù)學(xué) + 英語 + 綜合考試) / 4.0; return 平均分
單詞分解結(jié)果:{double},{平均分},{=},{(},{語文},{+},{數(shù)學(xué)},{+},{英語},{+},{綜合考試},{)},{/},{4.0},{;},{return},{平均分}
預(yù)處理后結(jié)果:{double},{平均分},{=},{(},{語文},{+},{數(shù)學(xué)},{+},{英語},{+},{綜合考試},{)},{/},{4.0},{;},{return},{平均分}
單詞分析結(jié)果:double:CONST_CLASS,平均分:ID,=:=,(:(,語文:ID,+:+,數(shù)學(xué):ID,+:+,英語:ID,+:+,綜合考試:ID,):),/:/,4.0:CONST_DOUBLE,;:;,return:return,平均分:ID
最后的語法樹:
1:   STAT_BLOCK:STAT_BLOCK                                                          STAT_BLOCK
2:      STAT_SEMICOLON:STAT_SEMICOLON STAT_SEMICOLON
3:         =:= =
4:            def:def def
5:               double:CONST_CLASS CONST_CLASS
5:               平均分:CONST_STRING CONST
4:            /:/ /
5:               (:CHILD_EXPRESS CHILD_EXPRESS
6:                  +:+ +
7:                     +:+ +
8:                        +:+ +
9:                           語文:ID ID
9:                           數(shù)學(xué):ID ID
8:                        英語:ID ID
7:                     綜合考試:ID ID
5:               4.0:CONST_DOUBLE CONST
2:      STAT_SEMICOLON:STAT_SEMICOLON STAT_SEMICOLON
3:         return:returnreturn
4:            平均分:ID ID


1:LoadData Class:double
2:LoadData 平均分
3:OP : def OPNUMBER[2]
4:LoadAttr:語文
5:LoadAttr:數(shù)學(xué)
6:OP : + OPNUMBER[2]
7:LoadAttr:英語
8:OP : + OPNUMBER[2]
9:LoadAttr:綜合考試
10:OP : + OPNUMBER[2]
11:LoadData 4.0
12:OP : / OPNUMBER[2]
13:OP : = OPNUMBER[2]
14:clearDataStack
15:LoadAttr:平均分
16:return [value]

外部需要定義的變量:
var : 數(shù)學(xué)
var : 綜合考試
var : 英語
var : 語文
執(zhí)行的表達(dá)式:double 平均分 = (語文 + 數(shù)學(xué) + 英語 + 綜合考試) / 4.0; return 平均分
單詞分解結(jié)果:{double},{平均分},{=},{(},{語文},{+},{數(shù)學(xué)},{+},{英語},{+},{綜合考試},{)},{/},{4.0},{;},{return},{平均分}
預(yù)處理后結(jié)果:{double},{平均分},{=},{(},{語文},{+},{數(shù)學(xué)},{+},{英語},{+},{綜合考試},{)},{/},{4.0},{;},{return},{平均分}
單詞分析結(jié)果:double:CONST_CLASS,平均分:ID,=:=,(:(,語文:ID,+:+,數(shù)學(xué):ID,+:+,英語:ID,+:+,綜合考試:ID,):),/:/,4.0:CONST_DOUBLE,;:;,return:return,平均分:ID
最后的語法樹:
1:   STAT_BLOCK:STAT_BLOCK                                                          STAT_BLOCK
2:      STAT_SEMICOLON:STAT_SEMICOLON STAT_SEMICOLON
3:         =:= =
4:            def:def def
5:               double:CONST_CLASS CONST_CLASS
5:               平均分:CONST_STRING CONST
4:            /:/ /
5:               (:CHILD_EXPRESS CHILD_EXPRESS
6:                  +:+ +
7:                     +:+ +
8:                        +:+ +
9:                           語文:ID ID
9:                           數(shù)學(xué):ID ID
8:                        英語:ID ID
7:                     綜合考試:ID ID
5:               4.0:CONST_DOUBLE CONST
2:      STAT_SEMICOLON:STAT_SEMICOLON STAT_SEMICOLON
3:         return:returnreturn
4:            平均分:ID ID


1:LoadData Class:double
2:LoadData 平均分
3:OP : def OPNUMBER[2]
4:LoadAttr:語文
5:LoadAttr:數(shù)學(xué)
6:OP : + OPNUMBER[2]
7:LoadAttr:英語
8:OP : + OPNUMBER[2]
9:LoadAttr:綜合考試
10:OP : + OPNUMBER[2]
11:LoadData 4.0
12:OP : / OPNUMBER[2]
13:OP : = OPNUMBER[2]
14:clearDataStack
15:LoadAttr:平均分
16:return [value]


外部需要定義的函數(shù):
執(zhí)行的表達(dá)式:double 平均分 = (語文 + 數(shù)學(xué) + 英語 + 綜合考試) / 4.0; return 平均分
單詞分解結(jié)果:{double},{平均分},{=},{(},{語文},{+},{數(shù)學(xué)},{+},{英語},{+},{綜合考試},{)},{/},{4.0},{;},{return},{平均分}
預(yù)處理后結(jié)果:{double},{平均分},{=},{(},{語文},{+},{數(shù)學(xué)},{+},{英語},{+},{綜合考試},{)},{/},{4.0},{;},{return},{平均分}
單詞分析結(jié)果:double:CONST_CLASS,平均分:ID,=:=,(:(,語文:ID,+:+,數(shù)學(xué):ID,+:+,英語:ID,+:+,綜合考試:ID,):),/:/,4.0:CONST_DOUBLE,;:;,return:return,平均分:ID
最后的語法樹:
1:   STAT_BLOCK:STAT_BLOCK                                                          STAT_BLOCK
2:      STAT_SEMICOLON:STAT_SEMICOLON STAT_SEMICOLON
3:         =:= =
4:            def:def def
5:               double:CONST_CLASS CONST_CLASS
5:               平均分:CONST_STRING CONST
4:            /:/ /
5:               (:CHILD_EXPRESS CHILD_EXPRESS
6:                  +:+ +
7:                     +:+ +
8:                        +:+ +
9:                           語文:ID ID
9:                           數(shù)學(xué):ID ID
8:                        英語:ID ID
7:                     綜合考試:ID ID
5:               4.0:CONST_DOUBLE CONST
2:      STAT_SEMICOLON:STAT_SEMICOLON STAT_SEMICOLON
3:         return:returnreturn
4:            平均分:ID ID


1:LoadData Class:double
2:LoadData 平均分
3:OP : def OPNUMBER[2]
4:LoadAttr:語文
5:LoadAttr:數(shù)學(xué)
6:OP : + OPNUMBER[2]
7:LoadAttr:英語
8:OP : + OPNUMBER[2]
9:LoadAttr:綜合考試
10:OP : + OPNUMBER[2]
11:LoadData 4.0
12:OP : / OPNUMBER[2]
13:OP : = OPNUMBER[2]
14:clearDataStack
15:LoadAttr:平均分
16:return [value]


腳本執(zhí)行結(jié)果: 100.25

8.不定參數(shù)的使用

在QLExpress中,可以通過使用不定參數(shù)(動態(tài)參數(shù))來處理方法的參數(shù)。

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.DynamicParamsUtil;
import com.ql.util.express.ExpressRunner;

/**
 * @program: zyfboot-javabasic
 * @description: 不定參數(shù)的使用
 * @author: zhangyanfeng
 **/
publicclass QLExpressDynamicParamsExample {
    public static void main(String[] args) {
        try {
            // 創(chuàng)建 ExpressRunner 實例
            ExpressRunner runner = new ExpressRunner();

            // 創(chuàng)建 DefaultContext 實例
            DefaultContext<String, Object> expressContext = new DefaultContext<>();

            // 在 runner 中添加一個函數(shù),使用不定參數(shù)
            runner.addFunctionOfServiceMethod("getTemplate", new QLExpressDynamicParamsExample(), "getTemplate",
                    new Class[]{Object[].class}, null);

            // 調(diào)用 getTemplate 方法,傳遞數(shù)組作為參數(shù)
            Object resultWithArray = runner.execute("getTemplate([11, '22', 33L, true])",
                    expressContext, null, false, false);
            System.out.println("Result with Array: " + resultWithArray);

            // 打開全局開關(guān),啟用動態(tài)參數(shù)調(diào)用
            DynamicParamsUtil.supportDynamicParams = true;

            // 調(diào)用 getTemplate 方法,傳遞多個參數(shù)
            Object resultWithDynamicParams = runner.execute("getTemplate(11, '22', 33L, true)", expressContext,
                    null, false, false);
            System.out.println("Result with Dynamic Params: " + resultWithDynamicParams);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 等價于 getTemplate(Object[] params)
    public Object getTemplate(Object... params) {
        StringBuilder result = new StringBuilder();
        for (Object obj : params) {
            result.append(obj).append(",");
        }
        return result.toString();
    }
}

9.集合的快捷用法

在QLExpress中,你可以使用一些快捷的語法來操作集合。

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @program: zyfboot-javabasic
 * @description: 集合操作
 * @author: zhangyanfeng
 **/
publicclass QLExpressCollectionOperationsExample {
    public static void main(String[] args) {
        try {
            ExpressRunner runner = new ExpressRunner();
            DefaultContext<String, Object> context = new DefaultContext<>();

            // 使用NewMap創(chuàng)建Map
            String expressMap = "abc = NewMap(1:1, 2:2); return abc.get(1) + abc.get(2);";
            Object resultMap = runner.execute(expressMap, context, null, false, false);
            System.out.println("NewMap Result: " + resultMap);

            // 使用NewList創(chuàng)建List
            String expressList = "abc = NewList(1, 2, 3); return abc.get(1) + abc.get(2);";
            Object resultList = runner.execute(expressList, context, null, false, false);
            System.out.println("NewList Result: " + resultList);

            // 使用方括號[]創(chuàng)建List
            String expressSquareBrackets = "abc = [1, 2, 3]; return abc[1] + abc[2];";
            Object resultSquareBrackets = runner.execute(expressSquareBrackets, context, null, false, false);
            System.out.println("Square Brackets Result: " + resultSquareBrackets);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

10.集合的遍歷

類似java的語法,只是ql不支持for(obj:list){}的語法,只能通過下標(biāo)訪問。

package org.zyf.javabasic.qlexpress;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;

import java.util.HashMap;
import java.util.Map;

/**
 * @program: zyfboot-javabasic
 * @description: 使用foreach關(guān)鍵字結(jié)合索引遍歷集合
 * @author: zhangyanfeng
 **/
publicclass QLExpressCollectionTraversalExample {
    public static void main(String[] args) {
        try {
            ExpressRunner runner = new ExpressRunner();
            DefaultContext<String, Object> context = new DefaultContext<>();

            // 創(chuàng)建一個Map
            Map<String, String> map = new HashMap<>();
            map.put("a", "a_value");
            map.put("b", "b_value");

            // 將Map放入上下文中
            context.put("map", map);

            // 遍歷Map
            String express = "keySet = map.keySet();\n" +
                    "objArr = keySet.toArray();\n" +
                    "for (i = 0; i < objArr.length; i++) {\n" +
                    "    key = objArr[i];\n" +
                    "    System.out.println(map.get(key));\n" +
                    "}";
            runner.execute(express, context, null, false, false);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

四、總結(jié)

本文全面介紹了 QLExpress 作為阿里巴巴開源的一款輕量級動態(tài)腳本引擎的主要功能和應(yīng)用場景,并深入講解了其在規(guī)則引擎和業(yè)務(wù)場景中的使用優(yōu)勢。通過對比其他規(guī)則引擎的性能與靈活性,QLExpress 展現(xiàn)了其在處理動態(tài)規(guī)則、復(fù)雜計算邏輯、實時決策等方面的獨(dú)特優(yōu)勢,尤其適用于需要動態(tài)配置業(yè)務(wù)規(guī)則的場景。在實際應(yīng)用中,QLExpress 的簡潔語法、快速上手和高性能表現(xiàn),使其成為了企業(yè)動態(tài)業(yè)務(wù)處理的有效工具。

未來,QLExpress 還可以進(jìn)一步優(yōu)化和拓展,以支持更多場景和定制化功能。對于希望在系統(tǒng)中靈活應(yīng)用規(guī)則邏輯、提升業(yè)務(wù)決策效率的開發(fā)者來說,QLExpress 是一個值得關(guān)注和嘗試的工具。

希望通過本文的介紹,大家能更好地理解和應(yīng)用 QLExpress,從而在項目中實現(xiàn)更高效、更靈活的規(guī)則管理。

責(zé)任編輯:武曉燕 來源: 碼猿技術(shù)專欄
相關(guān)推薦

2025-09-08 02:00:00

2025-02-04 11:30:10

2023-10-31 12:42:00

Spring動態(tài)增刪啟停

2025-07-17 10:30:11

2025-08-01 09:38:00

2025-11-10 03:10:00

2025-02-07 08:16:26

Java開發(fā)者代碼

2022-03-23 15:19:00

低代碼開源阿里巴巴

2025-06-23 00:00:05

2023-08-09 08:01:38

場景Redis接口

2015-09-28 14:27:12

硬編默認(rèn)選擇

2019-05-07 14:42:03

深度學(xué)習(xí)編程人工智能

2022-12-19 08:32:57

項目Feign框架

2025-06-03 08:20:00

Feign微服務(wù)

2021-01-18 06:43:54

程序員公務(wù)員996

2018-12-17 09:57:11

服務(wù)器LinuxBoot開源

2022-03-21 08:30:13

開源模型訓(xùn)練預(yù)測引擎

2021-06-11 10:53:40

Folly組件開發(fā)

2020-12-30 09:33:37

開源茅臺神器

2024-12-26 00:14:45

C#腳本開源
點贊
收藏

51CTO技術(shù)棧公眾號

在线视频亚洲一区| 97se亚洲国产综合自在线 | 日韩美女视频中文字幕| 久久久久久久毛片| 欧州一区二区三区| 欧美性猛交xxxx偷拍洗澡| 亚洲日本一区二区三区在线不卡| xxxx国产精品| 久久精品人人做人人爽电影蜜月| 久久亚洲国产成人| 91精品人妻一区二区| 欧美日韩破处视频| 午夜一区二区三区视频| 亚洲欧洲精品一区二区三区波多野1战4| 国产乱人乱偷精品视频| 久久电影一区| 欧美夫妻性视频| 99精品全国免费观看| 国产精品自在| 777奇米成人网| 欧美xxxxx在线视频| 超碰97国产精品人人cao| 国产欧美一区二区精品忘忧草| 国产精品免费一区二区| 91国产精品一区| 老色鬼久久亚洲一区二区| 欧美大尺度在线观看| 亚洲一二三四视频| 亚洲伊人春色| 日韩av在线高清| 粗大的内捧猛烈进出视频| jizzyou欧美16| 欧美日韩在线视频一区二区| 97超碰在线视| 黄色动漫在线观看| 国产精品久久一级| 视频一区二区三区在线观看| 午夜影院免费视频| 成人免费av资源| 99久久精品免费看国产一区二区三区 | 91精品国产91久久久久久吃药| 青花影视在线观看免费高清| 欧美熟乱15p| 亚洲网站视频福利| 少妇真人直播免费视频| 岳的好大精品一区二区三区| 亚洲第一中文字幕| 亚洲一区二区三区黄色| 91成人在线精品视频| 日韩欧美在线综合网| 人妻精品久久久久中文字幕69| 日韩美女在线| 91精品视频网| 69久久精品无码一区二区| 国产精品日本一区二区不卡视频| 欧美久久久久久久久| 亚洲免费999| 中文字幕日本一区| 91精品婷婷国产综合久久竹菊| 久久久精品高清| 91丨精品丨国产| 日韩久久久精品| 免费观看污网站| 久草在线综合| 亚洲欧美国产精品久久久久久久 | 亚洲午夜久久久久久久久电影网| 51xx午夜影福利| 欧美亚洲天堂| 欧美日韩午夜视频在线观看| 三级4级全黄60分钟| 在线成人视屏| 69久久99精品久久久久婷婷 | 欧美国产日产韩国视频| 精品99久久久久成人网站免费| 今天的高清视频免费播放成人| 午夜精品久久久久久久99热浪潮| 免费日韩一级片| 日本不卡视频在线| 亚洲va欧美va国产综合剧情| 乱精品一区字幕二区| 91原创在线视频| 日韩欧美视频一区二区| av中文在线| 亚洲精品国产第一综合99久久| 大地资源网在线观看免费官网| 黄视频在线免费看| 一本久久a久久精品亚洲| 亚洲综合欧美激情| 欧美一区一区| 亚洲人精品午夜在线观看| 免费成人美女女在线观看| 欧美视频导航| 日韩免费黄色av| 国产乱码精品一区二区三区精东| 99综合电影在线视频| 日本一区二区在线视频| 欧美6一10sex性hd| 日本精品视频一区二区三区| 天天操精品视频| 台湾亚洲精品一区二区tv| 视频直播国产精品| 好吊操这里只有精品| 看电视剧不卡顿的网站| 国产精品有限公司| 天堂а√在线资源在线| 狠狠色噜噜狠狠狠狠97| 污免费在线观看| 欧美女优在线视频| 久久久久久久久久久国产| 中文字幕日韩国产| 99精品在线免费| 欧美日韩视频免费在线观看| 自拍视频在线看| 欧美精品一区二区三区蜜臀| 99热99这里只有精品| 国产日韩一区| 国产精品一区二区av| 欧美18一19xxx性| 一本到不卡精品视频在线观看| 在线播放av网址| 亚洲a在线视频| 国产精品久久久久9999| 天天综合网天天综合| 亚洲女人****多毛耸耸8| 午夜精品在线免费观看| 网曝91综合精品门事件在线| 欧美激情伊人电影| 国产人妻精品一区二区三区| 国产精品欧美综合在线| 日本美女高潮视频| 亚洲精品国产setv| 欧美孕妇性xx| 亚洲av毛片成人精品| 亚洲成a人v欧美综合天堂下载| 手机看片国产精品| 欧美国产另类| 99久久精品免费看国产一区二区三区 | 国产精品自拍电影| 中文字幕亚洲不卡| 国产区二区三区| 国产探花一区| 日韩美女免费视频| 韩国三级在线观看久| 欧美日韩中文字幕日韩欧美| 最新在线黄色网址| 亚洲少妇一区| 免费中文日韩| 欧美大胆性生话| 亚洲色图国产精品| 亚洲高清视频免费观看| 久久美女高清视频| 可以在线看的黄色网址| 成人a'v在线播放| 国产综合福利在线| 污污的网站在线看| 亚洲成人国产精品| 波多野结衣视频网站| 久久久精品人体av艺术| 国产精品乱码久久久久| 日韩欧美高清在线播放| 91精品中文在线| 欧美videosex性欧美黑吊| 亚洲福利视频专区| 国产精品一区无码| 欧美国产日韩亚洲一区| 中文av一区二区三区| 久久精品久久久| 国产成人成网站在线播放青青| 福利在线导航136| 日韩经典第一页| 18国产免费视频| 亚洲免费观看高清完整版在线观看 | 亚洲av毛片成人精品| 一本一道久久a久久精品| 在线视频第一页| 国产麻豆精品95视频| 欧美日韩福利在线| 欧美日韩伦理| 成人在线观看91| 日韩欧美另类一区二区| 久久综合伊人77777| 韩国av永久免费| 91久久久免费一区二区| 玖玖爱这里只有精品| 99久久国产综合精品色伊| 午夜视频你懂的| 欧美视频不卡| 色之综合天天综合色天天棕色| 一本加勒比波多野结衣| 精品一级视频| 91av福利视频| 免费在线看黄色| 亚洲精品美女久久久| 在线观看国产精品视频| 亚洲成人一区在线| 黄色国产在线播放| 成人午夜视频网站| 日本 片 成人 在线| 在线国产欧美| 伊人天天久久大香线蕉av色| 青青操综合网| 亚洲一区二区久久久久久| 中老年在线免费视频| 久久精品影视伊人网| 青青草免费观看免费视频在线| 678五月天丁香亚洲综合网| 日本少妇毛茸茸高潮| 中文字幕亚洲不卡| 国产探花视频在线播放| 99久久精品免费看| 一级片免费在线观看视频| 久久精品女人天堂| 北条麻妃在线视频观看| 自拍偷拍欧美| 亚洲免费av网| 成人短片线上看| 蜜桃狠狠色伊人亚洲综合网站| 97视频一区| 亚洲精品女av网站| 日本成人在线网站| 国产成人精品在线播放| 理论片午夜视频在线观看| 美女av一区二区| 午夜免费福利在线观看| 亚洲天堂成人在线| 玖玖综合伊人| 亚洲精美色品网站| 欧美特黄一级视频| 日韩免费电影一区| aaaa一级片| 91精品国产色综合久久不卡蜜臀| 日韩乱码一区二区三区| 色老头久久综合| 天堂网一区二区三区| 亚洲福利一区二区| 久草免费新视频| 洋洋成人永久网站入口| 深夜福利影院在线观看| 亚洲男人的天堂在线观看| 中文字幕资源站| 国产精品理论在线观看| 东京热无码av男人的天堂| 国产精品人成在线观看免费 | 亚洲最大综合网| 久热精品视频| 日本男人操女人| 日韩黄色小视频| 久久久国产欧美| 免费一级片91| 亚洲精品综合在线观看| 精品在线亚洲视频| 亚洲制服中文字幕| 久草在线在线精品观看| 亚洲 国产 图片| 国产盗摄视频一区二区三区| 欧美激情一区二区三区p站| 成人午夜视频网站| 女同性恋一区二区三区| 99国产欧美久久久精品| 亚洲a v网站| 欧美激情在线一区二区三区| 99在线视频免费| 亚洲欧洲制服丝袜| 国产成人精品亚洲男人的天堂| 亚洲动漫第一页| 69视频免费在线观看| 在线视频一区二区免费| 国产精品九九九九| 日韩精品一区二区三区四区视频| 日本精品一区二区在线观看| 日韩成人中文字幕| www亚洲人| 欧美麻豆久久久久久中文| av老司机在线观看| 国产成人自拍视频在线观看| 久久精品国产精品亚洲毛片| 69堂成人精品视频免费| 日本欧美韩国国产| 亚洲欧美日韩精品综合在线观看| 自拍视频亚洲| 日韩黄色片视频| 国产一区二区三区高清播放| 国产情侣久久久久aⅴ免费| 国产午夜亚洲精品不卡| 欧美一区二区三区爽爽爽| 欧美日韩国产一中文字不卡| 中文字幕 亚洲视频| 欧美成人精品3d动漫h| 欧美日韩免费做爰大片| 两个人的视频www国产精品| 性爽视频在线| 91嫩草视频在线观看| 国产欧美日韩精品一区二区三区 | 亚洲美女网站18| 精品动漫一区| 91国内在线播放| 91日韩一区二区三区| √天堂中文官网8在线| 高跟丝袜一区二区三区| 国产视频一区二区三| 亚洲三级av在线| 97在线视频免费观看完整版| 国产在线视频91| 羞羞色国产精品网站| 久久久国内精品| 青青草国产成人av片免费| 国产精品入口麻豆| 综合精品久久久| 中文字幕 国产| 日韩精品视频在线免费观看| 国产福利视频在线观看| 国产精品欧美日韩一区二区| 久久影院资源站| av在线免费观看国产| 久久国产免费看| 手机看片福利视频| 日韩欧美高清视频| 手机在线不卡av| 久久99热精品| av一级久久| 亚洲三级一区| 老司机免费视频一区二区| 国产交换配乱淫视频免费| 午夜成人免费视频| 午夜精品在线播放| 麻豆国产精品va在线观看不卡| 国产精品久久久久久久久免费高清 | 日韩av自拍| 一级黄色香蕉视频| 久久久久久久久免费| 天天干天天干天天干天天| 亚洲精品电影在线观看| missav|免费高清av在线看| 成人免费视频网站入口| 欧美日韩91| 成人一区二区三区仙踪林| 一区二区在线观看视频| 99在线无码精品入口| 欧美成人精品一区二区| 精品视频国内| 国产精品免费看久久久无码| 极品销魂美女一区二区三区| 免费精品在线视频| 91精品国产乱| 直接在线观看的三级网址| 91在线播放国产| 午夜精品婷婷| 久久久久亚洲无码| 欧美日韩中文字幕日韩欧美| 九色在线视频蝌蚪| 国产精品久久久久一区二区| 日韩欧美大片| 欧美性受xxxx黒人xyx性爽| 亚洲欧美另类久久久精品| 午夜免费福利视频| 97视频在线观看播放| 少妇精品久久久| 日本国产一级片| 亚洲精品免费视频| 天天综合永久入口| 国产97在线|日韩| 91久久久精品国产| 免费看黄色片的网站| 懂色aⅴ精品一区二区三区蜜月| 免费在线超碰| 成人有码视频在线播放| 狠色狠色综合久久| 亚洲精品视频久久久| 欧美三级视频在线| 少女频道在线观看高清 | 黄色在线免费播放| 日韩欧美在线观看| 日本中文字幕在线视频| 97人人澡人人爽| 久久福利一区| 青青青在线免费观看| 日韩经典第一页| 亚洲精品大全| 全黄性性激高免费视频| 久久精品人人做人人爽人人| 国产精品热久久| 欧美亚洲一级片| 99久久精品费精品国产风间由美| av不卡中文字幕| 91福利视频久久久久| 中文字幕在线观看网站| 欧美三级网色| 国产精品资源在线看| 亚洲GV成人无码久久精品| www.久久色.com| 秋霞在线一区| 亚洲一二三av| 欧美性猛交xxxx黑人猛交| 超碰公开在线| 亚洲bbw性色大片| 91免费视频大全| 亚洲国产精品久久久久久久| 国产大片精品免费永久看nba| 欧美日韩一区二区三区四区在线观看| 99久久久无码国产精品衣服|