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<String> 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<Integer, String> 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属性文件,用${}来引用属性

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 扫描包中的组件类,注解需要 -->
    <context:component-scan base-package="testSpEL" />

    <!-- 加载属性文件 -->
    <context:property-placeholder location="classpath:test.properties"/>

    <!-- spring的属性加载器,加载properties文件中的属性 -->
    <!--<bean id="propertyConfigurer"-->
          <!--class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">-->
        <!--<property name="location">-->
            <!--<value>test.properties</value>-->
        <!--</property>-->
        <!--<property name="fileEncoding" value="utf-8" />-->
    <!--</bean>-->

    <bean id="itemBean" class="testSpEL.Item">
        <property name="itemId" value="#{111}"/>
        <property name="price" value="#{5300.0}"/>
        <!-- 注意字符串加单引号 -->
        <property name="description" value="#{'流畅IOS手机'}"/>
        <!-- 注入属性文件test.properties中的itemName -->
        <property name="itemName" value="${itemName}"/>
    </bean>

    <bean id="orderBean" class="testSpEL.Order">
        <!-- 注入上面配置的itemBean,与ref="itemBean"一样的效果 -->
        <property name="item" value="#{itemBean}"/>
    </bean>

</beans>

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,于是有了这篇文章,学无止境...


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值