自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

從零搭建開(kāi)發(fā)腳手架 Spring EL表達(dá)式的簡(jiǎn)介和實(shí)戰(zhàn)應(yīng)用

開(kāi)發(fā) 后端
Sping EL(Spring Expression Language 簡(jiǎn)稱(chēng) SpEL)是一種強(qiáng)大的表達(dá)式語(yǔ)言,支持在運(yùn)行時(shí)查詢(xún)和操作對(duì)象,它可以與 XML 或基于注解的 Spring 配置一起使用。語(yǔ)言語(yǔ)法類(lèi)似于統(tǒng)一 EL,但提供了額外的功能,方法調(diào)用和字符串模板功能。
本文轉(zhuǎn)載自微信公眾號(hào)「Java大廠(chǎng)面試官」,作者laker。轉(zhuǎn)載本文請(qǐng)聯(lián)系Java大廠(chǎng)面試官公眾號(hào)。
  • 簡(jiǎn)介
    • 算術(shù)運(yùn)算符
    • 關(guān)系運(yùn)算符
    • 邏輯運(yùn)算符
    • 三目運(yùn)算符
    • 正則運(yùn)算符
    • 訪(fǎng)問(wèn)List和Map
  • 以編程方式解析表達(dá)式
    • ExpressionParser
    • EvaluationContext
  • 高級(jí)應(yīng)用
    • Bean引用
    • #this和#root
    • 表達(dá)式模板
  • 實(shí)戰(zhàn)
    • 1.注冊(cè)常用的用戶(hù)、Request、Response、工具類(lèi)到上下文
    • 2.訪(fǎng)問(wèn)Spring容器中的任意Bean并調(diào)用其方法
    • 3.自定義注解+獲取方法入?yún)?/li>

簡(jiǎn)介

Sping EL(Spring Expression Language 簡(jiǎn)稱(chēng) SpEL)是一種強(qiáng)大的表達(dá)式語(yǔ)言,支持在運(yùn)行時(shí)查詢(xún)和操作對(duì)象,它可以與 XML 或基于注解的 Spring 配置一起使用。語(yǔ)言語(yǔ)法類(lèi)似于統(tǒng)一 EL,但提供了額外的功能,方法調(diào)用和字符串模板功能。

雖然還有其他幾種可用的 Java 表達(dá)式語(yǔ)言,OGNL、MVEL 和 JBoss EL等,但創(chuàng)建 Spring 表達(dá)式語(yǔ)言是為了向 Spring 社區(qū)提供一種受良好支持的表達(dá)式語(yǔ)言,SpEL基于與技術(shù)無(wú)關(guān)的 API,允許在需要時(shí)集成其他表達(dá)式語(yǔ)言實(shí)現(xiàn)。

SpEL支持以下運(yùn)算符

類(lèi)型 操作符
算術(shù)運(yùn)算符 +, -, *, /, %, ^, div, mod
關(guān)系運(yùn)算符 <, >, ==, !=, <=, >=, lt, gt, eq, ne, le, ge
邏輯運(yùn)算符 and, or, not, &&, ||, !
三目運(yùn)算符 ?:
正則運(yùn)算符 matches

以注解的方式舉例如下:

SpEL表達(dá)式以#符號(hào)開(kāi)頭,并用大括號(hào)括起來(lái):#{expression}??梢砸灶?lèi)似的方式引用屬性,以$符號(hào)開(kāi)頭,并用大括號(hào)括起來(lái):${property.name}。屬性占位符不能包含 SpEL 表達(dá)式,但表達(dá)式可以包含屬性引用.

  1. #{${someProperty} + 2} 
  2. someProperty 的值為 2,計(jì)算結(jié)果為 4。 

算術(shù)運(yùn)算符

支持所有基本算術(shù)運(yùn)算符。

  1. @Value("#{19 + 1}") // 20 
  2. private double add;  
  3.  
  4. @Value("#{'String1 ' + 'string2'}") // "String1 string2" 
  5. private String addString;  
  6.  
  7. @Value("#{20 - 1}") // 19 
  8. private double subtract; 
  9.  
  10. @Value("#{10 * 2}") // 20 
  11. private double multiply; 
  12.  
  13. @Value("#{36 / 2}") // 19 
  14. private double divide; 
  15.  
  16. @Value("#{36 div 2}") // 18, the same as for / operator 
  17. private double divideAlphabetic;  
  18.  
  19. @Value("#{37 % 10}") // 7 
  20. private double modulo; 
  21.  
  22. @Value("#{37 mod 10}") // 7, the same as for % operator 
  23. private double moduloAlphabetic;  
  24.  
  25. @Value("#{2 ^ 9}") // 512 
  26. private double powerOf; 
  27.  
  28. @Value("#{(2 + 2) * 2 + 9}") // 17 
  29. private double brackets; 

