成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

從零搭建開發腳手架 Spring EL表達式的簡介和實戰應用

開發 后端
Sping EL(Spring Expression Language 簡稱 SpEL)是一種強大的表達式語言,支持在運行時查詢和操作對象,它可以與 XML 或基于注解的 Spring 配置一起使用。語言語法類似于統一 EL,但提供了額外的功能,方法調用和字符串模板功能。
本文轉載自微信公眾號「Java大廠面試官」,作者laker。轉載本文請聯系Java大廠面試官公眾號。
  • 簡介
    • 算術運算符
    • 關系運算符
    • 邏輯運算符
    • 三目運算符
    • 正則運算符
    • 訪問List和Map
  • 以編程方式解析表達式
    • ExpressionParser
    • EvaluationContext
  • 高級應用
    • Bean引用
    • #this和#root
    • 表達式模板
  • 實戰
    • 1.注冊常用的用戶、Request、Response、工具類到上下文
    • 2.訪問Spring容器中的任意Bean并調用其方法
    • 3.自定義注解+獲取方法入參

簡介

Sping EL(Spring Expression Language 簡稱 SpEL)是一種強大的表達式語言,支持在運行時查詢和操作對象,它可以與 XML 或基于注解的 Spring 配置一起使用。語言語法類似于統一 EL,但提供了額外的功能,方法調用和字符串模板功能。

雖然還有其他幾種可用的 Java 表達式語言,OGNL、MVEL 和 JBoss EL等,但創建 Spring 表達式語言是為了向 Spring 社區提供一種受良好支持的表達式語言,SpEL基于與技術無關的 API,允許在需要時集成其他表達式語言實現。

SpEL支持以下運算符

類型 操作符
算術運算符 +, -, *, /, %, ^, div, mod
關系運算符 <, >, ==, !=, <=, >=, lt, gt, eq, ne, le, ge
邏輯運算符 and, or, not, &&, ||, !
三目運算符 ?:
正則運算符 matches

以注解的方式舉例如下:

SpEL表達式以#符號開頭,并用大括號括起來:#{expression}。可以以類似的方式引用屬性,以$符號開頭,并用大括號括起來:${property.name}。屬性占位符不能包含 SpEL 表達式,但表達式可以包含屬性引用.

  1. #{${someProperty} + 2} 
  2. someProperty 的值為 2,計算結果為 4。 

算術運算符

支持所有基本算術運算符。

  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; 

關系運算符

  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; 

邏輯運算符

  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; 

三目運算符

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

正則運算符

  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; 

訪問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; 

以編程方式解析表達式

ExpressionParser

  • ExpressionParser負責解析表達式字符串,可以使用它來調用方法、訪問屬性或調用構造函數。
  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設置值
  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); 
  • 允許它在指定索引為空時自動創建元素(*autoGrowNullReferences,*構造函數的第一個參數)
  • 自動增長數組或列表以容納超出其初始大小的元素(autoGrowCollections,第二個參數)

EvaluationContext

當計算表達式解析properties, methods, fields,并幫助執行類型轉換, 使用接口EvaluationContext 這是一個開箱即用的實現, StandardEvaluationContext,使用反射來操縱對象, 緩存java.lang.reflect的Method,Field,和Constructor實例 提高性能。

  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); 

高級應用

Bean引用

如果解析上下文已經配置,那么bean解析器能夠 從表達式使用(@)符號查找bean類。

  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工廠本身而不是它構造的Bean,可以使用&Bean名稱。

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

#this和#root

#this和#root代表了表達式上下文的對象,#root就是當前的表達式上下文對象,#this則根據當前求值環境的不同而變化。下面的例子中,#this即每次循環的值。

  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); 

表達式模板

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

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

實戰

以上都是官網的理論值,現總結下項目實戰中常用的技巧。

1.注冊常用的用戶、Request、Response、工具類到上下文

注冊常用的用戶、Request、Response、工具類到上下文,以便于在表達式中引用業務無關的對象。

  1. ExpressionParser parser = new SpelExpressionParser();// 這個是線程安全的 定義為全局變量。   
  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.訪問Spring容器中的任意Bean并調用其方法

要訪問 bean 對象,那么EvaluationContext中需要包含 bean 對象才行,可以借助BeanResolver來實現,如context.setBeanResolver(new BeanFactoryResolver(applicationContext)),訪問 bean 的前綴修飾為@符號。

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

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

3.自定義注解+獲取方法入參

1.定義自定義注解

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

2.針對自定義注解定義切面攔截

  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);// 模擬設置用戶信息 
  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.在業務類上使用自定義注解

  1. @Service 
  2. public class LakerService { 
  3.  
  4.     @Laker("#user.id + #msg") //要符合SpEL表達式格式 
  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

 

責任編輯:武曉燕 來源: Java大廠面試官
相關推薦

2021-07-13 18:42:38

Spring Boot腳手架開發

2021-04-28 16:10:48

開發腳手架 Spring

2020-08-19 08:55:47

Redis緩存數據庫

2021-09-01 10:07:43

開發零搭建Groovy

2021-05-13 17:02:38

MDC腳手架日志

2021-04-13 14:47:53

認證授權Java

2021-06-02 17:58:49

腳手架 冪等性前端

2021-02-19 22:43:50

開發腳手架Controller

2021-03-09 17:11:09

數據庫腳手架開發

2021-03-11 14:16:47

Spring Boo開發腳手架

2021-04-20 19:24:16

腳手架 Java微信

2016-08-10 14:59:41

前端Javascript工具

2025-05-16 07:24:41

Springkafka腳手架

2016-09-07 15:35:06

VueReact腳手架

2021-01-07 05:34:07

腳手架JDK緩存

2023-11-21 17:36:04

OpenFeignSentinel

2018-06-11 14:39:57

前端腳手架工具node.js

2018-08-30 16:08:37

Node.js腳手架工具

2014-08-15 09:36:06

2020-06-29 11:35:02

Spring BootJava腳手架
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品国产乱码久久久久久闺蜜 | 久优草| 国产精品日韩在线观看一区二区 | 一二三区av| 天堂综合网久久 | 国产精品 欧美精品 | 色综合区 | 精品视频久久久久久 | 欧美久久久 | 亚洲精品视频观看 | 日本综合在线观看 | 一a级片| 色综合久 | 高清国产一区二区 | 国产精品a免费一区久久电影 | 小川阿佐美pgd-606在线 | 欧美一区二区三区 | 三级在线视频 | 欧美一级小视频 | 欧美中文字幕一区二区 | 四虎在线观看 | 国产精品免费一区二区三区四区 | 四虎最新 | 国产在线高清 | 亚洲精品成人在线 | 四虎永久免费地址 | 亚洲第一免费播放区 | 精品视频一区二区三区在线观看 | 国产精品久久久久久久久久久新郎 | 天天天操 | 亚欧精品一区 | 一区二区三区福利视频 | 亚洲草草视频 | 三级av在线 | 一级视频黄色 | 国产精品视频导航 | 久久午夜视频 | 性一交一乱一透一a级 | 亚洲高清在线观看 | av大片在线观看 | 午夜影视大全 |