מדריך לשפת ביטוי האביב

1. סקירה כללית

שפת הביטוי האביבית (SpEL) היא שפת ביטוי עוצמתית התומכת בשאילתת מניפולציה של גרף עצמים בזמן הריצה. ניתן להשתמש בו עם תצורות אביב מבוססות XML או הערות.

ישנם מספר מפעילים הזמינים בשפה:

סוּגמפעילים
חֶשְׁבּוֹן+, -, *, /,%, ^, div, mod
יחסיים, ==,! =, =, lt, gt, eq, ne, le, ge
הגיוניו, או, לא, &&, ||,!
מותנה?:
רגקסהתאמות

2. מפעילים

לדוגמאות אלה נשתמש בתצורה מבוססת ביאור. ניתן למצוא פרטים נוספים על תצורת XML בחלקים מאוחרים יותר של מאמר זה.

ביטויי SpEL מתחילים עם # סמל, ועטופים בסוגרים: #{ביטוי}. ניתן להתייחס למאפיינים באופן דומה, החל מ- $ סמל, ועטוף בסוגרים: $ {property.name}. מצייני מיקום של נכסים אינם יכולים להכיל ביטויי SpEL, אך ביטויים יכולים להכיל הפניות למאפיינים:

# {$ {someProperty} + 2}

בדוגמא לעיל, נניח someProperty יש ערך 2, כך שהביטוי המתקבל יהיה 2 + 2, שיוערך ל -4.

2.1. מפעילי חשבון

כל המפעילים האריתמטיים הבסיסיים נתמכים.

@Value ("# {19 + 1}") // 20 הוספה כפולה פרטית; @Value ("# {'String1' + 'string2'}") // "String1 string2" פרטי מחרוזת addString; @Value ("# {20 - 1}") // 19 חיסור כפול פרטי; @Value ("# {10 * 2}") // כפול כפול פרטי; @Value ("# {36/2}") // 19 חלוקה כפולה פרטית; @Value ("# {36 div 2}") // 18, זהה לחלוקה כפולה פרטית עבור / operator, Alfabetisk; @Value ("# {37% 10}") // 7 מודול כפול פרטי; @Value ("# {37 mod 10}") // 7, זהה לאופרטור% כפול פרטי moduloAlphabetic; @Value ("# {2 ^ 9}") // 512 powerOf כפול פרטי; @Value ("# {(2 + 2) * 2 + 9}") // 17 סוגריים כפולים פרטיים; 

לפעולות חלוקה ומודולו יש כינויים אלפביתיים, div ל / ו mod ל %. ה + ניתן להשתמש באופרטור גם לשרשור מחרוזות.

2.2. מפעילים יחסיים והגיוניים

כל הפעולות היחסיות והלוגיות הבסיסיות נתמכות גם כן.

@Value ("# {1 == 1}") // שווה בוליאנית פרטית אמיתית; @Value ("# {1 eq 1}") // שווה ערך בוליאני פרטי אמיתי; @Value ("# {1! = 1}") // בוליאנית פרטית כוזבת notEqual; @Value ("# {1 ne 1}") // בוליאני פרטי שווא notEqualAlphabetic; @Value ("# {1 <1}") // שווא פרטי בוליאני lessThan; @Value ("# {1 lt 1}") // בוליאני פרטי שגוי פחות ThanAlphabetic; @Value ("# {1 1}") // שווא פרטי בוליאני גדול יותר; @Value ("# {1 gt 1}") // בוליאני פרטי שגוי גדול יותר ThanAlphabetic; @Value ("# {1> = 1}") // גדול יותר בוליאני גדול יותר ThanOrEqual; @Value ("# {1 ge 1}") // בוליאני פרטי אמיתי גדול יותר ThanOrEqualAlphabetic; 

לכל מפעילי ההתייחסות יש כינויים אלפביתיים. לדוגמא, בתצורות מבוססות XML איננו יכולים להשתמש במפעילים המכילים סוגריים זוויתיים (<, <=,>, >=). במקום זאת, אנו יכולים להשתמש לט (פחות מ), le (פחות מ או שווה), gt (גדול מ-), או ge (גדול או שווה).

