Spring El表达式解析

14 阅读2分钟
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.SpelCompilerMode;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class SpelExpressionExtractor {

    // 表达式解析器(带编译优化)
    private static final ExpressionParser PARSER = new SpelExpressionParser(
        new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, getClass().getClassLoader())
    );
    
    // 表达式缓存(提升性能)
    private static final Map<String, Expression> EXPRESSION_CACHE = new ConcurrentHashMap<>();
    
    // 自定义函数注册
    static {
        registerCustomFunctions();
    }

    /**
     * 执行取值操作
     * @param data 原始数据(接口返回的Map)
     * @param elExpress SpEL表达式
     * @param resultCode 结果标识码
     * @return 包含提取结果的单条目Map
     */
    public Map<String, Object> extract(
            Map<String, Object> data, 
            String elExpress, 
            String resultCode) {
        
        try {
            Object value = evaluateSpelExpression(data, elExpress);
            return Collections.singletonMap(resultCode, value);
        } catch (Exception e) {
            // 异常处理:返回错误信息
            Map<String, Object> errorResult = new HashMap<>();
            errorResult.put(resultCode, null);
            errorResult.put("error", "表达式解析失败: " + e.getMessage());
            return errorResult;
        }
    }

    /**
     * 评估SpEL表达式
     */
    private Object evaluateSpelExpression(Map<String, Object> data, String expression) {
        // 从缓存获取或创建表达式
        Expression expr = EXPRESSION_CACHE.computeIfAbsent(expression, PARSER::parseExpression);
        
        // 创建评估上下文
        StandardEvaluationContext context = new StandardEvaluationContext(data);
        
        // 设置根对象
        context.setRootObject(data);
        
        // 注册自定义函数
        registerContextFunctions(context);
        
        // 执行表达式
        return expr.getValue(context);
    }

    /**
     * 注册自定义函数(静态注册)
     */
    private static void registerCustomFunctions() {
        try {
            // 注册数学函数
            MathFunctions.register();
            
            // 注册字符串处理函数
            StringFunctions.register();
            
            // 注册日期处理函数
            DateFunctions.register();
        } catch (Exception e) {
            System.err.println("自定义函数注册失败: " + e.getMessage());
        }
    }

    /**
     * 注册上下文函数(每次评估时注册)
     */
    private void registerContextFunctions(StandardEvaluationContext context) {
        // 注册实用函数
        context.registerFunction("size", SpelFunctions.class.getDeclaredMethod("size", Object.class));
        context.registerFunction("empty", SpelFunctions.class.getDeclaredMethod("empty", Object.class));
    }

    // 测试用例
    public static void main(String[] args) {
        // 构建测试数据
        Map<String, Object> data = new HashMap<>();
        Map<String, Object> user = new HashMap<>();
        Map<String, Object> address = new HashMap<>();
        
        address.put("city", "Beijing");
        address.put("streets", new String[]{"Main St", "Second St"});
        user.put("address", address);
        user.put("age", 30);
        user.put("scores", new int[]{85, 92, 78});
        data.put("user", user);
        data.put("status", "active");
        data.put("price", 123.45);

        SpelExpressionExtractor extractor = new SpelExpressionExtractor();
        
        // 测试SpEL表达式
        System.out.println("1. 基本取值: " + 
            extractor.extract(data, "#root['user']['address']['city']", "CITY_CODE"));
        
        System.out.println("2. 数组取值: " + 
            extractor.extract(data, "user.address.streets[1]", "STREET_CODE"));
        
        System.out.println("3. 条件表达式: " + 
            extractor.extract(data, "user.age > 18 ? 'adult' : 'child'", "AGE_GROUP"));
        
        System.out.println("4. 安全导航: " + 
            extractor.extract(data, "user?.phone?.number ?: 'N/A'", "PHONE_CODE"));
        
        System.out.println("5. 集合投影: " + 
            extractor.extract(data, "user.scores.![#this > 80]", "PASS_SCORES"));
        
        System.out.println("6. 方法调用: " + 
            extractor.extract(data, "T(java.lang.Math).round(price)", "ROUNDED_PRICE"));
        
        System.out.println("7. 自定义函数: " + 
            extractor.extract(data, "#size(user.scores)", "SCORE_COUNT"));
        
        System.out.println("8. 复杂表达式: " + 
            extractor.extract(data, 
                "user.age > 25 && user.address.city contains 'jing' ? 'valid' : 'invalid'", 
                "VALIDATION"));
    }
}

/**
 * SpEL实用函数类
 */
class SpelFunctions {
    public static int size(Object obj) {
        if (obj == null) return 0;
        if (obj instanceof Map) return ((Map<?, ?>) obj).size();
        if (obj instanceof Iterable) return ((Iterable<?>) obj).spliterator().getExactSizeIfKnown();
        if (obj.getClass().isArray()) return java.lang.reflect.Array.getLength(obj);
        return 0;
    }
    
    public static boolean empty(Object obj) {
        return size(obj) == 0;
    }
}

/**
 * 数学函数注册器
 */
class MathFunctions {
    public static void register() throws NoSuchMethodException {
        // 可注册更多数学函数
    }
}

/**
 * 字符串函数注册器
 */
class StringFunctions {
    public static void register() throws NoSuchMethodException {
        // 可注册字符串处理函数
    }
}

/**
 * 日期函数注册器
 */
class DateFunctions {
    public static void register() throws NoSuchMethodException {
        // 可注册日期处理函数
    }
}