SpEL表达式案例

wen java案例 1

本文目录导读:

SpEL表达式案例

  1. 基础案例
  2. 集合操作案例
  3. 条件逻辑案例
  4. Spring 注解使用案例
  5. 高级案例
  6. 性能优化案例

基础案例

基础表达式

import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
public class SpELBasicCase {
    public static void main(String[] args) {
        SpelExpressionParser parser = new SpelExpressionParser();
        // 字符串表达式
        Expression exp = parser.parseExpression("'Hello World'");
        String message = (String) exp.getValue();
        System.out.println(message); // Hello World
        // 数学运算
        Expression exp2 = parser.parseExpression("10 + 5 * 2");
        int result = (int) exp2.getValue();
        System.out.println(result); // 20
        // 字符串拼接
        Expression exp3 = parser.parseExpression("'Hello' + ' ' + 'World'");
        System.out.println(exp3.getValue()); // Hello World
    }
}

使用 EvaluationContext

public class SpELContextCase {
    @Data
    static class User {
        private String name;
        private int age;
        private List<String> hobbies;
        private Address address;
    }
    @Data
    static class Address {
        private String city;
        private String street;
    }
    public static void main(String[] args) {
        // 创建用户对象
        User user = new User();
        user.setName("张三");
        user.setAge(25);
        user.setHobbies(Arrays.asList("编程", "阅读", "运动"));
        Address address = new Address();
        address.setCity("北京");
        address.setStreet("长安街");
        user.setAddress(address);
        SpelExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setVariable("user", user);
        // 访问对象属性
        Expression exp1 = parser.parseExpression("name");
        System.out.println(exp1.getValue(user)); // 张三
        // 嵌套属性
        Expression exp2 = parser.parseExpression("address.city");
        System.out.println(exp2.getValue(user)); // 北京
        // 方法调用
        Expression exp3 = parser.parseExpression("name.length()");
        System.out.println(exp3.getValue(user)); // 2
        // 集合访问
        Expression exp4 = parser.parseExpression("hobbies[0]");
        System.out.println(exp4.getValue(user)); // 编程
    }
}

集合操作案例

列表和映射操作

public class SpELCollectionCase {
    public static void main(String[] args) {
        SpelExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext();
        // 创建集合
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        Map<String, Object> map = new HashMap<>();
        map.put("name", "张三");
        map.put("age", 25);
        context.setVariable("numbers", numbers);
        context.setVariable("map", map);
        // 列表推导(过滤)
        Expression exp1 = parser.parseExpression("#numbers.?[#this > 3]");
        List<Integer> filtered = (List<Integer>) exp1.getValue(context);
        System.out.println(filtered); // [4, 5]
        // 列表推导(映射)
        Expression exp2 = parser.parseExpression("#numbers.![#this * 2]");
        List<Integer> mapped = (List<Integer>) exp2.getValue(context);
        System.out.println(mapped); // [2, 4, 6, 8, 10]
        // 筛选第一个匹配项
        Expression exp3 = parser.parseExpression("#numbers.^[#this > 2]");
        Integer firstMatch = (Integer) exp3.getValue(context);
        System.out.println(firstMatch); // 3
        // 筛选最后一个匹配项
        Expression exp4 = parser.parseExpression("#numbers.$[#this < 4]");
        Integer lastMatch = (Integer) exp4.getValue(context);
        System.out.println(lastMatch); // 3
        // 集合判断
        Expression exp5 = parser.parseExpression("#numbers.?[#this > 2].size() > 2");
        Boolean result = exp5.getValue(context, Boolean.class);
        System.out.println(result); // true
    }
}

对象列表操作

