Jexl表達式引擎-根據字符串動態執行JAVA


Table of Contents generated with DocToc

一、使用場景

在做某些項目的時候,有時會遇到如下情景:

用戶需要傳入某個JAVA 表達式,然后后台將這個表達式當作JAVA代碼執行


二、市面上表達式引擎比較

我們有許多表達式引擎可供選擇:

  • Jexl
  • Aviator

2.1 Aviator

avitor具體使用技巧可以參考這篇博客:https://blog.csdn.net/keda8997110/article/details/50782848

avitor可以滿足基本的表達式的判斷,但對於對象中的函數調用明顯力不從心,如果碰到以下業務情景:

用戶傳入的java表達式是:user.getName().equals(“123456”);

這個表達式是調用user對象里的getName方法,然后再掉用equals方法,判斷是否等於字符串123456,avitor對於調用對象的方法這個問題也有自己的解決方法:

User user = new User("123456");

//首先要注入User的類
AviatorEvaluator.addInstanceFunctions("user", User.class);

//再使用aviator特定的表達式運行方法: namespace.method(instance, args)
AviatorEvaluator.execute("User.getName(user)=='123456'")

這樣太麻煩了,雖然程序可以事先將需要的類注入到AviatorEvaluator引擎中,但是我們還需要將熟悉的java表達式轉化為Aviator需要的表達式形式。

那我們有沒有可以直接執行java代碼的呢?有!

2.2 Jexl

我們在maven中使用 Jexl 需要導入如下依賴:

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-jexl -->
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-jexl</artifactId>
  <version>2.1.1</version>
</dependency>

然后看我們的 Jexl 如何實現業務:

用戶傳入的java表達式是:user.getName().equals(“123456”);
然后后台直接執行

  1. 首先我們實現一個方法,用於動態加載函數
//動態加載方法
//jexlExp -- java表達式
//map -- 運行環境
private Object invokeMethod(String jexlExp, Map<String,Object> map){
    JexlEngine jexl=new JexlEngine();
    Expression e = jexl.createExpression(jexlExp);
    JexlContext jc = new MapContext();
    for(String key:map.keySet()){
        jc.set(key, map.get(key));
    }
    if(null==e.evaluate(jc)){
        return "";
    }
    return e.evaluate(jc);
}
  1. 然后編寫測試用例:
pubic class User{
    String name = "123456";
    public User(String name){
        this.name = name;
    }
    public String getName(){
        return name;
    }
}
public class JexlTest {

    private Map<String, Object> env;

    //注入測試環境,將變量形成一個map<對象名,對象>
    @Before
    public void before(){
        env = new HashMap<>();
        env.put("id","123456");
        env.put("user",new User());
    }

    //動態加載方法
    private Object invokeMethod(String jexlExp, Map<String,Object> map){
        JexlEngine jexl=new JexlEngine();
        Expression e = jexl.createExpression(jexlExp);
        JexlContext jc = new MapContext();
        for(String key:map.keySet()){
            jc.set(key, map.get(key));
        }
        if(null==e.evaluate(jc)){
            return "";
        }
        return e.evaluate(jc);
    }


    //調用Jexl執行引擎
    @Test
    public void TestFunctionMethod(){
        String expression="user.getId().equals(id)";
        boolean res = (boolean) invokeMethod(expression,env);
        Assert.assertTrue(res);
    }
}

執行結果為true

與Aviator相比,我們省去了修改表達式的步驟


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM