<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
是強大的表示式語言,支援查詢、操作執行時物件圖,以及解析邏輯、算術表示式。SpEL可以獨立使用,無論你是否使用Spring框架。
本文嘗試通過多個範例使用SpEL,探索其強大能力。
引入依賴:
compile group: 'org.springframework', name: 'spring-expression', version: '5.2.4.RELEASE'
讀者可以選擇最新版本或合適的版本。當然也可以下載相應jar檔案。在呼叫下面的函數之前,按如下方式初始化一個類級屬性SpelExpression解析器:
import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; public class ElMain { private ExpressionParser parser; ElMain(){ parser = new SpelExpressionParser(); } public static void main(String[] args) { ElMain elHelper = new ElMain(); elHelper.evaluateLiteralExpresssions(); } private static void print(Object message){ System.out.println(message); }
2.1. 解析直接文字
private void evaluateLiteralExpresssions() { Expression exp = parser.parseExpression("'Hello World'"); String message = (String) exp.getValue(); print(message); exp = parser.parseExpression("6"); Integer value = exp.getValue(Integer.class); print(value*2); }
這裡直接解決字串及數位文字。
2.2. 直接文字上呼叫方法
/** * A function that tests method invocation on literals */ private void methodInvocationOnLiterals() { Expression exp = parser.parseExpression("'Hello World'.concat('!')"); String message = (String) exp.getValue(); println(message); exp = parser.parseExpression("'Hello World'.length()"); Integer size = exp.getValue(Integer.class); println(size); exp = parser.parseExpression("'Hello World'.split(' ')[0]"); message = (String)exp.getValue(); println(message); }
範例展示了在字串上直接呼叫Java String類的public方法。
2.3.存取物件屬性和方法
/**A function that tests accessing properties of objects**/ private void accessingObjectProperties() { User user = new User("John", "Doe", true, "john.doe@acme.com",30); Expression exp = parser.parseExpression("firstName"); println((String)exp.getValue(user)); exp = parser.parseExpression("isAdmin()==false"); boolean isAdmin = exp.getValue(user, Boolean.class); println(isAdmin); exp = parser.parseExpression("email.split('@')[0]"); String emailId = exp.getValue(user, String.class); println(emailId); exp = parser.parseExpression("age"); Integer age = exp.getValue(user, Integer.class); println(age); }
表示式可以直接使用物件的屬性與方法。我們看到方法與屬性使用一樣,只是多了呼叫括號。
2.4.執行各種操作(比較、邏輯、算術)
SpEl支援下面幾種操作:
private void operators() { User user = new User("John", "Doe", true,"john.doe@acme.com", 30); Expression exp = parser.parseExpression("age > 18"); println(exp.getValue(user,Boolean.class)); exp = parser.parseExpression("age < 18 and isAdmin()"); println(exp.getValue(user,Boolean.class)); }
2.5.使用多個物件和變數
表示式不僅需要參照物件,而且可能需要參照多個不同型別的物件。我們可以把所有使用的物件都加入至上下文中。使用鍵值對的方式加入並參照。
private void variables() { User user = new User("John", "Doe", true, "john.doe@acme.com",30); Application app = new Application("Facebook", false); StandardEvaluationContext context = new StandardEvaluationContext(); context.setVariable("user", user); context.setVariable("app", app); Expression exp = parser.parseExpression("#user.isAdmin() and #app.isActive()"); Boolean result = exp.getValue(context,Boolean.class); println(result); }
2.6.呼叫自定義函數
SpEl也可以呼叫自定義的函數,使用者可以擴充套件業務邏輯。下面首先定義一個函數:
public class StringHelper { public static boolean isValid(String url){ return true; } }
下面在SpEl中呼叫isValid方法:
private void customFunctions() { try { StandardEvaluationContext context = new StandardEvaluationContext(); context.registerFunction("isURLValid", StringHelper.class.getDeclaredMethod("isValid", new Class[] { String.class })); String expression = "#isURLValid('http://google.com')"; Boolean isValid = parser.parseExpression(expression).getValue(context, Boolean.class); println(isValid); } catch (Exception e) { e.printStackTrace(); } }
通過範例介紹了SpEl中多種應用場景。讀者可以利用這些功能實現更加靈活的功能應用。
Spring 表示式語言(簡稱SpEL):是一個支援執行時查詢和操作物件圖的強大的表示式語言。
語法類似於 EL:SpEL 使用 #{…} 作為定界符,所有在大框號中的字元都將被認為是 SpEL
SpEL 為 bean 的屬性進行動態賦值提供了便利.
通過 SpEL 可以實現:
字面量的表示:
整數: <property name="count" value="#{5}"/> 小數: <property name="frequency" value="#{89.7}"/> 科學計數法: <property name="capacity" value="#{1e4}"/> String可以使用單引號或者雙引號作為字串的定界符號: <property name=「name」 value="#{'Chuck'}"/> 或 <property name='name' value='#{"Chuck"}'/> Boolean: <property name="enabled" value="#{false}"/>
如果僅僅是表示字面量,其實是沒有必要使用Spring EL表示式的,這裡僅僅演示一下而已,日常的開發中很少使用。
參照其他物件
但是我們更常用ref 來實現其他物件的參照
參照其他物件的屬性
呼叫其他方法,還可以鏈式操作
呼叫靜態方法或靜態屬性
通過 T() 呼叫一個類的靜態方法,它將返回一個 Class Object,然後再呼叫相應的方法或屬性:
算數運運算元:+, -, *, /, %, ^
加號還可以用作字串連線
比較運運算元: <, >, ==, <=, >=, lt, gt, eq, le, ge
邏輯運運算元號: and, or, not, |
if-else 運運算元:?: (ternary), ?: (Elvis)
if-else 的變體
正規表示式:matches
package com.xgj.spel; /** * * * @ClassName: Address * * @Description: 地址資訊 * * @author: Mr.Yang * * @date: 2018年4月7日 下午8:29:12 */ public class Address { private String city; private String street; public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } @Override public String toString() { return "Address [city=" + city + ", street=" + street + ", getClass()=" + getClass() + ", hashCode()=" + hashCode() + ", toString()=" + super.toString() + "]"; } }
package com.xgj.spel; /** * * * @ClassName: Car * * @Description: 車輛 * * @author: Mr.Yang * * @date: 2018年4月7日 下午8:30:01 */ public class Car { private String brand; private double price; // 呼叫靜態方法或靜態屬性:通過 T() 呼叫一個類的靜態方法,它將返回一個 Class Object,然後再呼叫相應的方法或屬性 private long weight; public long getWeight() { return weight; } public void setWeight(long weight) { this.weight = weight; } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } @Override public String toString() { return "Car [brand=" + brand + ", price=" + price + ", weight=" + weight + "]"; } }
package com.xgj.spel; public class Boss { private String name; private Car car; // 通過 Spring El 參照 Address的city private String city; // 通過 Car的price屬性,確定info ,如果car.price>=500000 ,info 為CEO,否則為 Staff private String info; public String getName() { return name; } public void setName(String name) { this.name = name; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } @Override public String toString() { return "Boss [name=" + name + ", car=" + car + ", city=" + city + ", info=" + info + "]"; } }
組態檔:
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="car" class="com.xgj.spel.Car" p:brand="Bench" p:price="700000" p:weight="#{T(java.lang.Math).PI * 4567}" /> <!-- 通過Spring El表示式為屬性賦值一個字面值 , 當然了,如果是字面值就沒有必要使用Spring El表示式了,這裡僅僅是演示該用法 --> <bean id="address" class="com.xgj.spel.Address" p:city="#{'NanJing'}" p:street="RuanJianDaDao" /> <bean id="boss" class="com.xgj.spel.Boss" p:name="Artisan" p:city="#{address.city}" p:car-ref="car" p:info="#{car.price > 500000 ? 'CEO' : 'staff'}" /> </beans>
測試類:
package com.xgj.spel; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpelTest { public static void main(String[] args) { String configLocation = "com/xgj/spel/beans_spel.xml"; ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocation); Car car = (Car) ctx.getBean("car"); System.out.println(car); Boss boss = (Boss) ctx.getBean("boss"); System.out.println(boss); } }
結果:
2018-04-07 21:21:30,804 INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@4af6178d: startup date [Sat Apr 07 21:21:30 BOT 2018]; root of context hierarchy
2018-04-07 21:21:30,907 INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/spel/beans_spel.xml]
Car [brand=Bench, price=700000.0, weight=14347]
Boss [name=Artisan, car=Car [brand=Bench, price=700000.0, weight=14347], city=NanJing, info=CEO]
範例-基於註解的方式
我們通過一個資料庫的例子來演示。雖然可以通過Spring El 表示式從組態檔中載入一個引數值,比如
@Value("#{properties['jdbc.driverClassName']}")
是不是容易出錯…. Spring提供了更好的方式 context:property-placeholder。
package com.xgj.spel.annotation; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** * * * @ClassName: MyDataSource * * @Description: 資料來源 @Component標註 * * @author: Mr.Yang * * @date: 2018年4月7日 下午9:26:32 */ @Component public class MyDataSource { private String driverClass; private String url; private String username; private String password; public String getDriverClass() { return driverClass; } /** * * * @Title: setDriverClass * * @Description: @Value註解自動注入屬性組態檔中對應屬性的值 * * @param driverClass * * @return: void */ @Value("${jdbc.driverClassName}") public void setDriverClass(String driverClass) { this.driverClass = driverClass; } public String getUrl() { return url; } @Value("${jdbc.url}") public void setUrl(String url) { this.url = url; } public String getUsername() { return username; } // @Value("$(jdbc.username)") @Value("${jdbc.username}") public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } @Value("${jdbc.password}") public void setPassword(String password) { this.password = password; } @Override public String toString() { return "MyDataSource [driverClass=" + driverClass + ", url=" + url + ", username=" + username + ", password=" + password + "]"; } }
<?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:p="http://www.springframework.org/schema/p" 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-4.3.xsd"> <!-- 掃描的基包 --> <context:component-scan base-package="com.xgj.spel.annotation"/> <!-- 載入外部properties檔案 --> <context:property-placeholder location="classpath:mysql/db_mysql.properties"/> </beans>
db_mysql.properties
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/artisan jdbc.username=artisan jdbc.password=artisan
package com.xgj.spel.annotation; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestCase { @Test public void test() { String configurationLocation = "com/xgj/spel/annotation/beans_anno.xml"; ApplicationContext ctx = new ClassPathXmlApplicationContext(configurationLocation); MyDataSource myDataSource = (MyDataSource) ctx.getBean("myDataSource"); System.out.println(myDataSource); System.out.println("driverClassName:" + myDataSource.getDriverClass()); System.out.println("url:" + myDataSource.getUrl()); System.out.println("username:" + myDataSource.getUsername()); System.out.println("password:" + myDataSource.getPassword()); } }
執行結果
2018-04-07 23:37:11,409 INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@761df304: startup date [Sat Apr 07 23:37:11 BOT 2018]; root of context hierarchy
2018-04-07 23:37:11,552 INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/spel/annotation/beans_anno.xml]
MyDataSource [driverClass=com.mysql.jdbc.Driver, url=jdbc:mysql://localhost:3306/artisan, username=artisan, password=artisan]
driverClassName:com.mysql.jdbc.Driver
url:jdbc:mysql://localhost:3306/artisan
username:artisan
password:artisan
以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45