Spring(23)——SPEL表示式(四)

weixin_33858249發表於2017-09-18

23.2.24 設定預設值

SpEl表示式中支援“a?:b”這樣的語法來設定預設值。其表示如果a不為null時其結果為a,否則就為b。

@Test
public void test24 () {
	ExpressionParser parser = new SpelExpressionParser();
	Assert.assertTrue(parser.parseExpression("#abc?:123").getValue().equals(123));//變數abc不存在
	Assert.assertTrue(parser.parseExpression("1?:123").getValue().equals(1));//數字1不為null
}

23.2.25 安全導航

我們可能經常會使用類似於“a.b.c”這樣的用法,表示a的b屬性的c屬性,但如果a為null或者a的b屬性為null時都會出現空指標。為了避免此種情況發生,我們可以在SpEl表示式中使用安全導航,這樣當a為null或a的b屬性為null時將直接返回null,而不丟擲空指標異常。SpEl表示式中安全導航的語法是將點“.”替換為“?.”,即不使用“a.b.c”,而是使用“a?.b?.c”。

@Test
public void test25 () {
	ExpressionParser parser = new SpelExpressionParser();
	Assert.assertNull(parser.parseExpression("null?.abc").getValue());
	Assert.assertNull(parser.parseExpression("T(System)?.getProperty('abc')?.length()").getValue());//數字1不為null
}

23.2.26 獲取bean物件

在SpEL表示式裡面也可以直接訪問bean物件,前提是指定了一個BeanResolver。BeanResolver是一個介面,其只定義了一個方法resolve,用以通過beanName解析為對應的bean物件並返回,具體定義如下。

public interface BeanResolver {

	Object resolve(EvaluationContext context, String beanName) throws AccessException;

}

如果要在SpEL表示式中訪問bean物件,我們需要通過StandardEvaluationContext來設定對應的BeanResolver,同時我們需要在SpEL表示式中以“@beanName”的方式來訪問對應的bean物件。如下是一段示例程式碼,我們在表示式中獲取到了名稱為hello的bean物件,並訪問了其getKey()方法。

@Test
public void test26() {
	ExpressionParser parser = new SpelExpressionParser();
	StandardEvaluationContext context = new StandardEvaluationContext();
	context.setBeanResolver(new MyBeanResolver());
	//訪問bean名稱為hello的bean物件的getKey()方法。
	Object obj = parser.parseExpression("@hello.key").getValue(context);
	System.out.println(obj);
}

private static class MyBeanResolver implements BeanResolver {

	private static ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
	
	public Object resolve(EvaluationContext context, String beanName)
			throws AccessException {
		return appContext.getBean(beanName);
	}
	
}

23.3 SpelParserConfiguration

在構建SpelExpressionParser時我們可以給其傳遞一個SpelParserConfiguration物件以對SpelExpressionParser進行配置。其可以用於指定在遇到List或Array為null時是否自動new一個對應的例項,對應SpelParserConfiguration的第一個構造引數;也可以指定在List或Array中對應索引超出了當前索引的最大值時是否自動進行擴充,對應SpelParserConfiguration的第二個構造引數,更多資訊請參考Spring的API文件。如下示例中我們就使用了SpelParserConfiguration物件,指定了在對應的List或Array為null時自動new一個對應的物件,並且在對應的索引超出了List或Array當前的最大索引時自動對其進行擴充。所以如下示例中在我們第一次訪問User的interests時其為null,之後第二次訪問時,由於指定了將自動new對應的物件並且在索引超出時自動進行擴充,所以將new一個List的例項,對應ArrayList,且在索引5不存在時將自動擴充並進行填值,填值時將對List的元素型別String new 6次。所以對於這種情況我們需要保證List或Array中存放的元素型別存在無參構造方法。

class User {
	public List<String> interests;
}

@Test
public void test() {
	User user = new User();
	SpelParserConfiguration parserConfig = new SpelParserConfiguration(true, true);
	ExpressionParser parser = new SpelExpressionParser(parserConfig);
	//第一次為null
	Assert.assertNull(parser.parseExpression("interests").getValue(user));
	//自動new一個List的例項,對應ArrayList,並自動new String()新增6次。
	Assert.assertTrue(parser.parseExpression("interests[5]").getValue(user).equals(""));
	//size為6
	Assert.assertTrue(parser.parseExpression("interests.size()").getValue(user).equals(6));
}

23.4 在bean定義中使用SpEl

在bean定義中使用SpEl表示式的語法是“#{exp}”。exp就是對應的表示式。如下示例中我們定義了一個名為hello的bean,在指定其userDir時我們使用了表示式。

<bean id="hello" class="com.app.Hello">
	<property name="userDir" value="#{T(System).getProperty('user.dir')}"/>
</bean>

對於系統屬性而言,在bean定義中使用時有一個內建的變數可以使用叫systemProperties,而且在使用時不需要加“#”,即不需要以“#systemProperties”的形式出現。所以上述示例也可以是如下這樣。

<bean id="hello" class="com.elim.learn.spring.bean.Hello">
	<property name="userDir" value="#{systemProperties['user.dir']}"/>
</bean>

23.4.1 引用其它bean的屬性

在進行bean定義時,我們也可以通過表示式引用其它bean定義的屬性。如下示例中我們就在定義id為world的bean的key屬性時通過表示式引用了名為hello的bean的key屬性,即world的key屬性也將被賦予值“abc”。

<bean id="hello" class="com.app.Hello">
	<property name="key" value="abc"/>
</bean>

<bean id="world" class="com.app.World">
	<property name="key" value="#{hello.key}"/>
</bean>

23.4.2 基於註解配置的使用

在基於註解配置的bean定義中我們也可以使用SpEl表示式進行某些定義。在基於註解配置bean定義時我們可以使用@Value註解定義在方法或屬性上來指定對應的值。此時我們就可以使用對應的表示式,當然不使用表示式也是可以的。如下示例中我們就通過@Value指定了userDir和key的值。其中userDir的值的定義使用了SpEl表示式,而key的值的定義是直接定義的。

public class Hello {

	@Value("#{systemProperties['user.dir']}")
	private String userDir;
	@Value("abc")
	private String key;

	public String getUserDir() {
		return userDir;
	}

	public void setUserDir(String userDir) {
		this.userDir = userDir;
	}

	public String getKey() {
		return key;
	}

	public void setKey(String key) {
		this.key = key;
	}

}

(注:本文是基於Spring4.1.0所寫)

相關文章