jexl2 报错 JexlException 的解决方法

今天,在做功能的时候,遇到一个问题。

xml文件中有配置限制条件,例如:

<CONDITION TYPE="range$in" 
PARASNAME="userlevel$department" 
EXPRESSION="(userlevel) and (department)">
    [0,4]$[开发部][测试部]
</CONDITION>

其中,PARASNAME 中配置的是变量名称; TYPE用来描述变量和值的关系;EXPRESSION 是各个变量的逻辑关系。

需要实现这样一个功能:

根据前台传入的变量值,以及EXPRESSION中配置的表达式的逻辑关系,计算出当前情况是否满足条件,然后返回一个结果。

初步想法是,把 EXPRESSION 中的内容按如下规则进行替换:
变量–>变量和值的关系
and –>&&

就像这样:

(userlevel>=0&&userlevel<=4)&&
([开发部][测试部].indexOf(department)>0)

但问题是,替换之后的表达式如何执行呢?


通过查询,还真有可以执行表达式的方法。一般通过jexl2 方式。

首先引入jar包:

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

其次,写好执行表达式的函数:

/*
    exp:表达式字符串
    map:表达式中的变量和值
*/
public static Object exeExpression(String exp,Map<String,Object> map){  
        JexlEngine jexl=new JexlEngine();  
        Expression e = jexl.createExpression(exp);
        JexlContext jc = new MapContext();  
        for(String key:map.keySet()){//copy一下参数Map到JexlContext
            jc.set(key, map.get(key));  
        }  
        if(e.evaluate(jc)==null){  
            return "";  
        }  
        return e.evaluate(jc);  
    }  
}

调用方法:

Map<String,Object> map=new HashMap<String,Object>(); 
map.put("userlevel","1"); 
map.put("department","aaa");  
String expression=
"(userlevel>=0&&userlevel<=4)&&([开发部][测试部].indexOf(department)>0)"; 
Object code = convertToCode(expression,map);
System.out.println(""+code);

执行函数报错:

Exception in thread "main" org.apache.commons.jexl2.JexlException: com.test.TestReg.convertToCode@37tokenization failed
    at org.apache.commons.jexl2.JexlEngine.parse(JexlEngine.java:816)
    at org.apache.commons.jexl2.JexlEngine.createExpression(JexlEngine.java:380)
    at org.apache.commons.jexl2.JexlEngine.createExpression(JexlEngine.java:364)
    at com.test.TestReg.convertToCode(TestReg.java:37)
    at com.test.TestReg.main(TestReg.java:20)
Caused by: org.apache.commons.jexl2.parser.TokenMgrError: Lexical error at line 1, column 32.  Encountered: "\u5f00" (24320), after : ""
    at org.apache.commons.jexl2.parser.ParserTokenManager.getNextToken(ParserTokenManager.java:1564)

看提示的意思是有汉字,哦,忘记了给字符串加引号了。

又改成如下:

String expression="(userlevel>=0&&userlevel<=4)&&(\"[开发部][测试部]\".indexOf(department)>0)"; 

还是报同样的错误。

后来换了个思路,把这些常量放到放到变量Map里。

map.put("depart","[开发部][测试部]");  
String expression="(userlevel>=0&&userlevel<=4)&&(depart.indexOf(department)>0)"; 

输出结果:

false

问题解决,原来jexl2表达式不支持字符串常量。
通过研究 jexl2官网 发现:

1.构建参数值的Map可以优化一下,简化代码:
这里写图片描述

/*
    exp:表达式字符串
    map:表达式中的变量和值
*/
public static Object exeExpression(String exp,Map<String,Object> map){  
        JexlEngine jexl=new JexlEngine();  
        Expression e = jexl.createExpression(exp);
        JexlContext jc = new MapContext(map);  
        if(e.evaluate(jc)==null){  
            return "";  
        }  
        return e.evaluate(jc);  
    }  
}

2 创建JEXL engine时,最好用单例模式。(可能是3.0版本才支持)
这里写图片描述

 private static final JexlEngine jexl = 
 new JexlBuilder.cache(512).strict(true).silent(false).create();

猜你喜欢

转载自blog.csdn.net/h517604180/article/details/80764436