2.3. פעולות לוגיות

SpEL תומך בכל הפעולות הלוגיות הבסיסיות:

@Value ("#") // בוליאני פרטי או אלפביתי אמיתי; @Value ("# {! True}") // בוליאני פרטי שווא לא; @Value ("# {not true}") // בוליאני פרטי שווא notAlphabetic;

כמו במפעילי חשבון ומערכת יחסים, לכל המפעילים ההגיוניים יש גם שיבוטים אלפביתיים.

2.4. מפעילים מותנים

אופרטורים מותנים משמשים להזרקת ערכים שונים בהתאם למצב כלשהו:

@Value ("# {2> 1? 'A': 'b'}") // "a" מחרוזת פרטית;

האופרטור המשולש משמש לביצוע לוגיקה מותנית קומפקטית אם-אז-אחרת בתוך הביטוי. בדוגמה זו אנו מנסים לבדוק אם היה נָכוֹן או שלא.

שימוש נפוץ נוסף עבור המפעיל השלישי הוא לבדוק אם משתנה כלשהו הוא ריק ואז להחזיר את ערך המשתנה או ברירת מחדל:

@Value ("# {someBean.someProperty! = Null? SomeBean.someProperty: 'default'}") פרטי מחרוזת שלישית;

מפעיל אלביס הוא דרך לקיצור התחביר של המפעיל התלת-ממדי למקרה לעיל המשמש בשפה הגרובית. זה זמין גם ב- SpEL. הקוד שלהלן שווה לקוד שלמעלה:

@Value ("# {someBean.someProperty?: 'Default'}") // יזריק מחרוזת שסופקה אם someProperty הוא אפס פרטי מחרוזת;

2.5. שימוש ב- Regex ב- SpEL

ה התאמות ניתן להשתמש במפעיל כדי לבדוק אם מחרוזת תואמת ביטוי קבוע נתון או לא.

@Value ("# {'100' מתאים '\ d +'}") // אמת בוליאנית פרטית validNumericStringResult; @Value ("# {'100fghdjf' matches '\ d +'}") // false בוליאני פרטי שגוי invalidNumericStringResult; @Value ("# {'מחרוזת אלפביתית חוקית' תואמת '[a-zA-Z \ s] +'}") // אמת בוליאנית פרטית אמיתית validAlphabeticStringResult; @Value ("# {'מחרוזת אלפביתית לא חוקית # $ 1' תואמת '[a-zA-Z \ s] +'}") // שגויה בוליאנית פרטית שגויה invalidAlphabeticStringResult; @Value ("# {someBean.someValue תואם '\ d +'}") // נכון אם someValue מכיל ספרות בלבד בוליאני validNumericValue;

2.6. ניגש רשימה ו מַפָּה חפצים

בעזרת SpEL אנו יכולים לגשת לתוכן של כל אחד מהם מַפָּה אוֹ רשימה בהקשר. ניצור שעועית חדשה עובדים מחזיק שיאחסן מידע אודות עובדים מסוימים ומשכורתם בא רשימה ו מַפָּה:

