App下載

Java如何使用JEXL實(shí)現(xiàn)動(dòng)態(tài)表達(dá)式編譯 附實(shí)例代碼

猿友 2021-08-03 17:07:46 瀏覽數(shù) (4972)
反饋

JEXL 是 Java 編程語(yǔ)言中一種表達(dá)式語(yǔ)言引擎,可以用來(lái)校驗(yàn)數(shù)據(jù)等。那么 Java 具體是怎么使用JEXL這個(gè)引擎的?下面,我將通過 Java 實(shí)例代碼為大家展示 Java 是如何用 JEXL 引擎實(shí)現(xiàn)動(dòng)態(tài)表達(dá)式編譯。

背景

做項(xiàng)目突然遇到這樣的需求:
系統(tǒng)要獲取多個(gè)數(shù)據(jù)源的數(shù)據(jù),并進(jìn)行處理,最后輸出多個(gè)字段。字段的計(jì)算規(guī)則一般是簡(jiǎn)單的取值最多加一點(diǎn)條件判斷。
而且需要?jiǎng)討B(tài)變動(dòng)?。±缫粋€(gè)字段a的取值,如果a > 10的時(shí)候輸出10,a <= 10則輸出a。這里的10可能在一天后改成8,也可能在后天就改成了12。當(dāng)然,如果只是一個(gè)數(shù)字的變動(dòng)還好說,我們可以使用數(shù)據(jù)庫(kù)進(jìn)行存儲(chǔ)。但是,萬(wàn)一哪天需求突然變成了a < 10的時(shí)候輸出10,a >=10 則輸出a,就需要對(duì)代碼改動(dòng),再測(cè)試再發(fā)布才能到生產(chǎn)環(huán)境使用。
一兩個(gè)這樣的字段還沒什么,如果整個(gè)系統(tǒng)所依賴的字段都有這樣的屬性,那么我們就需要找一種方法來(lái)實(shí)現(xiàn)動(dòng)態(tài)的加載邏輯。
下面介紹的JEXL就可以解決這種問題

JEXL(Java Expression Language)介紹

JEXL – Apache Commons JEXL Overview

下面用一些實(shí)例來(lái)介紹JEXL的使用方法

實(shí)例

maven依賴:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-jexl</artifactId>
    <version>2.0</version>
</dependency>

正則表達(dá)式匹配

首先寫一個(gè)公共方法:

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變量就是可以動(dòng)態(tài)編譯的表達(dá)式,這里要注意表達(dá)式中出現(xiàn)的所有變量,都需要事先set進(jìn)JexlContext中,否則會(huì)報(bào)錯(cuò)。這里有多種形式的錯(cuò)誤:

①如果沒有set”Util”,程序運(yùn)行中會(huì)拋出異常。

org.apache.commons.jexl2.JexlException: TmpTest.RL@40![13,40]: 'ans = QeUtil.regMatch('[一-龥]{10,}', str);' attempting to call method on null

②如果沒有set”str”,程序不會(huì)拋出異常,并輸出null。如果你的regMatch方法中有判空處理,就會(huì)輸出判空的結(jié)果。如果沒有判空處理,在控制臺(tái)的輸出如下:

警告: 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”,程序會(huì)正常運(yùn)行,并輸出正確值
為了保險(xiǎn)起見,建議表達(dá)式中出現(xiàn)的所有變量,都需要事先set進(jìn)JexlContext中

循環(huán)

JEXL支持兩種循環(huán)方式:

for(item : list) {
    x = x + item;
}

while (x lt 10) {
    x = x + 2;
}

下面是使用while的實(shí)例:

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"));
}

getset方法調(diào)用

JEXL支持傳入對(duì)象,并調(diào)用對(duì)象的方法
下面的簡(jiǎn)單的getset方法的實(shí)例:

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());
}

上面的用例會(huì)在控制臺(tái)先輸出1,再輸出2

以上就是關(guān)于 Java 使用 JEXL 引擎實(shí)現(xiàn)動(dòng)態(tài)表達(dá)式的編譯的全部?jī)?nèi)容,想要了解更多關(guān)于 Java JEXL 引擎的詳細(xì)內(nèi)容,可以搜素W3Cschool站內(nèi)相關(guān)技術(shù)文章。

0 人點(diǎn)贊