public class SpELListObjectCase {
    @Data
    @AllArgsConstructor
    static class Product {
        private String name;
        private Double price;
        private Integer stock;
        private String category;
    }
    public static void main(String[] args) {
        SpelExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext();
        List<Product> products = Arrays.asList(
            new Product("iPhone", 5999.0, 100, "手机"),
            new Product("华为", 3999.0, 200, "手机"),
            new Product("MacBook", 12999.0, 50, "电脑"),
            new Product("iPad", 3499.0, 150, "平板")
        );
        context.setVariable("products", products);
        // 筛选价格大于4000的产品
        Expression exp1 = parser.parseExpression("#products.?[price > 4000]");
        List<Product> expensiveProducts = (List<Product>) exp1.getValue(context);
        System.out.println("高价产品: " + expensiveProducts);
        // 筛选特定类别并按价格排序
        Expression exp2 = parser.parseExpression("#products.?[category == '手机'].![name]");
        List<String> phoneNames = (List<String>) exp2.getValue(context);
        System.out.println("手机品牌: " + phoneNames);
        // 统计平均值
        Expression exp3 = parser.parseExpression("#products.![price].^[true]");
        List<Double> prices = (List<Double>) exp3.getValue(context);
        double average = prices.stream().mapToDouble(Double::doubleValue).average().orElse(0);
        System.out.println("平均价格: " + average);
        // 条件判断所有产品
        Expression exp4 = parser.parseExpression("#products.![stock > 0].^[true]");
        System.out.println("所有产品有库存: " + exp4.getValue(context));
    }
}

条件逻辑案例

条件表达式

public class SpELConditionCase {
    public static void main(String[] args) {
        SpelExpressionParser parser = new SpelExpressionParser();
        // 三元运算符
        Expression exp1 = parser.parseExpression("10 > 5 ? '正确' : '错误'");
        String result1 = (String) exp1.getValue();
        System.out.println(result1); // 正确
        // Elvis运算符(类似三元)
        Expression exp2 = parser.parseExpression("name != null ? name : '默认值'");
        // 等价于
        Expression exp3 = parser.parseExpression("name ?: '默认值'");
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setVariable("name", null);
        System.out.println(exp3.getValue(context)); // 默认值
        // 安全导航操作符(避免空指针)
        context.setVariable("user", null);
        Expression exp4 = parser.parseExpression("user?.name?.toUpperCase()");
        Object result = exp4.getValue(context);
        System.out.println("安全导航结果: " + result); // null(不会抛异常)
        // 复杂的逻辑判断
        Expression exp5 = parser.parseExpression(
            "(age > 18 && age < 65) || (age >= 65 && isRetired)"
        );
        StandardEvaluationContext userContext = new StandardEvaluationContext();
        userContext.setVariable("age", 70);
        userContext.setVariable("isRetired", true);
        System.out.println(exp5.getValue(userContext)); // true
    }
}

业务规则案例

public class SpELBusinessRuleCase {
    @Data
    @AllArgsConstructor
    static class Order {
        private double amount;
        private Customer customer;
        private List<OrderItem> items;
    }
    @Data
    @AllArgsConstructor
    static class Customer {
        private String level; // VIP / NORMAL
        private int loyaltyYears;
    }
    @Data
    @AllArgsConstructor
    static class OrderItem {
        private String productName;
        private double price;
        private int quantity;
    }
    public static void main(String[] args) {
        SpelExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext();
        // 创建订单
        Customer vipCustomer = new Customer("VIP", 5);
        List<OrderItem> items = Arrays.asList(
            new OrderItem("电脑", 8000, 1),
            new OrderItem("鼠标", 100, 2)
        );
        Order order = new Order(8200, vipCustomer, items);
        context.setVariable("order", order);
        // 规则1:VIP客户且忠诚度超过3年,享受95折
        String vipRule = 
            "#order.customer.level == 'VIP' and #order.customer.loyaltyYears > 3";
        boolean isVipEligible = parser.parseExpression(vipRule)
            .getValue(context, Boolean.class);
        System.out.println("VIP折扣资格: " + isVipEligible);
        // 规则2:订单金额超过5000,可以免运费
        String freeShippingRule = "#order.amount > 5000";
        boolean freeShipping = parser.parseExpression(freeShippingRule)
            .getValue(context, Boolean.class);
        System.out.println("免运费资格: " + freeShipping);
        // 规则3:包含特定商品
        String hasComputerRule = 
            "#order.items.?[productName == '电脑'].size() > 0";
        boolean hasComputer = parser.parseExpression(hasComputerRule)
            .getValue(context, Boolean.class);
        System.out.println("包含电脑: " + hasComputer);
        // 规则4:计算折扣金额
        String discountRule = 
            "#order.amount * (#order.customer.level == 'VIP' ? 0.95 : 1.0)";
        double finalAmount = parser.parseExpression(discountRule)
            .getValue(context, Double.class);
        System.out.println("最终金额: " + finalAmount);
    }
}

