写在前面
设想一个这样的问题:如果前端通过拼接生成了一个判断语句: age > 0,
那么传递到后端,肯定是用String类型来存储:
String test = "age > 0";
那么我想执行前端传递过来的判断条件该怎么办呢?
表达式语言引擎:Apache Commons JEXL
这里展示了一个工具类
import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.JexlEngine;
import org.apache.commons.jexl2.MapContext;
import java.util.Map;
/**
* 这个工具类是为了能够把字符串当作java代码来执行
*/
public class ExecuteStringAsCodeUtils {
/**
* 这个方法能够将字符串当作java代码来执行
* @param express
* @return
*/
public Object executeString(String express, Map<String,Object> parameter) {
JexlEngine jexlEngine = new JexlEngine();
Expression expression = jexlEngine.createExpression(express);//将参数中的字符串传进来
JexlContext jexlContext = new MapContext();
for(String key:parameter.keySet()) {//遍历传过来的参数
jexlContext.set(key,parameter.get(key));//将传进来的参数替换到表达式中去
}
if(null == expression.evaluate(jexlContext)) {//执行表达式
return "";//为空就返回空字符串
}
return expression.evaluate(jexlContext);//执行表达式,返回结果
}
}
调用方式:
//创建工具类
ExecuteStringAsCodeUtils tool = new ExecuteStringAsCodeUtils();
String condition = "age > 0";
int age = 1;
Map<String,Object> map=new HashMap<String,Object>();
map.put("age",age);
boolean res = (boolean)tool.executeString(condition,map);
System.out.println(res);
提取字符串表达式的变量名
问题描述:
在字符串 "age > 3 || ‘zhangsan’.equals(name) "中,age,name是变量名,考虑将变量名提取出来
为什么有这个想法:
我们发现,如果HashMap中没有age或者name的变量名时,执行就会报错,因此设计一个方法,用来提取字符串表达式中包含的变量名
大致代码如下:
import java.util.*;
public class Test {
public static void main(String[] args) {
String exp = "(aa >= bb )|| (aa <= cc) ||(dd < ee) || (ff != gg) && (ff == ee) &&(!'Yes'.equals(STR))";
parseKeysFromExpression(exp);
}
//获取表达式中的参数集合
public static Set<String> parseKeysFromExpression(String args){
Set<String> arg_set = new HashSet<>();
//去掉args中多余的空格
args = args.replaceAll(" ","");
//第一道过滤,过滤表达式中的 &&
String[] split1 = args.split("&&");
//第二道过滤,过滤表达式中的 ||
split1 = makeANewStrings(split1,"[||]");
//第三道,过滤表达式中的比较运算符
split1 = makeANewStrings(split1,"[!=><()]");
//第四道,过滤字符串的等于
split1 = makeANewStrings(split1,".equals");
for(int i=0; i< split1.length; ++i){
//排除掉空字符串,以及带单引号的字符串(这在表达式中是常量字符,而非变量)
if(!"".equals(split1[i])&&!split1[i].contains("\'")) {
arg_set.add(split1[i]);
//System.out.println(split1[i]);
}
}
//System.out.println("set:"+arg_set);
return arg_set;
}
//将字符数组中的每个字符分割后,组成一个新数组
public static String[] makeANewStrings(String[] org,String exp){
List<String> ans = new ArrayList<>();
for(int i=0; i< org.length; ++i){//遍历字符串数组
String[] split = org[i].split(exp);
for (int j=0; j<split.length; ++j){
ans.add(split[j]);
}
}
String[] ans2 = new String[ans.size()];
return ans.toArray(ans2);
}
}