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));
    }
posted @ 2024-04-03 16:54  CharyGao  阅读(245)  评论(0编辑  收藏  举报