Spring 注解使用案例

@Value 注解

@Component
public class SpELValueAnnotationCase {
    // 字符串字面量
    @Value("'Hello World'")
    private String message;
    // 系统属性
    @Value("#{systemProperties['user.home']}")
    private String userHome;
    // 引用其他Bean属性
    @Value("#{databaseConfig.url}")
    private String databaseUrl;
    // 调用方法
    @Value("#{propertiesUtil.getProperty('app.name', '默认应用名')}")
    private String appName;
    // 静态常量
    @Value("#{T(java.lang.Math).PI}")
    private double pi;
    // 复杂表达式
    @Value("#{systemProperties['user.region'] == 'CN' ? '中国大陆' : '其他地区'}")
    private String region;
    // 列表
    @Value("#{{'spring', 'mybatis', 'redis'}}")
    private List<String> frameworks;
    // Map
    @Value("#{{'key1': 'value1', 'key2': 'value2'}}")
    private Map<String, String> configMap;
    // 数组
    @Value("#{new String[]{'item1', 'item2', 'item3'}}")
    private String[] items;
    // 引用配置文件中的值
    @Value("${app.name:默认名称}")
    private String appNameFromConfig;
    public void showConfigs() {
        System.out.println("Message: " + message);
        System.out.println("User Home: " + userHome);
        System.out.println("Database URL: " + databaseUrl);
        System.out.println("App Name: " + appName);
        System.out.println("PI: " + pi);
        System.out.println("Region: " + region);
        System.out.println("Frameworks: " + frameworks);
        System.out.println("Config Map: " + configMap);
        System.out.println("Items: " + Arrays.toString(items));
    }
}

@PreAuthorize 注解(Spring Security)

@RestController
public class SpELSecurityCase {
    // 基于角色的权限控制
    @PreAuthorize("hasRole('ADMIN')")
    @GetMapping("/admin/data")
    public String adminData() {
        return "Admin Data";
    }
    // 基于用户名
    @PreAuthorize("#username == authentication.principal.username")
    @GetMapping("/user/{username}")
    public String userData(@PathVariable String username) {
        return "User: " + username;
    }
    // 自定义方法
    @PreAuthorize("@securityService.checkPermission(authentication, #request)")
    @PostMapping("/api/secure")
    public String secureEndpoint(@RequestBody ApiRequest request, 
                                 Authentication authentication) {
        return "Secure response";
    }
    // 复杂的权限表达式
    @PreAuthorize("hasAnyRole('ADMIN', 'MANAGER') AND " +
                  "(hasPermission(#id, 'READ') OR #userId == authentication.principal.id)")
    @GetMapping("/document/{id}")
    public String getDocument(@PathVariable Long id, @RequestParam Long userId) {
        return "Document: " + id;
    }
}

高级案例

自定义函数

public class SpELCustomFunctionCase {
    public static String formatDate(LocalDate date) {
        return date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }
    public static double calculateDiscount(double price, double discountRate) {
        return price * (1 - discountRate);
    }
    public static void main(String[] args) {
        SpelExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext();
        // 注册静态方法
        context.registerFunction("formatDate", 
            SpELCustomFunctionCase.class.getDeclaredMethod("formatDate", LocalDate.class));
        context.registerFunction("calculateDiscount", 
            SpELCustomFunctionCase.class.getDeclaredMethod("calculateDiscount", double.class, double.class));
        // 使用自定义函数
        Expression exp1 = parser.parseExpression("#formatDate(T(java.time.LocalDate).now())");
        String dateStr = (String) exp1.getValue(context);
        System.out.println("格式化日期: " + dateStr);
        // 计算折扣
        Expression exp2 = parser.parseExpression("#calculateDiscount(1000, 0.15)");
        double price = (double) exp2.getValue(context);
        System.out.println("折扣价格: " + price);
    }
}

