背景:
最近上頭讓研究各種物流的運費計算,並獲取最優配送物流方案,無意之間搜索到了QLExpress,它是阿里的一個組件,一種規則引擎的算法,QLExpress在阿里集團內部有很強的影響力,被廣泛應用在電商場景中,在業務靈活多變的場景下常常需要規則引擎的支持。所以我就動手自己實現了一下
GitHub地址:https://github.com/alibaba/QLExpress
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
前端監控:www.webfunny.cn ;只需要簡單幾步,就可以搭建一套屬於自己的前端監控系統,快來試試吧。(github:webfunny_monitor)
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1、優勢
QLExpress腳本引擎被廣泛應用在阿里的電商業務場景,具有以下的一些特性:
1、線程安全,引擎運算過程中的產生的臨時變量都是threadlocal類型。
2、高效執行,比較耗時的腳本編譯過程可以緩存在本地機器,運行時的臨時變量創建采用了緩沖池的技術,和groovy性能相當。
3、弱類型腳本語言,和groovy,javascript語法類似,雖然比強類型腳本語言要慢一些,但是使業務的靈活度大大增強。
4、安全控制,可以通過設置相關運行參數,預防死循環、高危系統api調用等情況。
5、代碼精簡,依賴最小,250k的jar包適合所有java的運行環境,在android系統的低端pos機也得到廣泛運用。
2、引入依賴的jar
<!-- QLExpress -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>QLExpress</artifactId>
<version>${qlexpress.version}</version>
</dependency>
<qlexpress.version>3.2.0</qlexpress.version>
用到的版本是3.2.0
3、語法
操作符和java對象操作
//支持 +,-,*,/,<,>,<=,>=,==,!=,<>【等同於!=】,%,mod【取模等同於%】,++,--,
//in【類似sql】,like【sql語法】,&&,||,!,等操作符
//支持for,break、continue、if then else 等標准的程序控制邏輯
n=10;
for(sum=0,i=0;i<n;i++){
sum=sum+i;
}
return sum;
//邏輯三元操作
a=1;
b=2;
maxnum = a>b?a:b;
和java語法相比,要避免的一些ql寫法錯誤
不支持try{}catch{}
不支持java8的lambda表達式
不支持for循環集合操作for (GRCRouteLineResultDTO item : list)
弱類型語言,請不要定義類型聲明,更不要用Templete(Map<String,List>之類的)
array的聲明不一樣
min,max,round,print,println,like,in 都是系統默認函數的關鍵字,請不要作為變量名
QL用法:
是否符合 = 1;運費 = 0;如果 (30 < 重量 ) 則
{ 是否符合 = 0; return 是否符合;}
最長邊 = 長 > 寬 ? 長 : 寬;
最長邊 = 最長邊 > 高 ? 最長邊 : 高;
最短邊 = 長 < 寬 ? 長 : 寬;
最短邊 = 最短邊 < 高 ? 最短邊 : 高;
中間邊 = (長 + 寬 + 高) - 最長邊 - 最短邊;
圍長 = (中間邊 + 最短邊) * 2 + 最長邊;
如果 (圍長 > 300) 則
{ 是否符合 = 0; return 是否符合;}
如果 (最長邊 > 175) 則
{ 是否符合 = 0; return 是否符合;}
java代碼調用:
public class DPDRuleTest {
@Test
public void DPDRuleTest() throws Exception {
List<String> ruleFileNames = new ArrayList<String>();
ruleFileNames.add("rule/GB/DPD/DPD_UK.ql");
for (int i = 0; i < ruleFileNames.size(); i++) {
String script = getResourceAsStream(ruleFileNames.get(i));
ExpressRunner runner = new ExpressRunner(false, false);
runner.addOperatorWithAlias("如果", "if", null);
runner.addOperatorWithAlias("則", "then", null);
runner.addOperatorWithAlias("否則", "else", null);
IExpressContext<String, Object> context = new DefaultContext<String, Object>();
try {
context.put("長", 20);
context.put("寬", 20);
context.put("高", 20);
context.put("重量", 10);
context.put("COUNTRY","IS");
runner.execute(script, context, null, true, false);
if (String.valueOf(context.get("是否符合")).equals("1")) {
System.out.println("文件名稱:" + ruleFileNames.get(i));
System.out.println("最長邊:" + context.get("最長邊"));
System.out.println("中間邊:" + context.get("中間邊"));
System.out.println("最短邊:" + context.get("最短邊"));
System.out.println("是否符合:" + context.get("是否符合"));
System.out.println("運費:" + context.get("運費")); }
} catch (Exception e) {
e.printStackTrace();
//Assert.assertTrue(e.toString().contains("at line 7"));
}
}
}
public static String getResourceAsStream(String path) throws Exception {
InputStream in = Thread.currentThread().getContextClassLoader()
.getResourceAsStream(path);
if (in == null) {
throw new Exception("classLoader中找不到資源文件:" + path);
}
BufferedReader reader = new BufferedReader(new InputStreamReader(in, "utf-8"));
StringBuilder builder = new StringBuilder();
String tmpStr = null; w
hile ((tmpStr = reader.readLine()) != null) {
builder.append(tmpStr).append("\n");
}
reader.close();
in.close();
return builder.toString();
}
}
各種規則定義QL:
規則ql文件
也可以把這些規則全都放到數據庫字段里面保存起來,並且頁面化,進行可配置操作,達到方便配置的效果。
如下就是我們項目中一個規則引擎表設計:
規則表
freight_rule:保存各種規則。
到此我們的規則引擎已經達到了業務需求,后期准備在進行擴展。
-----------------------------------------------------------------------------------------------------------------------------------
前端監控:www.webfunny.cn ;只需要簡單幾步,就可以搭建一套屬於自己的前端監控系統,快來試試吧。(github:webfunny_monitor)
-----------------------------------------------------------------------------------------------------------------------------------
————————————————
版權聲明:本文為CSDN博主「簡簡單單就是我_hehe」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/yulei0524/article/details/107248709