spring表达语言(SpEL)快速掌握

在Spring3中就已经支持EL表达式了, spring Expression Language(SpEL)是类似于OGNL和EL的表达式语言, 能够在运行时构建复杂表达式, 存取对象属性、调用对象方法等, 它支持XML和Annotation两种方式, 格式:#{SpEL expression}。我使用的spring4.2.2的版本,SpEL位于spring-expression的jar包中。

下面是一个测试类,包含了基本的例子
package testSpEL;

import org.junit.Test;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.util.*;

/**
 * writer: holien
 * Time: 2017-08-17 10:27
 * Intent: spring el 测试
 */
public class SpELTest {
    @Test
    public void testEL() {
        // 模拟一个情境
        EvaluationContext context = new StandardEvaluationContext();
        // 往情境存放变量
        context.setVariable("name", "pens");
        // 构造解析器
        ExpressionParser parser = new SpelExpressionParser();
        // 解析表达式
        Expression expression = parser.parseExpression("#name");
        // 从情境中获取值并打印,注意:取情境中的属性记得加上context
        System.out.println(expression.getValue(context));  // pens

        // 直接解析各种变量,可以指定类型,比如getValue(String.class)
        System.out.println(parser.parseExpression("10").getValue());  // 10
        System.out.println(parser.parseExpression("10.1f").getValue());  // 10.1
        System.out.println(parser.parseExpression("0xFFFF").getValue());  // 65535
        System.out.println(parser.parseExpression("true").getValue());  // true
        System.out.println(parser.parseExpression("null").getValue());  // null

        // 调用list
        ArrayList list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        context.setVariable("list", list);
        System.out.println(parser.parseExpression("#list[0]").getValue(context));  // a

        // 调用map
        HashMap map = new HashMap<>();
        map.put(1, "x");
        map.put(2, "y");
        map.put(3, "z");
        context.setVariable("map", map);
        System.out.println(parser.parseExpression("#map[1]").getValue(context));  // x

        // 使用T{}引用类,然后调用静态方法
        System.out.println(parser.parseExpression("T(Math).abs(-10)").getValue());  // 10

        // Attempted to call method toUpperCase() on null context object
        // 防止出现上面的空指针异常,在变量名后面加?,返回null
        System.out.println(parser.parseExpression("#age?.toUpperCase()").getValue(context, String.class));  // null

        // 使用一个模板情景参数进行字符串拼接,用#{}把变量#name包含起来
        System.out.println(parser.parseExpression("我的名字叫#{#name}", new TemplateParserContext()).getValue(context)); // 我的名字叫pens

        /**
         * ?[condition] 选择符合条件的所有元素
         * ^[condition] 选择符合条件的第一个元素
         * &[condition] 选择符合条件的最后一个元素
         * ![condition] 遍历符合条件的元素
         * #this 当前对象或属性
         */
        // #this代表数组{1, 2, 3, 4, 5}
        System.out.println(parser.parseExpression("{1, 2, 3, 4, 5}.?[#this > 3]").getValue());  // [4, 5]

        /**
         * 关系操作符, 包括: eq(==), ne(!=), lt()<, le(<=), gt(>), ge(>=)
         * 逻辑运算符, 包括: and(&&), or(||), not(!)
         * 数学操作符, 包括: 加(+), 减(-), 乘(*), 除(/), 取模(%), 幂指数(^)
         * 其他操作符, 如: 三元操作符, instanceof, 赋值(=), 正则匹配(matches)
         */
        System.out.println(parser.parseExpression("5 > 3").getValue());  // true
        System.out.println(parser.parseExpression("1 < 10 ? '对' : '错'").getValue());  // 对
        System.out.println(parser.parseExpression("#name instanceof T(String)").getValue(context));  // true
        System.out.println(parser.parseExpression("#name = 'newName'").getValue(context));  // newName
        System.out.println(parser.parseExpression("'4.13' matches '^\\d\\.\\d{2}$'").getValue());  // true
    }
}

下面是实际开发中使用到的情况,先看看配置文件applicationContext.xml文件,里面顺带加载了test.properties属性文件,用${}来引用属性




    
    

    
    

    
    
          
        
            
        
        
    

    
        
        
        
        
        
        
    

    
        
        
    

test.properties,只包含一个属性对

itemName=phone

xml方式使用SpEL,两个bean已经配置在applicationContext.xml中了,下面是测试方法
package testSpEL;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * writer: holien
 * Time: 2017-08-18 21:13
 * Intent: 测试配置文件中配置的bean
 */
public class XmlBeanTest {
    @Test
    public void testXmlBean() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        // 测试itemBean
        Item item = (Item) context.getBean("itemBean");
        System.out.println("商品项的id:" + item.getItemId() + " 价格:" + item.getPrice()
                + " 名称:" + item.getItemName() + " 描述:" + item.getDescription());
        // 测试orderBean
        Order order = (Order) context.getBean("orderBean");
        System.out.println(order.getItem().getItemName());
    }
}

annotation方式使用SpEL

package testSpEL;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

/**
 * writer: holien
 * Time: 2017-08-17 10:51
 * Intent: 通过注解和SpEL的方式注入属性值的商品项类
 */
@Component("item")
public class Item {

    @Value("001")
    private int itemId;

    @Value("5200.0")
    private double price;

    // 注入字符串,注意注解不用加单引号
    @Value("物美价廉")
    private String description;

    // 注入.properties文件中的属性
    @Value("${itemName}")
    private String itemName;

    @Test
    public void testAnnotationBean() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        Item item = (Item) context.getBean("item");
        System.out.println("商品项的id:" + item.getItemId() + " 价格:" + item.getPrice()
                + " 名称:" + item.getItemName() + " 描述:" + item.getDescription());
    }

    public int getItemId() {
        return itemId;
    }

    public void setItemId(int id) {
        this.itemId = id;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public String getItemName() {
        return itemName;
    }

    public void setItemName(String itemName) {
        this.itemName = itemName;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}
运行结果:商品项的id:1 价格:5200.0 名称:phone 描述:物美价廉

package testSpEL;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

/**
 * writer: holien
 * Time: 2017-08-17 10:51
 * Intent: 通过注解和SpEL的方式注入属性值的订单类
 */
@Component("order")
public class Order {

    // 注入item
    @Value("#{item}")
    private Item item;

    @Test
    public void testAnnotationBean() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        Order order = (Order) context.getBean("order");
        System.out.println(order.getItem().getItemName());
    }

    public Item getItem() {
        return item;
    }

    public void setItem(Item item) {
        this.item = item;
    }

}
运行结果:phone,证明已经把item当作属性注入到order中。


学shiro时发现shiro中用ehcache做缓存,于是学起了ehcache,学ehcache时发现其与spring整合时,注解中使用了SpEL,于是有了这篇文章,学无止境...


你可能感兴趣的:(spring)