java利用JEXL實現(xiàn)動態(tài)表達式編譯
背景
做項目突然遇到這樣的需求:
系統(tǒng)要獲取多個數(shù)據(jù)源的數(shù)據(jù),并進行處理,最后輸出多個字段。字段的計算規(guī)則一般是簡單的取值最多加一點條件判斷。
而且需要動態(tài)變動?。±缫粋€字段a的取值,如果a > 10的時候輸出10,a <= 10則輸出a。這里的10可能在一天后改成8,也可能在后天就改成了12。當然,如果只是一個數(shù)字的變動還好說,我們可以使用數(shù)據(jù)庫進行存儲。但是,萬一哪天需求突然變成了a < 10的時候輸出10,a >=10 則輸出a,就需要對代碼改動,再測試再發(fā)布才能到生產(chǎn)環(huán)境使用。
一兩個這樣的字段還沒什么,如果整個系統(tǒng)所依賴的字段都有這樣的屬性,那么我們就需要找一種方法來實現(xiàn)動態(tài)的加載邏輯。
下面介紹的JEXL就可以解決這種問題
JEXL(Java Expression Language)介紹
JEXL – Apache Commons JEXL Overview
下面用一些實例來介紹JEXL的使用方法
實例
maven依賴:
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-jexl</artifactId> <version>2.0</version> </dependency>
正則表達式匹配
首先寫一個公共方法:
public class Util { public static boolean regMatch(String regEx, String str) { Pattern pattern = Pattern.compile(regEx); return pattern.matcher(str).matches(); } }
下面是使用JEXL調(diào)用的方法
public void RL() { JexlContext jc = new MapContext(); String str = "一二三四五六七八九十"; jc.set("Util", new Util()); jc.set("str", str); jc.set("ans", ""); String expression = "ans = Util.regMatch(\"[\u4e00-\u9fa5]{10,}\",str)"; Expression e = new JexlEngine().createExpression(expression); e.evaluate(jc); System.out.println(jc.get("ans")); }
代碼中的expression變量就是可以動態(tài)編譯的表達式,這里要注意表達式中出現(xiàn)的所有變量,都需要事先set進JexlContext中,否則會報錯。這里有多種形式的錯誤:
①如果沒有set”Util”,程序運行中會拋出異常。
org.apache.commons.jexl2.JexlException: TmpTest.RL@40![13,40]: 'ans = QeUtil.regMatch('[一-龥]{10,}', str);' attempting to call method on null
②如果沒有set”str”,程序不會拋出異常,并輸出null。如果你的regMatch方法中有判空處理,就會輸出判空的結(jié)果。如果沒有判空處理,在控制臺的輸出如下:
警告: TmpTest.RL@39![36,39]: 'ans = QeUtil.regMatch('[一-龥]{10,}', str);' undefined variable str
二月 21, 2017 4:00:41 下午 org.apache.commons.jexl2.JexlEngine invocationFailed
警告: TmpTest.RL@39![13,40]: 'ans = QeUtil.regMatch('[一-龥]{10,}', str);' method invocation error
java.lang.NullPointerException
③如果沒有set”ans”,程序會正常運行,并輸出正確值
為了保險起見,建議表達式中出現(xiàn)的所有變量,都需要事先set進JexlContext中
循環(huán)
JEXL支持兩種循環(huán)方式:
for(item : list) { x = x + item; }
和
while (x lt 10) { x = x + 2; }
下面是使用while的實例:
public void loop() { JexlContext jc = new MapContext(); jc.set("a", 1); jc.set("b", "0"); jc.set("ans", new StringBuffer()); Expression e = new JexlEngine().createExpression("while (a < 10) {a = a + 1;ans.append(b);}"); e.evaluate(jc); System.out.println(jc.get("ans")); }
get\set方法調(diào)用
JEXL支持傳入對象,并調(diào)用對象的方法
下面的簡單的get\set方法的實例:
public void getSet() { TmpTest tmpTest = new TmpTest(); tmpTest.setA(1); JexlContext jc = new MapContext(); jc.set("tmpTest", tmpTest); jc.set("ans", ""); Expression e = new JexlEngine().createExpression("ans = tmpTest.getA()"); e.evaluate(jc); System.out.println(jc.get("ans")); e = new JexlEngine().createExpression("ans = tmpTest.setA(2)"); e.evaluate(jc); TmpTest tmpTest1 = (TmpTest) jc.get("tmpTest"); System.out.println(tmpTest1.getA()); }
上面的用例會在控制臺先輸出1,再輸出2
下面是其他網(wǎng)友的評論
ScriptEngine比這個方便n倍,能動態(tài)執(zhí)行js function,了解一下
相關(guān)文章
Spring AI 使用本地 Ollama Embeddings的操作方法
使用 OpenAI 的 Embeddings 接口是有費用的,如果想對大量文檔進行測試,使用本地部署的 Embeddings 就能省去大量的費用,所以我們嘗試使用本地的 Ollama Embeddings,這篇文章主要介紹了Spring AI 使用本地 Ollama Embeddings,需要的朋友可以參考下2024-05-05SpringBoot+Vue實現(xiàn)EasyPOI導(dǎo)入導(dǎo)出的方法詳解
項目開發(fā)過程中,很大的需求都有 導(dǎo)入導(dǎo)出功能。本文將利用SpringBoot+Vue實現(xiàn)EasyPOI導(dǎo)入導(dǎo)出功能,感興趣的可以了解一下2022-08-08Serializable接口的作用_動力節(jié)點Java學(xué)院整理
這篇文章主要為大家詳細介紹了java中Serializable接口的作用,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-05-05java集合_淺談Iterable和Iterator的區(qū)別
下面小編就為大家?guī)硪黄猨ava集合_淺談Iterable和Iterator的區(qū)別。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-09-09

懶人 IDEA 插件推薦: EasyCode 一鍵幫你生成所需代碼(Easycode用法)

JAVA簡單鏈接Oracle數(shù)據(jù)庫 注冊和登陸功能的實現(xiàn)代碼