一個輕量級的類java語法規則引擎,做爲一個嵌入式規則引擎在業務系統中使用。讓業務規則定義簡便而不失靈活。讓業務人員就能夠定義業務規則。支持標準的JAVA語法,還能夠支持自定義操做符號、操做符號重載、函數定義、宏定義、數據延遲加載等。java
QLExpress在阿里集團內部有很強的影響力,被普遍應用在電商場景中,在業務靈活多變的場景下經常須要規則引擎的支持。git
官方地址爲:github.com/alibaba/QLE…github
項目已經給了不少的使用案例,可是若是不親自運行一下,不容易體會到其用法與強大之處,本次主要給一個QLExpress的運行案例,能夠真正的跑起來官方給的各類案例代碼。express
說明:數組
/**
* 執行一段文本
* @param expressString 程序文本
* @param context 執行上下文,執行上下文在執行的過程當中會產生中間數據,上下文不要重複使用
* @param errorList 輸出的錯誤信息List
* @param isCache 是否使用Cache中的指令集
* @param isTrace 是否輸出詳細的執行指令信息
* @return
* @throws Exception
*/
public Object execute(String expressString, IExpressContext<String,Object> context,
List<String> errorList, boolean isCache, boolean isTrace) throws Exception {
return this.execute(expressString, context, errorList, isCache, isTrace, null);
}
複製代碼
運行案例:bash
package me.aihe.demo.qlexpress;
import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;
import com.ql.util.express.IExpressContext;
import com.ql.util.express.Operator;
import java.util.HashMap;
public class QLExpressionDemo {
public static void main(String[] args) throws Exception {
ExpressRunner runner = new ExpressRunner();
// getStarted(runner);
// basicStatement(runner);
// collectionStatement(runner);
// objectStatement(runner);
// functionStatement(runner);
// macronStatement(runner);
// workWithJavaStatement(runner);
// extendOperatorStatement(runner);
customOperatorStatement(runner);
}
/**
* 自定義操做符的使用
* @param runner
*/
private static void customOperatorStatement(ExpressRunner runner) throws Exception {
class JoinOperator extends Operator {
public Object executeInner(Object[] list) throws Exception {
Object opdata1 = list[0];
Object opdata2 = list[1];
if(opdata1 instanceof java.util.List){
((java.util.List)opdata1).add(opdata2);
return opdata1;
}else{
java.util.List result = new java.util.ArrayList();
result.add(opdata1);
result.add(opdata2);
return result;
}
}
}
// 返回結果 [1, 2, 3]
//(1)addOperator
DefaultContext<String, Object> context = new DefaultContext<String, Object>();
runner.addOperator("join",new JoinOperator());
Object r = runner.execute("1 join 2 join 3", context, null, false, false);
System.out.println(r);
// (2) addFunction
// 返回結果:[1 , 2 ]
runner.addFunction("joinfunc",new JoinOperator());
r = runner.execute("joinfunc(1,2,3)", context, null, false, false);
System.out.println(r);
//(3)replaceOperator
// 返回結果 [1, 2, 3]
runner.replaceOperator("+",new JoinOperator());
r = runner.execute("1 + 2 + 3", context, null, false, false);
System.out.println(r);
}
/**
* 操做符處理,通常不太經常使用,但能夠自定義一些操做符
* @param runner
*/
private static void extendOperatorStatement(ExpressRunner runner) throws Exception {
runner.addOperatorWithAlias("若是", "if",null);
runner.addOperatorWithAlias("則", "then",null);
runner.addOperatorWithAlias("不然", "else",null);
IExpressContext<String, Object> context =new DefaultContext<String, Object>();
context.put("語文", 88);
context.put("數學", 99);
context.put("英語", 95);
String exp = "若是 (語文+數學+英語>270) 則 {return 1;} 不然 {return 0;}";
// DefaultContext<String, Object> context = new DefaultContext<String, Object>();
Object result = runner.execute(exp, context, null, false, false, null);
System.out.println(result);
}
/**
* 將Java中已經寫好的一些方法,綁定到咱們自定義的變量上,在業務中最經常使用的部分。
* @param runner
*/
private static void workWithJavaStatement(ExpressRunner runner) throws Exception {
// 在使用的時候會建立對象
runner.addFunctionOfClassMethod("取絕對值", Math.class.getName(), "abs",
new String[] { "double" }, null);
// 對象已經存在,直接調用對象中的方法
runner.addFunctionOfServiceMethod("打印", System.out, "println",new String[] { "String" }, null);
String exp = "a=取絕對值(-100);打印(\"Hello World\");打印(a.toString())";
DefaultContext<String, Object> context = new DefaultContext<>();
runner.execute(exp, context,null,false,false);
System.out.println(context);
}
/**
* Macro定義, 即預先定義一些內容,在使用的時候直接替換Macro中的變量爲上下文的內容
* @param runner
*/
private static void macronStatement(ExpressRunner runner) throws Exception {
runner.addMacro("計算平均成績", "(語文+數學+英語)/3.0");
runner.addMacro("是否優秀", "計算平均成績>90");
IExpressContext<String, Object> context =new DefaultContext<String, Object>();
context.put("語文", 88);
context.put("數學", 99);
context.put("英語", 95);
Object result = runner.execute("是否優秀", context, null, false, false);
System.out.println(result);
}
/**
* 自定義在QLexpress中的函數
* 通常語句的最後一句話是返回結果
* @param runner
*/
private static void functionStatement(ExpressRunner runner) throws Exception {
String functionStatement = "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" +
"add(a,4) + sub(a,9);";
Object result = runner.execute(functionStatement, new DefaultContext<>(), null, false, false);
// runner.execute(functionStatement, new DefaultContext<>(), null, true, false, 1000);
System.out.println(result);
}
/**
* 對Java對象的操做
* 系統自動會import java.lang.*,import java.util.*;
* @param runner
*/
private static void objectStatement(ExpressRunner runner) throws Exception {
// TradeEvent tradeEvent = new TradeEvent();
// tradeEvent.setPrice(20.0);
// tradeEvent.setName("購物");
// tradeEvent.setId(UUID.randomUUID().toString());//
//
String objectStatement = "import me.aihe.demo.trade.TradeEvent;\n" +
" tradeEvent = new TradeEvent();\n" +
" tradeEvent.setPrice(20.0);\n" +
" tradeEvent.id=UUID.randomUUID().toString();\n" +
" System.out.println(tradeEvent.getId());\n" +
" System.out.println(tradeEvent.price);";
runner.execute(objectStatement, new DefaultContext<>(), null, false, false);
}
/**
* 在定義集合,數組相關的操做,ql有本身的語法,不能簡單的使用Java語法
* //java語法:使用泛型來提醒開發者檢查類型
* keys = new ArrayList<String>();
* deviceName2Value = new HashMap<String,String>(7);
* String[] deviceNames = {"ng","si","umid","ut","mac","imsi","imei"};
* int[] mins = {5,30};
*
* //ql寫法:
* keys = new ArrayList();
* deviceName2Value = new HashMap();
* deviceNames = ["ng","si","umid","ut","mac","imsi","imei"];
* mins = [5,30];
*
*
* //java語法:對象類型聲明
* FocFulfillDecisionReqDTO reqDTO = param.getReqDTO();
* //ql寫法:
* reqDTO = param.getReqDTO();
*
* //java語法:數組遍歷
* for(GRCRouteLineResultDTO item : list) {
* }
* //ql寫法:
* for(i=0;i<list.size();i++){
* item = list.get(i);
* }
*
* //java語法:map遍歷
* for(String key : map.keySet()) {
* System.out.println(map.get(key));
* }
* //ql寫法:
* keySet = map.keySet();
* objArr = keySet.toArray();
* for (i=0;i<objArr.length;i++) {
* key = objArr[i];
* System.out.println(map.get(key));
* }
* @param runner
*/
private static void collectionStatement(ExpressRunner runner) throws Exception {
DefaultContext<String, Object> defaultContext = new DefaultContext<>();
HashMap<String, String> mapData = new HashMap(){{
put("a","hello");
put("b","world");
put("c","!@#$");
}};
defaultContext.put("map",mapData);
//ql不支持for(obj:list){}的語法,只能經過下標訪問。
String mapTraverseStatement = " 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(mapTraverseStatement,defaultContext,null,false,false);
System.out.println(defaultContext);
// 集合的快捷寫法
/**
* ExpressRunner runner = new ExpressRunner(false,false);
* DefaultContext<String, Object> context = new DefaultContext<String, Object>();
* String express = "abc = NewMap(1:1,2:2); return abc.get(1) + abc.get(2);";
* Object r = runner.execute(express, context, null, false, false);
* System.out.println(r);
* express = "abc = NewList(1,2,3); return abc.get(1)+abc.get(2)";
* r = runner.execute(express, context, null, false, false);
* System.out.println(r);
* express = "abc = [1,2,3]; return abc[1]+abc[2];";
* r = runner.execute(express, context, null, false, false);
* System.out.println(r);
*/
}
/**
* 語法基本說明:
* 不支持try{}catch{}
* 不支持java8的lambda表達式
* 不支持for循環集合操做for (GRCRouteLineResultDTO item : list)
* 弱類型語言,請不要定義類型聲明
* 不要用Templete(Map<String,List>之類的)
* array的聲明不同
* min,max,round,print,println,like,in 都是系統默認函數的關鍵字,請不要做爲變量名
* @param runner
*/
private static void basicStatement(ExpressRunner runner) throws Exception {
DefaultContext<String, Object> defaultContext = new DefaultContext<>();
// defaultContext.put("n",10); //直接從Java中傳遞上下文等於在表達式中傳遞上下文
String loopStatement = "sum=0;n=10;" +
"for(i=0;i<n;i++){\n" +
"sum=sum+i;\n" +
"}\n" +
"return sum;";
Object result = runner.execute(loopStatement, defaultContext, null, false, false);
System.out.println(result);
// 注意使用同一個defaultContext,上一步語句執行的中間變量會被傳遞到下一個語句中
String maxmiumStatement = "a=1;\n" +
"b=2;\n" +
"maxnum = a>b?a:b;";
result = runner.execute(maxmiumStatement, defaultContext, null, false, false);
System.out.println(result);
}
// 入門展現express使用部分
private static void getStarted(ExpressRunner runner) throws Exception {
DefaultContext<String, Object> context = new DefaultContext<String, Object>();
context.put("a",1);
context.put("b",2);
context.put("c",3);
String express = "a+b*c";
Object r = runner.execute(express, context, null, true, true);
System.out.println(r);
}
}
複製代碼
綁定java類或者對象的method,在業務中常常用到,能夠重點關注,其他的親自跑一下看看運行效果。dom
參考:函數