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”);
然后后台直接執行
- 首先我們實現一個方法,用於動態加載函數
//動態加載方法
//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);
}
- 然后編寫測試用例:
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相比,我們省去了修改表達式的步驟