- Spring EL表示式語言,這種語言jsp中學到的el,但是在整個spring之中其表示式語言要更加的複雜,而且支援度更加的廣泛,最重要的是他可以進行方法的呼叫,物件的例項化,集合操作等等,但是唯一的難點就是:程式碼太複雜了,表示式太複雜了。
- 深刻領會,spring中針對於字串的改進,程式設計師使用字串開發,絕對要比使用那些類簡單,所以在spring裡面無時無刻提供的就是字串的加強。
使用案例
字串的擷取
public class TestStringSub{
public static void main(String [] args){
String str = "hello world".subString(5,6);
System.out.println(str);
}
}
整個spring表示式操作之中可以將一個完全的字串變為了一個可以用於程式執行的語句,這繫系列的執行語句需要有一系列的支援類完成,但是至少我可以發現字串的功能又一次被加強了。
字串的擷取(SpringEL表示式)
public class TestStringSubExpression{
public static void main(String [] args){
String expression = "\"hello world\".subString(5,6)";
ExpressionParser expressionParser = new SpelExpressionParser();// 指定spelExpressionParser解析器實現類
Expression expression = parser.parseExpression(expression);//解析表示式
EvaluationContext context = new StandardEvaluationContext(expression);//設定物件模型基礎。
System.out.println(expression.getValue(evaluationContext);
}
}
封裝一個工具方法:
專門解析傳入物件的指定屬性數值,這裡做了下處理,如果獲取失敗,則直接返回當前傳入的屬性名稱,方便大家做靜態解析和動態解析,比如你傳入一個8,因為8的這個屬性肯定會不對,所以最後會返回一個8。
private static ExpressionParser expressionParser = new SpelExpressionParser();
public static Object getValueByExpression(Object targetObject,String propertyName){
try {
EvaluationContext evaluationContext = new StandardEvaluationContext();
evaluationContext.setVariable("model",targetObject);
Expression expression =expressionParser.parseExpression(String.format("#{#model.%s}",propertyName),new TemplateParserContext());
return expression.getValue(evaluationContext,Object.class);
} catch (ParseException e) {
log.warn("ParseException analysis the parameter is {}",propertyName);
} catch (EvaluationException e) {
log.warn("EvaluationException analysis the parameter is {}",propertyName);
}
return propertyName;
}
表示式解析器
org.springframework.expression.expressionparser
主要負責根據給定的表示式字串內容對解析器進行處理.
解析器處理類
org.springframework.expression.spel.standard.spelexpressionparsr
Expressionparser本身只是一個操作的標準,但是它對應的處理類必須單獨設定,本次使用的是spel的標準處理
表示式
org.springframework.expression.Expression
將字串根據指定的解析器進行解析,而後使用這個生成表示式:
設定表示式的一些屬性資訊:
org.springframework.expression.evaluationcontext
因為表示式操作之中可能會存在有某些佔位符需要進行處理
引數動態化傳入+解析操作
public class TestStringSubExpression{
public static void main(String [] args){
String expression = "\"hello world\".subString(#start,#end)";
ExpressionParser expressionParser = new SpelExpressionParser();// 指定spelExpressionParser解析器實現類
Expression expression = parser.parseExpression(expression);//解析表示式
EvaluationContext context = new StandardEvaluationContext(expression);//設定物件模型基礎。
context.setVariable("start",1);
context.setVariable("end",2);
System.out.println(expression.getValue(evaluationContext);
}
}
套用模板方法解析器
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;
public class Test {
public static void main(String[] args) {
//測試SpringEL解析器
String template = "#{#name},早上好";//設定文字模板,其中#{}表示表示式的起止,#user是表示式字串,表示引用一個變數。
ExpressionParser paser = new SpelExpressionParser();//建立表示式解析器
//通過evaluationContext.setVariable可以在上下文中設定變數。
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("name","Alex");
//解析表示式,如果表示式是一個模板表示式,需要為解析傳入模板解析器上下文。
Expression expression = paser.parseExpression(template,new TemplateParserContext());
//使用Expression.getValue()獲取表示式的值,這裡傳入了Evalution上下文,第二個引數是型別引數,表示返回值的型別。
System.out.println(expression.getValue(context,String.class));
}
}
表示式的處理原理
除了編寫字串之外還可以編寫數字.甚至各種字串的資料.
一定要首先對其一個判斷,判斷表示式應該由那些組成,而後要拆分組成的內容,最後要進行字串的相關資料型別的轉換,從而得出最終的計算結果.
- 首先明確的給出表示式,例如1+2
- 隨後需要準備出spel的表示式解析器,而進行解析的時候要按照如下的步驟.
- 使用一個專門的斷詞器,將給定的表示式字串拆分為spring可以認可的資料格式.
- 隨後要根據斷詞器的處理生成抽象語法樹
- 將已經處理後的表示式定義到一個專門的表示式物件之中等待進行最終的結果計算
- 考慮到表示式裡面可能會存在部分的佔位變數的內容,所以在進行表示式計算之前,需要設定一個表示式上下文物件進行佔位變數內容的處理.
- 最後設定了變數內容,並且利用表示式物件就可以計算出表示式最終所執行的結果
Spring自動的進行了操作的隱藏,用起來很方便
自定義分隔符
任何的表示式其組成之中一定會包含相應的邊界形式,例如:在jsp中的el裡面使用${表示式},在spring裡面,如果使用者有需要也可以定義我們的邊界.首先觀察解析表示式的操作類:Expressionparser
就是使用者自己設計邊界符的:
是否使用模板
boolean isTemplate();
邊界開始
String getExpressionPrefix();
邊界結束
String getExpressionSubffix();
使用匿名內部類的方式完成.可以在這步定義表示式的邊界.定義的表示式在計算的過程中都會自動的忽略掉,大部分我們不會用到自定義邊界。
Expression parser = new SpelExpressionParser().parseExpression(str,new ParserContext(){
public boolean isTemplate() {
return true;
}
public String getExpressionPrefix() {
return "[";
}
public String getExpressionSuffix() {
return "]";
}
});
// 預設的ParserContext
public interface ParserContext {
ParserContext TEMPLATE_EXPRESSION = new ParserContext() {
public boolean isTemplate() {
return true;
}
public String getExpressionPrefix() {
return "#{";
}
public String getExpressionSuffix() {
return "}";
}
};
boolean isTemplate();
String getExpressionPrefix();
String getExpressionSuffix();
}
基本表示式
字面表示式
- 數值型
- 布林型
- 字串
- null就是null
數學表示式
- 四則運算
Expression exp = parser.parseExpression("1+2+4+5/2");
- 求模
Expression exp = parser.parseExpression("1%2");
Expression exp = parser.parseExpression("1 MOD 2");
- 冪運算
Expression exp = parser.parseExpression("1 ^ 2");
- 除法
Expression exp = parser.parseExpression("1 / 2");
關係表示式
- 等於
Expression exp = parser.parseExpression("1 == 2");
Expression exp = parser.parseExpression("1 EQ 2");
- 不等於
Expression exp = parser.parseExpression("1 != 2");
Expression exp = parser.parseExpression("1 NE 2");
- 大於
Expression exp = parser.parseExpression("1 > 2");
Expression exp = parser.parseExpression("1 GT 2");
- 大於等於
Expression exp = parser.parseExpression("1 >= 2");
Expression exp = parser.parseExpression("1 GE 2");
- 區間
Expression exp = parser.parseExpression("1 BETWEEN {5,20}");
其他的以此類推就不過多贅述了!
邏輯表示式
- 與操作
Expression exp = parser.parseExpression("1 = 1 AND 2 = 2");
- 或操作
Expression exp = parser.parseExpression("1 = 1 or 2 = 2");
- 三目運算子
Expression exp = parser.parseExpression("1 > 1? 1:2);
Spring中#{}與${}的區別
#{}是SrpingEl表示式的語法規則.
例如:#{bean.屬性?:預設值},注意bean.屬性必須是要存在的,當為null時匹配
${}是Spring佔位符的語法規則
請注意它是否能用,跟bean的初始化時間有關.
例如:${屬性:預設值},如果屬性為null或者不存在的話,就是用預設值填充
使用案例大全
- @Value("${test.username}"):注意這樣是錯誤的.$符號不是El表示式的取值方式.
- @Value("#{test.xxx.other}"):注意這樣是錯誤的,"."這個點不能連續使用.不知道怎麼轉義
- @Value("#{test.usernameXX?:'預設的username'}"):注意這樣是錯誤的,如果想使用預設值你需要確保test這類以及usernameXX這個屬性必須存在
@Value("#{test.username?:'預設的username'}")
private String userName;
@Value("#{test.password}")
private Integer password;
@Value("${username}")
private String userName;
@Value("${other.undefindValue}") // 直接使用屬性名稱輸入
@Value("${xxxxx:other.undefindValue}") // 當xxxxx不存在時,使用other.undefindValue進行賦值
@Value("${xxxxx:123}") // 當xxxxx不存在時,使用123進行賦值
private Integer password;
@Value("${other.undefindValue}")
private String undefindValue;
當然你還可以通過Environment物件進行獲取哦!
// 申明bean需要使用的resource
@PropertySource("classpath:config.properties")
public class ClazzName{
// 獲取resource
@Autowired private Environment environment;
/** 獲取config配置檔案 */
public String getStr(String key){
return environment.getProperty(key);
}
}