动态规则引擎案例

public class SpringELRuleEngine {
    static class Rule {
        private String name;
        private String condition;
        private String action;
        private int priority;
    }
    @Data
    @AllArgsConstructor
    static class Transaction {
        private double amount;
        private String type; // TRANSFER / PURCHASE / WITHDRAW
        private String from;
        private String to;
    }
    public static void main(String[] args) {
        SpelExpressionParser parser = new SpelExpressionParser();
        // 定义规则
        List<Rule> rules = Arrays.asList(
            new Rule("大额转账", 
                    "#trans.amount > 10000 and #trans.type == 'TRANSFER'",
                    "执行大额转账审核流程", 1),
            new Rule("频繁交易", 
                    "#trans.amount > 5000 and #trans.type == 'PURCHASE'",
                    "标记为高消费用户", 2),
            new Rule("异常取现", 
                    "#trans.type == 'WITHDRAW' and #trans.amount > 50000",
                    "触发取现风控", 1)
        );
        // 测试事务
        Transaction t1 = new Transaction(15000, "TRANSFER", "A001", "B002");
        Transaction t2 = new Transaction(8000, "PURCHASE", "A001", "SHOP001");
        Transaction t3 = new Transaction(60000, "WITHDRAW", "A001", "CASH");
        for (Transaction trans : Arrays.asList(t1, t2, t3)) {
            System.out.println("\n=== 事务检查: " + trans.getType() + " " + trans.getAmount() + " ===");
            StandardEvaluationContext context = new StandardEvaluationContext();
            context.setVariable("trans", trans);
            for (Rule rule : rules) {
                boolean matched = parser.parseExpression(rule.condition)
                    .getValue(context, Boolean.class);
                if (matched) {
                    System.out.println("触发规则: " + rule.name + " -> " + rule.action);
                }
            }
        }
    }
}

性能优化案例

public class SpELPerformanceCase {
    static class ExpressionCache {
        private static final ConcurrentHashMap<String, Expression> CACHE = new ConcurrentHashMap<>();
        private static final SpelExpressionParser PARSER = new SpelExpressionParser();
        public static Expression getExpression(String expr) {
            return CACHE.computeIfAbsent(expr, PARSER::parseExpression);
        }
    }
    public static void main(String[] args) {
        // 编译模式的性能优化
        SpelParserConfiguration config = new SpelParserConfiguration(
            SpelCompilerMode.IMMEDIATE, 
            ExpressionCache.class.getClassLoader()
        );
        SpelExpressionParser compilerParser = new SpelExpressionParser(config);
        // 使用编译模式
        String expression = "name.toUpperCase() + ' - ' + age";
        StandardEvaluationContext context = new StandardEvaluationContext();
        User user = new User();
        user.setName("张三");
        user.setAge(25);
        // 缓存表达式避免重复解析
        Expression exp = ExpressionCache.getExpression(expression);
        // 性能测试
        long start = System.nanoTime();
        for (int i = 0; i < 100000; i++) {
            Object result = exp.getValue(user);
        }
        long end = System.nanoTime();
        System.out.println("执行100000次耗时: " + (end - start) / 1_000_000 + "ms");
    }
}

这些案例展示了 SpEL 在不同场景下的应用:

  1. 基础表达式:字面量、运算符、方法调用
  2. 集合操作:过滤、映射、投影、聚合
  3. 条件逻辑:三元运算符、安全导航
  4. Spring 注解:@Value、@PreAuthorize
  5. 自定义函数:注册和使用自定义方法
  6. 规则引擎:动态业务规则处理
  7. 性能优化:编译模式、表达式缓存

SpEL 非常灵活,可以处理复杂的表达式,但要注意:

  • 复杂表达式可能影响性能
  • 避免在循环中重复创建表达式
  • 适当使用缓存提高性能
  • 注意表达式安全性(避免注入攻击)

抱歉,评论功能暂时关闭!