@Test
public void test1() {
// 解析器
ExpressionParser parser = new SpelExpressionParser();
//表达式
Expression expression = parser.parseExpression("('Hello' + ' World').concat(#end)");
// 构建上下文
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("end", "!");
//表达式从上下文中获取值
System.out.println(expression.getValue(context));
}
@Test
public void test2() {
// 字面量表达式
ExpressionParser parser = new SpelExpressionParser();
String str1 = parser.parseExpression("'Hello World!'").getValue(String.class);
int int1 = parser.parseExpression("1").getValue(Integer.class);
long long1 = parser.parseExpression("-1L").getValue(long.class);
float float1 = parser.parseExpression("1.1").getValue(Float.class);
double double1 = parser.parseExpression("1.1E+2").getValue(double.class);
int hex1 = parser.parseExpression("0xa").getValue(Integer.class);
long hex2 = parser.parseExpression("0xaL").getValue(long.class);
boolean true1 = parser.parseExpression("true").getValue(boolean.class);
boolean false1 = parser.parseExpression("false").getValue(boolean.class);
Object null1 = parser.parseExpression("null").getValue(Object.class);
System.out.println("str1=" + str1);
System.out.println("int1=" + int1);
System.out.println("long1=" + long1);
System.out.println("float1=" + float1);
System.out.println("double1=" + double1);
System.out.println("hex1=" + hex1);
System.out.println("hex2=" + hex2);
System.out.println("true1=" + true1);
System.out.println("false1=" + false1);
System.out.println("null1=" + null1);
}
@Test
public void test3() {
// 算数运算表达式 SpEL支持加(+)、减(-)、乘(*)、除(/)、求余(%)、幂(^)运算。
ExpressionParser parser = new SpelExpressionParser();
System.out.println(parser.parseExpression("1+3%4").getValue(Integer.class));
//关系表达式 等于(==)、不等于(!=)、大于(>)、大于等于(>=)、小于(<)、小于等于(<=),区间(between)运算。
// between运算符右边操作数必须是列表类型,且只能包含2个元素。第一个元素为开始,第二个元素为结束,区间运算是包含边界值的,即 xxx>=list.get(0) && xxx<=list.get(1)。
System.out.println(parser.parseExpression("1>2").getValue(Boolean.class));
System.out.println(parser.parseExpression("1==1").getValue(Boolean.class));
System.out.println(parser.parseExpression("1 between {2,3}").getValue(Boolean.class));
// 逻辑表达式
//且(and或者&&)、或(or或者||)、非(!或NOT)。
System.out.println(parser.parseExpression("1>3 or 3<=3").getValue(Boolean.class));
//字符串连接及截取表达式
System.out.println(parser.parseExpression("'aaa'+'bbb'").getValue(String.class));
System.out.println(parser.parseExpression("'aaa'[0]").getValue(String.class));
// 三目运算
System.out.println(parser.parseExpression("1>2?'aaaa':'bbb'").getValue(String.class));
System.out.println(parser.parseExpression("1>2?'aaaa':'bbb'").getValue(String.class));
// 类类型表达式
// 使用“T(Type)”来表示java.lang.Class实例,“Type”必须是类全限定名,
// “java.lang”包除外,即该包下的类可以不指定包名;使用类类型表达式还可以进行访问类静态方法及类静态字段。
System.out.println(parser.parseExpression("T(Integer).MAX_VALUE").getValue(Integer.class));
System.out.println(parser.parseExpression("T(Integer).parseInt('22')").getValue(Integer.class));
//类实例化 实例化完全跟Java内方式一样,运行输出
System.out.println(parser.parseExpression("new String('路人甲java')").getValue(String.class));
System.out.println(parser.parseExpression("new java.util.Date()").getValue(Date.class));
}
@Test
public void tes4() throws NoSuchMethodException {
// 变量定义及引用变量定义通过EvaluationContext接口的setVariable(variableName, value)方法定义;
// 在表达式中使用"#variableName"引用;除了引用自定义变量,SpE还允许引用根对象及当前上下文对象,使用"#root"引用根对象,使用"#this"引用当前上下文对象;
ExpressionParser parser = new SpelExpressionParser();
// EvaluationContext context = new StandardEvaluationContext();
// context.setVariable("name","maxx");
// System.out.println(parser.parseExpression("'我的名称:'+#name").getValue(context, String.class));
//// 方法作为表达式并传入参数获取方法执行结果 (可以自定义类)
// Method parseInt = Integer.class.getDeclaredMethod("parseInt", String.class);
// context.setVariable("parseInt1",parseInt);
// System.out.println(parser.parseExpression("#parseInt1('123')").getValue(context, Integer.class));
//// 类作为表达式并赋值 获取属性值
// User user = new User();
// EvaluationContext context1 = new StandardEvaluationContext(user);
// parser.parseExpression("#root.name").setValue(context1,"mxxx");
// System.out.println(parser.parseExpression("#root").getValue(context, user.getName()));
//
// EvaluationContext context2 = new StandardEvaluationContext();
// context2.setVariable("user1",user);
// parser.parseExpression("#user1.name").setValue(context1,"mxxx1");
// System.out.println(parser.parseExpression("#user1").getValue(context2, user.getName()));
User user1 = new User();
user1.setName("aaaa");
EvaluationContext context3 = new StandardEvaluationContext(user1);
System.out.println(parser.parseExpression("name=='111'").getValue(context3, user1,Boolean.class));
}
// 集合相关表达式......
// todo 参考:https://zhuanlan.zhihu.com/p/174786047
class User{
String name;
@Override
public String toString() {
return "User{" +
"name='" + name + ''' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
项目中使用: 判断对象中的属性是否符合特定条件
1.定义解析器
protected final SpelExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
2.定义上下文
protected EvaluationContext buildEvaluationContext(CpBankTransaction cpBankTransaction) {
try {
// 放对象
EvaluationContext context = new StandardEvaluationContext(cpBankTransaction);
// 还放了自定义方法
context.setVariable(Functions.IN_COLLECTION, Functions.class.getDeclaredMethod(Functions.IN_COLLECTION, Object.class, List.class));
context.setVariable(Functions.NOT_COLLECTION, Functions.class.getDeclaredMethod(Functions.NOT_COLLECTION, Object.class, List.class));
context.setVariable(Functions.BATCH_CONTAIN, Functions.class.getDeclaredMethod(Functions.BATCH_CONTAIN, Object.class, List.class));
context.setVariable(Functions.BATCH_NOT_CONTAIN, Functions.class.getDeclaredMethod(Functions.BATCH_NOT_CONTAIN, Object.class, List.class));
return context;
} catch (Exception ex) {
throw new ServiceException("无法定位对应的函数", ex);
}
}
基类:
public static final class Functions {
public final static String IN_COLLECTION = "inCollection";
public final static String NOT_COLLECTION = "notCollection";
public final static String BATCH_CONTAIN = "batchContains";
public final static String BATCH_NOT_CONTAIN = "batchNotContains";
public static boolean inCollection(Object value, List<Object> objs) {
return objs.contains(value);
}
public static boolean notCollection(Object value, List<Object> objs) {
return !objs.contains(value);
}
public static boolean batchContains(Object value, List<Object> objs) {
for (Object obj : objs) {
if (value.toString().contains(obj.toString())) {
return true;
}
}
return false;
}
public static boolean batchNotContains(Object value, List<Object> objs) {
for (Object obj : objs) {
if (value.toString().contains(obj.toString())) {
return false;
}
}
return true;
}
}
以上两步可以作为公用的 3. 解析表达式,得到表达式模板类
Expression expression = parser.parseExpression(rule.getExpression());
// 表达式作为参数可以动态配置
#规则三:主体
cashflow.rule.companyname[0].code=TF30001
cashflow.rule.companyname[0].name=调拨-收
cashflow.rule.companyname[0].expression=inAmount !=0 AND #inCollection(oppositeAccountName,{'Fishtrip Investment Holding Ltd.', 'Le Joyment Limited', 'TUJIA.COM (HONG KONG) LIMITED', 'TUJIA.COM INTERNATIONAL', 'Waka Trip(HK) Limited', '北京果加智能科技有限公司', '北京火河科技有限公司', '北京途家旅游有限公司', '北京鱼行天下网络科技有限公司', '北京裕山阳科技发展有限公司', '北京云端翱翔科技有限公司', '北京云端翱翔科技有限公司杭州分公司', '广东果加电子科技有限公司', '南通途家在线信息技术有限公司', '上海珍程信息技术有限公司', '天津安伴智能科技有限公司', '天津安伴智能科技有限公司北京分公司', '天津途家公寓管理有限公司', '天津途家旅游有限公司', '天津途家投资有限公司', '天津易云游网络技术有限公司', '途家ネット株式会社', '途家网网络技术(北京)有限公司', '途家网网络技术(北京)有限公司三亚分公司', '途家网网络技术(北京)有限公司上海分公司', '途家网网络技术(天津)有限公司', '途家在线信息技术(北京)有限公司', '途家在线信息技术(天津)有限公司', '途家在线信息技术(天津)有限公司北京分公司', '途嘉(天津)企业管理咨询中心(有限合伙)', '途宁(天津)企业管理咨询中心(有限合伙)', '途掌柜物业管理股份公司', '易云游网络技术(北京)有限公司'})
4.表达式模板类从上下文和root对象中计算表达式的值
Boolean isMatch = expression.getValue(context, cpBankTransaction, Boolean.class);