@SpEL表达式

Spring表达式语言(Spring Expression Language, SpEL)是Spring框架提供的一种强大的表达式语言,支持在运行时查询和操作对象。

基本语法

1. 字面量

#{3.14}       // 浮点数
#{'Hello'}    // 字符串
#{true}       // 布尔值

2. Bean引用

#{beanName}          // 引用Bean
#{beanName.property} // 引用Bean属性

3. 系统属性

#{systemProperties['user.name']}
#{systemEnvironment['JAVA_HOME']}

运算符

类型运算符示例
算术+ - * / % ^#{1 + 2}
比较< > == <= >= lt gt eq le ge#{age > 18}
逻辑and or not !#{!isAdmin}
条件?:(三元)#{score > 60 ? '及格':'不及格'}
Elvis?:#{name?:'无名'}

集合操作

基本访问

#{list[0]}      // 列表
#{map['key']}   // Map
#{array[0]}     // 数组
#{'abc'[1]}     // 字符串

集合处理

// 过滤
#{users.?[age > 18]}

// 投影
#{users.![name]}

// 安全导航
#{user?.address?.city}

类型操作

#{T(java.lang.Math).PI}       // 静态字段
#{T(java.lang.Math).random()} // 静态方法
#{T(java.lang.String).valueOf(123)}

实例

@RestController
@RequestMapping("/SpEL")
public class SpELController {
 
	@Value("${apollo.meta:xxx}")  //占位符: 读取字符串配置项,配置为空时取默认值xxx。
	String meta;
 
    @Value("#{'Hello World1'}")
	String helloWorld1;        //EL表达式: 变量word赋值直接量: 字符串"Hello World"
 
    @Value("Hello World2")
    String helloWorld2;        //EL表达式:变量word赋值直接量: 字符串"Hello World"
 
    //注入list
    @Value("7,2,3,5,1") //EL表达式: 字面量
    private List<Integer> fList;
 
 
    /**
     * {@code @Value} 注入String
     * @return
     */
    @RequestMapping(value = "/valueAnnoString", method = RequestMethod.POST)
    public String valueAnnoString() {
        return helloWorld1 + " & " + helloWorld2;
    }
 
    /**
     * {@code @Value} 注入List
     * @return
     * @throws NoSuchMethodException
     */
    @RequestMapping(value = "/valueAnnoList", method = RequestMethod.POST)
    public List<Integer> valueAnnoList() {
        return fList;
    }
    /**
     * 测试通过ExpressionParser调用SpEL表达式
     * @return
     */
    @RequestMapping(value = "/expressionParse", method = RequestMethod.POST)
    public List<Integer> expressionParse() {
 
        //创建ExpressionParser解析表达式
        ExpressionParser parser = new SpelExpressionParser();
        List<Integer> result1 = parser.parseExpression("{4,5,5,6}").getValue(List.class);
        return result1;
    }
 
    /**
     * 使用java代码
     * @return
     */
    @RequestMapping(value = "/javaCode", method = RequestMethod.POST)
    public Integer javaCode() {
 
        //创建ExpressionParser解析表达式
        ExpressionParser parser = new SpelExpressionParser();
 
        //等同于直接用java代码, 还有方法调用
        String str = parser.parseExpression("new String('Hello World').substring(3)").getValue(String.class);
        log.info("str=={}", str);
 
        //TType 等同于java的Integer.MAX_VALUE
        Integer integer = parser.parseExpression("T(Integer).MAX_VALUE").getValue(Integer.class);
        log.info("integer=={}", integer);
        return integer;
    }
 
    /**
     * 注入并调用method方法
     * @return
     * @throws NoSuchMethodException
     */
    @RequestMapping("methodInvoke")
    private boolean methodInvoke() throws NoSuchMethodException {
        //创建ctx容器
        StandardEvaluationContext ctx = new StandardEvaluationContext();
        //获取java自带的Integer类的parseInt(String)方法
        Method parseInt = Integer.class.getDeclaredMethod("parseInt", String.class);
        //将parseInt方法注册在ctx容器内, 推荐这样使用
        ctx.registerFunction("parseInt", parseInt);
        //再将parseInt方法设为parseInt2
        ctx.setVariable("parseInt2", parseInt);
 
        //创建ExpressionParser解析表达式
        ExpressionParser parser = new SpelExpressionParser();
        //SpEL语法, 比对两个方法执行完成后, 结果是否相同
        String expreString = "#parseInt('2') == #parseInt2('3')";
        //执行SpEL
        Expression expression = parser.parseExpression(expreString);
        Boolean value = expression.getValue(ctx, Boolean.class);
        return value;
    }
 
 
 