@Component ("workersHolder") מחלקה ציבורית WorkersHolder {עובדים פרטיים ברשימה = חדש LinkedList (); משכורת מפה פרטית salByWorkers = HashMap חדש (); Public WorkHolder () {workers.add ("ג'ון"); workers.add ("סוזי"); workers.add ("אלכס"); workers.add ("ג'ורג '"); salaryByWorkers.put ("ג'ון", 35000); salaryByWorkers.put ("סוזי", 47000); salaryByWorkers.put ("אלכס", 12000); salaryByWorkers.put ("ג'ורג '", 14000); } // גטרים וקובעים}

כעת אנו יכולים לגשת לערכי האוספים באמצעות SpEL:

@Value ("# {workersHolder.salaryByWorkers ['John']}") // 35000 שלם פרטי johnSalary; @Value ("# {workersHolder.salaryByWorkers ['George']}") // 14000 שלם פרטי georgeSalary; @Value ("# {workersHolder.salaryByWorkers ['Susie']}") // 47000 susieSalary פרטי שלם; @Value ("# {workersHolder.workers [0]}") // John Private String WorkWorker; @Value ("# {workersHolder.workers [3]}") // ג'ורג 'פרטי מחרוזת lastWorker; @Value ("# {workersHolder.workers.size ()}") // 4 מספר מספר שלם פרטיOfWorkers;

3. השתמש בתצורת האביב

3.1. הפניה לשעועית

בדוגמה זו נבדוק כיצד להשתמש ב- SpEL בתצורה מבוססת XML. ניתן להשתמש בביטויים להפניה של שעועית או שדות שעועית / שיטות. לדוגמה, נניח שיש לנו את השיעורים הבאים:

מנוע ברמה ציבורית {קיבולת אינטראקטיבית פרטית; כניסה פרטית פרטית; מספר אינטראקטיבי פרטיOfCylinders; // גטרים וקובעים} רכב בכיתה ציבורית {פרטי מיתרים פרטיים; מודל אינטי פרטי; מנוע מנוע פרטי; פרטי int horsePower; // גטרים וקובעים}

כעת אנו יוצרים הקשר יישומי שבו משתמשים בביטויים להזרקת ערכים:

תסתכל על someCar אפונה. ה מנוע ו כוח סוס שדות של someCar השתמש בביטויים שהם הפניות לשעועית מנוע שעועית ו כוח סוס שדה בהתאמה.

כדי לעשות את אותו הדבר בתצורות מבוססות הערות, השתמש ב @Value ("# {expression}") ביאור.

3.2. שימוש במפעילים בתצורה

כל מפעיל מהקטע הראשון במאמר זה יכול לשמש בתצורות מבוססות XML והערות. עם זאת, זכור שבתצורה מבוססת XML, איננו יכולים להשתמש במפעיל סוגר הזווית "<". במקום זאת, עלינו להשתמש בכינויים האלפביתיים, כגון לט (פחות מ) או le (פחות או שווה). עבור תצורות מבוססות הערות, אין הגבלות כאלה.

מעמד ציבורי SpelOperators {שווים בוליאניים פרטיים; פרטי בוליאני לא שווה; פרטית בוליאנית גדולה יותרThanOrEqual; בוליאני פרטי ו; בוליאני פרטי או; פרטי מחרוזת addString; // גטרים וקובעים
 @ עקירה ציבורית מחרוזת toString () {// toString הכוללת את כל השדות}

כעת נוסיף א משחקים שעועית להקשר היישום:

   = 6} "/> 300 או someCar.engine.capacity> 3000}" />

כשמשחזרים את השעועית מההקשר, נוכל לוודא שהערכים הוזרקו כראוי:

ApplicationContext context = חדש ClassPathXmlApplicationContext ("applicationContext.xml"); SpelOperators spelOperators = (SpelOperators) context.getBean ("spelOperators"); 

כאן אנו יכולים לראות את הפלט של ה- toString שיטה של משחקים אפונה:

[שווה = true, notEqual = false, greaterThanOrEqual = true, ו- = true, או = true, addString = דגם כלשהו המיוצר על ידי חלק מהיצורים] 

4. ניתוח ביטויים באופן פרוגרמטי

לעיתים, נרצה לנתח ביטויים מחוץ להקשר התצורה. למרבה המזל, זה אפשרי באמצעות SpelExpressionParser. אנו יכולים להשתמש בכל האופרטורים שראינו בדוגמאות הקודמות, אך עלינו להשתמש בהם ללא סוגר וסמל hash. כלומר, אם אנו רוצים להשתמש בביטוי עם ה- + כאשר משתמשים בתצורת אביב, התחביר הוא #{1 + 1}; כאשר משתמשים בו מחוץ לתצורה, התחביר הוא פשוט 1 + 1.

בדוגמאות הבאות נשתמש ב- אוטו ו מנוע שעועית שהוגדרה בסעיף הקודם.

4.1. באמצעות ExpressionParser

בואו נסתכל על דוגמה פשוטה:

ExpressionParser expressionParser = SpelExpressionParser חדש (); ביטוי ביטוי = expressionParser.parseExpression ("'כל מחרוזת'"); תוצאת מחרוזת = (מחרוזת) expression.getValue (); 

ExpressionParser אחראי על ניתוח מחרוזות הביטוי. בדוגמה זו, מנתח SpEL פשוט יעריך את המחרוזת 'כל מחרוזת' כביטוי. באופן לא מפתיע, התוצאה תהיה 'כל מחרוזת'.

כמו בשימוש ב- SpEL בתצורה, אנו יכולים להשתמש בו בכדי להתקשר לשיטות, לגשת למאפיינים או לבנות שיחות.

ביטוי ביטוי = expressionParser.parseExpression ("'כל מחרוזת'. אורך ()"); תוצאה שלמה = (Integer) expression.getValue ();

בנוסף, במקום לפעול ישירות על המילולי, נוכל להתקשר לבנאי:

ביטוי ביטוי = expressionParser.parseExpression ("מחרוזת חדשה ('כל מחרוזת'). אורך ()");

אנחנו יכולים גם לגשת ל בתים רכוש של חוּט class, באותו אופן, וכתוצאה מכך ייצוג הבייט [] של המחרוזת:

ביטוי ביטוי = expressionParser.parseExpression ("'כל מחרוזת'. בתים"); בתים [] תוצאה = (בתים []) expression.getValue ();

אנו יכולים לשרשר שיחות בשיטה, בדיוק כמו בקוד Java רגיל:

ביטוי ביטוי = expressionParser.parseExpression ("'כל מחרוזת'. מקום (\" \ ", \" \ "). אורך ()"); תוצאה שלמה = (שלם) expression.getValue ();

במקרה זה התוצאה תהיה 9 מכיוון שהחלפנו את המרחב הלבן במחרוזת הריקה. אם איננו מעוניינים להטיל את תוצאת הביטוי, נוכל להשתמש בשיטה הגנרית T getValue (Class wantedResultType), בו אנו יכולים לספק את סוג הכיתה הרצוי אותו אנו רוצים שיוחזרו. ציין זאת EvaluationException יושלך אם לא ניתן להעביר את הערך המוחזר wantedResultType:

תוצאה שלמה = expression.getValue (Integer.class);

השימוש הנפוץ ביותר הוא לספק מחרוזת ביטוי המוערכת על פי מופע ספציפי של אובייקט:

מכונית לרכב = מכונית חדשה (); car.setMake ("יצרן טוב"); car.setModel ("דגם 3"); car.setYearOfProduction (2014); ExpressionParser expressionParser = SpelExpressionParser חדש (); ביטוי ביטוי = expressionParser.parseExpression ("מודל"); EvaluationContext context = StandardEvaluationContext חדש (רכב); תוצאת מחרוזת = (מחרוזת) expression.getValue (הקשר);

במקרה זה, התוצאה תהיה שווה לערך ה- דֶגֶם שדה של אוטו חפץ, “דגם 3". ה StandardEvaluationContext מחלקה מציינת מול איזה אובייקט יוערך הביטוי.

לא ניתן לשנותו לאחר יצירת אובייקט ההקשר. StandardEvaluationContext הוא יקר לבנייה, ובמהלך שימוש חוזר, הוא בונה מצב במטמון המאפשר לבצע הערכות ביטוי עוקבות במהירות רבה יותר. בגלל שמירה במטמון כדאי להשתמש שוב StandardEvaluationContext איפה זה אפשרי אם עצם השורש לא ישתנה.

עם זאת, אם אובייקט השורש ישתנה שוב ושוב, נוכל להשתמש במנגנון המוצג בדוגמה שלהלן:

ביטוי ביטוי = expressionParser.parseExpression ("מודל"); תוצאה מחרוזת = (מחרוזת) expression.getValue (מכונית);

הנה, אנו קוראים getValue שיטה עם טיעון המייצג את האובייקט עליו אנו רוצים להחיל ביטוי SpEL. אנחנו יכולים גם להשתמש בגנרי getValue שיטה, בדיוק כמו קודם:

ביטוי ביטוי = expressionParser.parseExpression ("yearOfProduction> 2005"); תוצאה בוליאנית = expression.getValue (מכונית, Boolean.class);

4.2. באמצעות ExpressionParser להגדיר ערך

משתמש ב הגדר ערך שיטה על ביטוי אובייקט שהוחזר על ידי ניתוח ביטוי, אנו יכולים להגדיר ערכים על אובייקטים. SpEL ידאג להמרת סוג. כברירת מחדל, SpEL משתמש org.springframework.core.convert.ConversionService. אנו יכולים ליצור ממיר מותאם אישית משלנו בין סוגים. ConversionService מודע לגנריות, ולכן ניתן להשתמש בו עם גנריות. בואו נסתכל כיצד נוכל להשתמש בו בפועל:

מכונית לרכב = מכונית חדשה (); car.setMake ("יצרן טוב"); car.setModel ("דגם 3"); car.setYearOfProduction (2014); CarPark carPark = CarPark חדש (); carPark.getCars (). להוסיף (רכב); StandardEvaluationContext context = חדש StandardEvaluationContext (carPark); ExpressionParser expressionParser = SpelExpressionParser חדש (); expressionParser.parseExpression ("מכוניות [0] .מודל"). setValue (הקשר, "דגם אחר");

לאובייקט המכונית שנוצר יהיה דֶגֶםדגם אחר"שהשתנה מ"דגם 3“.

4.3. תצורת מנתח

בדוגמה הבאה נשתמש במחלקה הבאה:

CarPark בכיתה ציבורית {מכוניות ברשימה פרטית = ArrayList חדש (); // גטר וסתר}

אפשר להגדיר ExpressionParser על ידי קריאה לבנאי עם א SpelParserConfiguration לְהִתְנַגֵד. למשל, אם ננסה להוסיף אוטו חפץ לתוך מכוניות מגוון של חניון ללא הגדרת המנתח, נקבל שגיאה כזו:

EL1025E: (pos 4): באוסף יש אלמנטים '0', אינדקס '0' אינו חוקי

אנו יכולים לשנות את התנהגות המנתח, כדי לאפשר לו ליצור באופן אוטומטי אלמנטים אם האינדקס שצוין הוא null (autoGrowNullReferences, הפרמטר הראשון לבנאי), או להגדיל באופן אוטומטי מערך או רשימה כדי להתאים לאלמנטים מעבר לגודל הראשוני שלהם (autoGrowCollections, הפרמטר השני).

SpelParserConfiguration config = SpelParserConfiguration חדש (נכון, נכון); StandardEvaluationContext context = חדש StandardEvaluationContext (carPark); ExpressionParser expressionParser = SpelExpressionParser חדש (config); expressionParser.parseExpression ("מכוניות [0]"). setValue (הקשר, מכונית); תוצאת מכונית = carPark.getCars (). Get (0);

כתוצאה מכך אוטו האובייקט יהיה שווה ל- אוטו אובייקט אשר הוגדר כאלמנט הראשון של מכוניות מגוון של חניון אובייקט מהדוגמה הקודמת.

5. מסקנה

SpEL היא שפת ביטוי חזקה ונתמכת, שניתן להשתמש בה בכל המוצרים בתיק האביב. ניתן להשתמש בו כדי להגדיר יישומי אביב או לכתוב מנתחים לביצוע משימות כלליות יותר בכל יישום.

דוגמאות הקוד במאמר זה זמינות במאגר GitHub המקושר.