關(guān)系運(yùn)算符

  1. @Value("#{1 == 1}") // true 
  2. private boolean equal; 
  3.  
  4. @Value("#{1 eq 1}") // true 
  5. private boolean equalAlphabetic; 
  6.  
  7. @Value("#{1 != 1}") // false 
  8. private boolean notEqual; 
  9.  
  10. @Value("#{1 ne 1}") // false 
  11. private boolean notEqualAlphabetic; 
  12.  
  13. @Value("#{1 < 1}") // false 
  14. private boolean lessThan; 
  15.  
  16. @Value("#{1 lt 1}") // false 
  17. private boolean lessThanAlphabetic; 
  18.  
  19. @Value("#{1 <= 1}") // true 
  20. private boolean lessThanOrEqual; 
  21.  
  22. @Value("#{1 le 1}") // true 
  23. private boolean lessThanOrEqualAlphabetic; 
  24.  
  25. @Value("#{1 > 1}") // false 
  26. private boolean greaterThan; 
  27.  
  28. @Value("#{1 gt 1}") // false 
  29. private boolean greaterThanAlphabetic; 
  30.  
  31. @Value("#{1 >= 1}") // true 
  32. private boolean greaterThanOrEqual; 
  33.  
  34. @Value("#{1 ge 1}") // true 
  35. private boolean greaterThanOrEqualAlphabetic; 

邏輯運(yùn)算符

  1. @Value("#{250 > 200 && 200 < 4000}") // true 
  2. private boolean and;  
  3.  
  4. @Value("#{250 > 200 and 200 < 4000}") // true 
  5. private boolean andAlphabetic; 
  6.  
  7. @Value("#{400 > 300 || 150 < 100}") // true 
  8. private boolean or
  9.  
  10. @Value("#{400 > 300 or 150 < 100}") // true 
  11. private boolean orAlphabetic; 
  12.  
  13. @Value("#{!true}") // false 
  14. private boolean not
  15.  
  16. @Value("#{not true}") // false 
  17. private boolean notAlphabetic; 

