SPEL解析JSON或MAP
背景:
在某项目中,需要使用el表达式对json进行解析;后端先将json序列化为一个map,然后将这个map作为root对象进行el解析,结果报错:
Exception in thread "main" org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'sub' cannot be found on object of type 'java.util.LinkedHashMap' - maybe not public or not valid?
at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:217)
at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:104)
at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:91)
at org.springframework.expression.spel.ast.CompoundExpression.getValueRef(CompoundExpression.java:61)
at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:91)
at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:112)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:272)
研究后发现,采用el表达式进行解析,针对map的解析写法比较复杂:
map['student']['address']['city']
以上写法不优雅,为了更优雅的兼容map解析,需要对原有的StandardEvaluationContext
添加一个属性访问器:MapAccessor
这样就可以通过如下写法获取属性:
map.student.address.city
代码如下:
/**
* spel解析器
*/
private static final SpelExpressionParser parser= new SpelExpressionParser();
/**
* spel缓存
*/
private static final ConcurrentHashMap<String, Expression> expressionMap = new ConcurrentHashMap<>(256);
public static void main(String[] args) {
// String el = "#root['student']['address']['city']";
String el = "student.address.city";
Map<String, Object> address = new HashMap<>();
address.put("city", "北京");
Map<String, Object> student = new HashMap<>();
student.put("address", address);
Map<String, Object> root = new LinkedHashMap<>();
root.put("student", student);
Expression expression = getExpression(el);
StandardEvaluationContext context = new StandardEvaluationContext(root);
//这里很关键,如果没有配置MapAccessor,那么只能用['c']['a']这种解析方式
context.addPropertyAccessor(new MapAccessor());
Object value = expression.getValue(context);
System.out.println(value);
}
/**
* 从缓存中获取spel编译表达式
*
* @return SpelExpression
*/
private static Expression getExpression(String el) {
Expression expression = expressionMap.get(el);
if (expression != null) {
return expression;
}
return expressionMap.computeIfAbsent(el, k -> parser.parseRaw(el));
}
摘抄自网络,便于检索查找。