    /**
     * 运算符
     * @return
     */
    @RequestMapping(value = "/operator", method = RequestMethod.POST)
    public boolean operator() {
 
        //创建ctx容器
        StandardEvaluationContext ctx = new StandardEvaluationContext();
        //将字符串defg放在 ctx容器内
        ctx.setVariable("abc", new String("defg"));
        //创建ExpressionParser解析表达式
        ExpressionParser parser = new SpelExpressionParser();
        String abc = parser.parseExpression("#abc").getValue(ctx, String.class);
        log.info("abc=={}", abc);
 
        //运算符判断
        Boolean result = parser.parseExpression("#abc.length() > 3").getValue(ctx, Boolean.class);
        log.info("result=={}", result);
        return result;
    }
 
 
    /**
     * Elvis等用法
     * @return
     */
    @RequestMapping(value = "/elvis", method = RequestMethod.POST)
    public void elvis(){
        //创建ctx容器
        StandardEvaluationContext ctx = new StandardEvaluationContext();
        //将字符串defg放在 ctx容器内
        ctx.setVariable("name", null);
        //创建ExpressionParser解析表达式
        ExpressionParser parser = new SpelExpressionParser();
        String name = parser.parseExpression("#name?:'other'").getValue(ctx, String.class);
        log.info("name=={}",name);
        log.info("saved length() == {}", parser.parseExpression("#name?.lenth()").getValue(ctx));
 
        //将字符串defg放在 ctx容器内
        ctx.setVariable("name", "abc");
        name = parser.parseExpression("#name?:'other'").getValue(ctx, String.class);
        log.info("changed name=={}",name);
        log.info("changed saved length() == {}", parser.parseExpression("#name?.length()").getValue(ctx));
 
 
        //map获取
        Map<String, Integer> map = new HashMap<String, Integer>();
        map.put("a", 1);
        ctx.setVariable("map", map);
        int mapA = parser.parseExpression("#map['a']").getValue(ctx, int.class);
        log.info("map['a']=={}", mapA);
        //修改
        parser.parseExpression("#map['a']").setValue(ctx, 6);
        mapA = parser.parseExpression("#map['a']").getValue(ctx, int.class);
        log.info("changed map['a']=={}", mapA);
 
        return ;
    }
 
 
    @RequestMapping("/listFunction")
    private void listFunction() {
        //创建ctx容器
        StandardEvaluationContext ctx = new StandardEvaluationContext();
        //创建ExpressionParser解析表达式
        ExpressionParser parser = new SpelExpressionParser();
 
        //list过滤
        ctx.setVariable("aList",fList);
        List<Integer> cList = parser.parseExpression("#aList.?[#this>3]").getValue(ctx, List.class);
        log.info("filter list=={}", cList);
 
 
        List<Book> books = new ArrayList<>();
        books.add(new Book("JAVA Program", 2000, 102.5));
        books.add(new Book("C Program", 1985, 36));
        books.add(new Book("scala", 2015, 60));
 
        //object过滤
        ctx.setVariable("books", books);
        List<Book> filterBooks1 = (List<Book>) parser.parseExpression("#books.?[year>2000]").getValue(ctx);
        log.info("filterBooks1=={}", filterBooks1);
 
        //投影
        List<String> filterBooksName = parser.parseExpression("#books.?[price<100].![name]").getValue(ctx, List.class);
        log.info("filterBooksName=={}", filterBooksName);
 
        return;
    }
 
 
 
    @Data
    class Book{
        private String name;
        private int year;
        private double price;
 
        public Book(String name, int year, double price) {
            this.name = name;
            this.year = year;
            this.price = price;
        }
    }
 
}