三目運(yùn)算符

  1. @Value("#{2 > 1 ? 'a' : 'b'}") // "a" 
  2. private String ternary; 
  3. @Value("#{someBean.someProperty != null ? someBean.someProperty : 'default'}"
  4. private String ternary; 

正則運(yùn)算符

  1. @Value("#{'100' matches '\\d+' }") // true 
  2. private boolean validNumericStringResult; 
  3.  
  4. @Value("#{'100fghdjf' matches '\\d+' }") // false 
  5. private boolean invalidNumericStringResult; 
  6.  
  7. @Value("#{'valid alphabetic string' matches '[a-zA-Z\\s]+' }") // true 
  8. private boolean validAlphabeticStringResult; 
  9.  
  10. @Value("#{'invalid alphabetic string #$1' matches '[a-zA-Z\\s]+' }") // false 
  11. private boolean invalidAlphabeticStringResult; 
  12.  
  13. @Value("#{someBean.someValue matches '\d+'}") // true if someValue contains only digits 
  14. private boolean validNumericValue; 

訪(fǎng)問(wèn)List和Map

  1. @Component("workersHolder"
  2. public class WorkersHolder { 
  3.     private List<String> workers = new LinkedList<>(); 
  4.     private Map<String, Integer> salaryByWorkers = new HashMap<>(); 
  5.  
  6.     public WorkersHolder() { 
  7.         workers.add("John"); 
  8.         workers.add("Susie"); 
  9.         workers.add("Alex"); 
  10.         workers.add("George"); 
  11.  
  12.         salaryByWorkers.put("John", 35000); 
  13.         salaryByWorkers.put("Susie", 47000); 
  14.         salaryByWorkers.put("Alex", 12000); 
  15.         salaryByWorkers.put("George", 14000); 
  16.     } 
  17.  
  18.     //Getters and setters 
  19.  
  20.  
  21. @Value("#{workersHolder.salaryByWorkers['John']}") // 35000 
  22. private Integer johnSalary; 
  23.  
  24. @Value("#{workersHolder.salaryByWorkers['George']}") // 14000 
  25. private Integer georgeSalary; 
  26.  
  27. @Value("#{workersHolder.salaryByWorkers['Susie']}") // 47000 
  28. private Integer susieSalary; 
  29.  
  30. @Value("#{workersHolder.workers[0]}") // John 
  31. private String firstWorker; 
  32.  
  33. @Value("#{workersHolder.workers[3]}") // George 
  34. private String lastWorker; 
  35.  
  36. @Value("#{workersHolder.workers.size()}") // 4 
  37. private Integer numberOfWorkers; 

以編程方式解析表達(dá)式

ExpressionParser

  • ExpressionParser負(fù)責(zé)解析表達(dá)式字符串,可以使用它來(lái)調(diào)用方法、訪(fǎng)問(wèn)屬性或調(diào)用構(gòu)造函數(shù)。
  1. Expression expression = expressionParser.parseExpression("'Any string'.length()"); 
  2. Integer result = (Integer) expression.getValue(); 
  3.  
  4. Expression expression = expressionParser.parseExpression("new String('Any string').length()"); 
  5.  
  6. Expression expression = expressionParser.parseExpression("'Any string'.replace(\" \", \"\").length()"); 
  7. Integer result = expression.getValue(Integer.class); 
  8.  
  9. Car car = new Car(); 
  10. car.setMake("Good manufacturer"); 
  11. car.setModel("Model 3"); 
  12. car.setYearOfProduction(2014); 
  13. ExpressionParser expressionParser = new SpelExpressionParser(); 
  14. Expression expression = expressionParser.parseExpression("model"); 
  15.  
  16. EvaluationContext context = new StandardEvaluationContext(car); 
  17. String result = (String) expression.getValue(context); 
  18.  
  19. Expression expression = expressionParser.parseExpression("yearOfProduction > 2005"); 
  20. boolean result = expression.getValue(car, Boolean.class); 
  21.  
  22. Expression expression = expressionParser.parseExpression("model"); 
  23. String result = (String) expression.getValue(car); 
  • 使用ExpressionParser設(shè)置值
  1. StandardEvaluationContext context = new StandardEvaluationContext(carPark); 
  2.  
  3. ExpressionParser expressionParser = new SpelExpressionParser(); 
  4. expressionParser.parseExpression("cars[0].model").setValue(context, "Other model"); 
  • ExpressionParser解析器配置
  1. SpelParserConfiguration config = new SpelParserConfiguration(truetrue); 
  2. StandardEvaluationContext context = new StandardEvaluationContext(carPark); 
  3.  
  4. ExpressionParser expressionParser = new SpelExpressionParser(config); 
  5. expressionParser.parseExpression("cars[0]").setValue(context, car); 
  6.  
  7. Car result = carPark.getCars().get(0); 
  • 允許它在指定索引為空時(shí)自動(dòng)創(chuàng)建元素(*autoGrowNullReferences,*構(gòu)造函數(shù)的第一個(gè)參數(shù))
  • 自動(dòng)增長(zhǎng)數(shù)組或列表以容納超出其初始大小的元素(autoGrowCollections,第二個(gè)參數(shù))

EvaluationContext

當(dāng)計(jì)算表達(dá)式解析properties, methods, fields,并幫助執(zhí)行類(lèi)型轉(zhuǎn)換, 使用接口EvaluationContext 這是一個(gè)開(kāi)箱即用的實(shí)現(xiàn), StandardEvaluationContext,使用反射來(lái)操縱對(duì)象, 緩存java.lang.reflect的Method,F(xiàn)ield,和Constructor實(shí)例 提高性能。

  1. class Simple { 
  2.     public List<Boolean> booleanList = new ArrayList<Boolean>(); 
  3.  
  4. Simple simple = new Simple(); 
  5.  
  6. simple.booleanList.add(true); 
  7.  
  8. StandardEvaluationContext simpleContext = new StandardEvaluationContext(simple); 
  9.  
  10. // false is passed in here as a string. SpEL and the conversion service will 
  11. // correctly recognize that it needs to be a Boolean and convert it 
  12. parser.parseExpression("booleanList[0]").setValue(simpleContext, "false"); 
  13.  
  14. // b will be false 
  15. Boolean b = simple.booleanList.get(0); 

高級(jí)應(yīng)用

Bean引用

如果解析上下文已經(jīng)配置,那么bean解析器能夠 從表達(dá)式使用(@)符號(hào)查找bean類(lèi)。

  1. ExpressionParser parser = new SpelExpressionParser(); 
  2. StandardEvaluationContext context = new StandardEvaluationContext(); 
  3. context.setBeanResolver(new MyBeanResolver()); 
  4.  
  5. // This will end up calling resolve(context,"foo"on MyBeanResolver during evaluation 
  6. Object bean = parser.parseExpression("@foo").getValue(context); 

如果需要獲取Bean工廠(chǎng)本身而不是它構(gòu)造的Bean,可以使用&Bean名稱(chēng)。

  1. Object bean = parser.parseExpression("&foo").getValue(context); 

#this和#root

#this和#root代表了表達(dá)式上下文的對(duì)象,#root就是當(dāng)前的表達(dá)式上下文對(duì)象,#this則根據(jù)當(dāng)前求值環(huán)境的不同而變化。下面的例子中,#this即每次循環(huán)的值。

  1. // create an array of integers 
  2. List<Integer> primes = new ArrayList<Integer>(); 
  3. primes.addAll(Arrays.asList(2,3,5,7,11,13,17)); 
  4.  
  5. // create parser and set variable 'primes' as the array of integers 
  6. ExpressionParser parser = new SpelExpressionParser(); 
  7. StandardEvaluationContext context = new StandardEvaluationContext(); 
  8. context.setVariable("primes",primes); 
  9.  
  10. // all prime numbers > 10 from the list (using selection ?{...}) 
  11. // evaluates to [11, 13, 17] 
  12. List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExpression("#primes.?[#this>10]").getValue(context); 

表達(dá)式模板

表達(dá)式模板使用#{}定義,它允許我們混合多種結(jié)果。下面就是一個(gè)例子,首先Spring會(huì)先對(duì)模板中的表達(dá)式求值,在這里是返回一個(gè)隨機(jī)值,然后將結(jié)果和外部的表達(dá)式組合起來(lái)。最終的結(jié)果就向下面這樣了。

  1. String randomPhrase = parser.parseExpression( 
  2.         "random number is #{T(java.lang.Math).random()}"
  3.         new TemplateParserContext()).getValue(String.class); 
  4. // 結(jié)果是 "random number is 0.7038186818312008" 

實(shí)戰(zhàn)

以上都是官網(wǎng)的理論值,現(xiàn)總結(jié)下項(xiàng)目實(shí)戰(zhàn)中常用的技巧。

1.注冊(cè)常用的用戶(hù)、Request、Response、工具類(lèi)到上下文

注冊(cè)常用的用戶(hù)、Request、Response、工具類(lèi)到上下文,以便于在表達(dá)式中引用業(yè)務(wù)無(wú)關(guān)的對(duì)象。

  1. ExpressionParser parser = new SpelExpressionParser();// 這個(gè)是線(xiàn)程安全的 定義為全局變量。   
  2. String expression = "#{user.id + request.getQuringString()}"
  3. Expression exp = parser.parseExpression(expression); 
  4.  
  5. EvaluationContext context = new StandardEvaluationContext(); 
  6. context.setVariable("user"user); 
  7. context.setVariable("request", request); 
  8. context.setVariable("dateUtils", dateUtils); 
  9.          
  10. String value = (String) exp.getValue(context); 

2.訪(fǎng)問(wèn)Spring容器中的任意Bean并調(diào)用其方法

要訪(fǎng)問(wèn) bean 對(duì)象,那么EvaluationContext中需要包含 bean 對(duì)象才行,可以借助BeanResolver來(lái)實(shí)現(xiàn),如context.setBeanResolver(new BeanFactoryResolver(applicationContext)),訪(fǎng)問(wèn) bean 的前綴修飾為@符號(hào)。

我們需要獲取ApplicationContext,可以繼承ApplicationContextAware,或者使用@Autowired獲取。

  1. StandardEvaluationContext context = new StandardEvaluationContext(); 
  2. context.setBeanResolver(new BeanFactoryResolver(applicationContext));  
  3.  
  4. // 獲取bean對(duì)象 
  5. LakerService lakerService = parser.parseExpression("@lakerService").getValue(context, LakerService.class); 
  6. System.out.println("lakerService : " + lakerService); 
  7.  
  8. // 訪(fǎng)問(wèn)bean方法 
  9. String result = parser.parseExpression("@lakerService.print('lakernote')").getValue(context, String.class); 
  10. System.out.println("return result : " + result); 

3.自定義注解+獲取方法入?yún)?/h3>

1.定義自定義注解

  1. @Target(ElementType.METHOD) 
  2. @Retention(RetentionPolicy.RUNTIME) 
  3. @Documented 
  4. public @interface Laker { 
  5.     String value(); 

2.針對(duì)自定義注解定義切面攔截

  1. @Aspect 
  2. @Component 
  3. @Slf4j 
  4. public class LakerAspect { 
  5.     private SpelExpressionParser parserSpel = new SpelExpressionParser(); 
  6.     private DefaultParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); 
  7.  
  8.     @Pointcut("@annotation(com.laker.map.moudle.spel.Laker)"
  9.     private void elPoint() { 
  10.  
  11.     } 
  12.  
  13.     @Around("elPoint()"
  14.     public void cache(ProceedingJoinPoint pjp) { 
  15.         Method method = ((MethodSignature) pjp.getSignature()).getMethod(); 
  16.         Laker laker = method.getAnnotation(Laker.class); 
  17.         String value = getValue(laker.value(), pjp); 
  18.         log.info(value); 
  19.         try { 
  20.             pjp.proceed(); 
  21.         } catch (Throwable e) { 
  22.             log.error("", e); 
  23.         } 
  24.     } 
  25.  
  26.     public String getValue(String key, ProceedingJoinPoint pjp) { 
  27.         Expression expression = parserSpel.parseExpression(key); 
  28.         EvaluationContext context = new StandardEvaluationContext(); 
  29.          
  30.         User user = new User(); 
  31.         user.id = 123L; 
  32.         context.setVariable("user"user);// 模擬設(shè)置用戶(hù)信息 
  33.          
  34.         MethodSignature methodSignature = (MethodSignature) pjp.getSignature(); 
  35.         Object[] args = pjp.getArgs(); 
  36.         String[] paramNames = parameterNameDiscoverer.getParameterNames(methodSignature.getMethod()); 
  37.         for (int i = 0; i < args.length; i++) { 
  38.             context.setVariable(paramNames[i], args[i]); 
  39.         } 
  40.         return expression.getValue(context).toString(); 
  41.     } 
  42.  
  43.     class User { 
  44.         public Long id; 
  45.     } 

3.在業(yè)務(wù)類(lèi)上使用自定義注解

  1. @Service 
  2. public class LakerService { 
  3.  
  4.     @Laker("#user.id + #msg") //要符合SpEL表達(dá)式格式 
  5.     public void print(String msg) { 
  6.         System.out.println(msg); 
  7.     } 

參考:

 

  • https://docs.spring.io/spring-framework/docs/current/reference/html/
  • https://www.baeldung.com/spring-expression-language

 

責(zé)任編輯:武曉燕 來(lái)源: Java大廠(chǎng)面試官
相關(guān)推薦

2021-07-13 18:42:38

Spring Boot腳手架開(kāi)發(fā)

2021-04-28 16:10:48

開(kāi)發(fā)腳手架 Spring

2020-08-19 08:55:47

Redis緩存數(shù)據(jù)庫(kù)

2021-09-01 10:07:43

開(kāi)發(fā)零搭建Groovy

2021-05-13 17:02:38

MDC腳手架日志

2021-04-13 14:47:53

認(rèn)證授權(quán)Java

2021-06-02 17:58:49

腳手架 冪等性前端

2021-02-19 22:43:50

開(kāi)發(fā)腳手架Controller

2021-03-09 17:11:09

數(shù)據(jù)庫(kù)腳手架開(kāi)發(fā)

2021-03-11 14:16:47

Spring Boo開(kāi)發(fā)腳手架

2021-04-20 19:24:16

腳手架 Java微信

2016-08-10 14:59:41

前端Javascript工具

2016-09-07 15:35:06

VueReact腳手架

2023-11-21 17:36:04

OpenFeignSentinel

2021-01-07 05:34:07

腳手架JDK緩存

2018-08-30 16:08:37

Node.js腳手架工具

2018-06-11 14:39:57

前端腳手架工具node.js

2014-08-15 09:36:06

2020-06-29 11:35:02

Spring BootJava腳手架

2022-07-18 07:58:46

Spring工具工具類(lèi)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)