[[414188]] 本文转载自微信公众号「Java大厂面试官」,作者laker。转载本文请联系Java大厂面试官公众号。

成都创新互联是一家集网站建设,新城企业网站建设,新城品牌网站建设,网站定制,新城网站建设报价,网络营销,网络优化,新城网站推广为一体的创新建站企业,帮助传统企业提升企业形象加强企业竞争力。可充分满足这一群体相比中小企业更为丰富、高端、多元的互联网需求。同时我们时刻保持专业、时尚、前沿,时刻以成就客户成长自我,坚持不断学习、思考、沉淀、净化自己,让我们为更多的企业打造出实用型网站。
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 表达式,但表达式可以包含属性引用.
- #{${someProperty} + 2}
 - someProperty 的值为 2,计算结果为 4。
 
支持所有基本算术运算符。
- @Value("#{19 + 1}") // 20
 - private double add;
 - @Value("#{'String1 ' + 'string2'}") // "String1 string2"
 - private String addString;
 - @Value("#{20 - 1}") // 19
 - private double subtract;
 - @Value("#{10 * 2}") // 20
 - private double multiply;
 - @Value("#{36 / 2}") // 19
 - private double divide;
 - @Value("#{36 div 2}") // 18, the same as for / operator
 - private double divideAlphabetic;
 - @Value("#{37 % 10}") // 7
 - private double modulo;
 - @Value("#{37 mod 10}") // 7, the same as for % operator
 - private double moduloAlphabetic;
 - @Value("#{2 ^ 9}") // 512
 - private double powerOf;
 - @Value("#{(2 + 2) * 2 + 9}") // 17
 - private double brackets;
 
- @Value("#{1 == 1}") // true
 - private boolean equal;
 - @Value("#{1 eq 1}") // true
 - private boolean equalAlphabetic;
 - @Value("#{1 != 1}") // false
 - private boolean notEqual;
 - @Value("#{1 ne 1}") // false
 - private boolean notEqualAlphabetic;
 - @Value("#{1 < 1}") // false
 - private boolean lessThan;
 - @Value("#{1 lt 1}") // false
 - private boolean lessThanAlphabetic;
 - @Value("#{1 <= 1}") // true
 - private boolean lessThanOrEqual;
 - @Value("#{1 le 1}") // true
 - private boolean lessThanOrEqualAlphabetic;
 - @Value("#{1 > 1}") // false
 - private boolean greaterThan;
 - @Value("#{1 gt 1}") // false
 - private boolean greaterThanAlphabetic;
 - @Value("#{1 >= 1}") // true
 - private boolean greaterThanOrEqual;
 - @Value("#{1 ge 1}") // true
 - private boolean greaterThanOrEqualAlphabetic;
 
- @Value("#{250 > 200 && 200 < 4000}") // true
 - private boolean and;
 - @Value("#{250 > 200 and 200 < 4000}") // true
 - private boolean andAlphabetic;
 - @Value("#{400 > 300 || 150 < 100}") // true
 - private boolean or;
 - @Value("#{400 > 300 or 150 < 100}") // true
 - private boolean orAlphabetic;
 - @Value("#{!true}") // false
 - private boolean not;
 - @Value("#{not true}") // false
 - private boolean notAlphabetic;
 
- @Value("#{2 > 1 ? 'a' : 'b'}") // "a"
 - private String ternary;
 - @Value("#{someBean.someProperty != null ? someBean.someProperty : 'default'}")
 - private String ternary;
 
- @Value("#{'100' matches '\\d+' }") // true
 - private boolean validNumericStringResult;
 - @Value("#{'100fghdjf' matches '\\d+' }") // false
 - private boolean invalidNumericStringResult;
 - @Value("#{'valid alphabetic string' matches '[a-zA-Z\\s]+' }") // true
 - private boolean validAlphabeticStringResult;
 - @Value("#{'invalid alphabetic string #$1' matches '[a-zA-Z\\s]+' }") // false
 - private boolean invalidAlphabeticStringResult;
 - @Value("#{someBean.someValue matches '\d+'}") // true if someValue contains only digits
 - private boolean validNumericValue;
 
- @Component("workersHolder")
 - public class WorkersHolder {
 - private List
 workers = new LinkedList<>(); - private Map
 salaryByWorkers = new HashMap<>(); - public WorkersHolder() {
 - workers.add("John");
 - workers.add("Susie");
 - workers.add("Alex");
 - workers.add("George");
 - salaryByWorkers.put("John", 35000);
 - salaryByWorkers.put("Susie", 47000);
 - salaryByWorkers.put("Alex", 12000);
 - salaryByWorkers.put("George", 14000);
 - }
 - //Getters and setters
 - }
 - @Value("#{workersHolder.salaryByWorkers['John']}") // 35000
 - private Integer johnSalary;
 - @Value("#{workersHolder.salaryByWorkers['George']}") // 14000
 - private Integer georgeSalary;
 - @Value("#{workersHolder.salaryByWorkers['Susie']}") // 47000
 - private Integer susieSalary;
 - @Value("#{workersHolder.workers[0]}") // John
 - private String firstWorker;
 - @Value("#{workersHolder.workers[3]}") // George
 - private String lastWorker;
 - @Value("#{workersHolder.workers.size()}") // 4
 - private Integer numberOfWorkers;
 
- Expression expression = expressionParser.parseExpression("'Any string'.length()");
 - Integer result = (Integer) expression.getValue();
 - Expression expression = expressionParser.parseExpression("new String('Any string').length()");
 - Expression expression = expressionParser.parseExpression("'Any string'.replace(\" \", \"\").length()");
 - Integer result = expression.getValue(Integer.class);
 - Car car = new Car();
 - car.setMake("Good manufacturer");
 - car.setModel("Model 3");
 - car.setYearOfProduction(2014);
 - ExpressionParser expressionParser = new SpelExpressionParser();
 - Expression expression = expressionParser.parseExpression("model");
 - EvaluationContext context = new StandardEvaluationContext(car);
 - String result = (String) expression.getValue(context);
 - Expression expression = expressionParser.parseExpression("yearOfProduction > 2005");
 - boolean result = expression.getValue(car, Boolean.class);
 - Expression expression = expressionParser.parseExpression("model");
 - String result = (String) expression.getValue(car);
 
- StandardEvaluationContext context = new StandardEvaluationContext(carPark);
 - ExpressionParser expressionParser = new SpelExpressionParser();
 - expressionParser.parseExpression("cars[0].model").setValue(context, "Other model");
 
- SpelParserConfiguration config = new SpelParserConfiguration(true, true);
 - StandardEvaluationContext context = new StandardEvaluationContext(carPark);
 - ExpressionParser expressionParser = new SpelExpressionParser(config);
 - expressionParser.parseExpression("cars[0]").setValue(context, car);
 - Car result = carPark.getCars().get(0);
 
当计算表达式解析properties, methods, fields,并帮助执行类型转换, 使用接口EvaluationContext 这是一个开箱即用的实现, StandardEvaluationContext,使用反射来操纵对象, 缓存java.lang.reflect的Method,Field,和Constructor实例 提高性能。
- class Simple {
 - public List
 booleanList = new ArrayList (); - }
 - Simple simple = new Simple();
 - simple.booleanList.add(true);
 - StandardEvaluationContext simpleContext = new StandardEvaluationContext(simple);
 - // false is passed in here as a string. SpEL and the conversion service will
 - // correctly recognize that it needs to be a Boolean and convert it
 - parser.parseExpression("booleanList[0]").setValue(simpleContext, "false");
 - // b will be false
 - Boolean b = simple.booleanList.get(0);
 
如果解析上下文已经配置,那么bean解析器能够 从表达式使用(@)符号查找bean类。
- ExpressionParser parser = new SpelExpressionParser();
 - StandardEvaluationContext context = new StandardEvaluationContext();
 - context.setBeanResolver(new MyBeanResolver());
 - // This will end up calling resolve(context,"foo") on MyBeanResolver during evaluation
 - Object bean = parser.parseExpression("@foo").getValue(context);
 
如果需要获取Bean工厂本身而不是它构造的Bean,可以使用&Bean名称。
- Object bean = parser.parseExpression("&foo").getValue(context);
 
#this和#root代表了表达式上下文的对象,#root就是当前的表达式上下文对象,#this则根据当前求值环境的不同而变化。下面的例子中,#this即每次循环的值。
- // create an array of integers
 - List
 primes = new ArrayList (); - primes.addAll(Arrays.asList(2,3,5,7,11,13,17));
 - // create parser and set variable 'primes' as the array of integers
 - ExpressionParser parser = new SpelExpressionParser();
 - StandardEvaluationContext context = new StandardEvaluationContext();
 - context.setVariable("primes",primes);
 - // all prime numbers > 10 from the list (using selection ?{...})
 - // evaluates to [11, 13, 17]
 - List
 primesGreaterThanTen = (List ) parser.parseExpression("#primes.?[#this>10]").getValue(context); 
表达式模板使用#{}定义,它允许我们混合多种结果。下面就是一个例子,首先Spring会先对模板中的表达式求值,在这里是返回一个随机值,然后将结果和外部的表达式组合起来。最终的结果就向下面这样了。
- String randomPhrase = parser.parseExpression(
 - "random number is #{T(java.lang.Math).random()}",
 - new TemplateParserContext()).getValue(String.class);
 - // 结果是 "random number is 0.7038186818312008"
 
以上都是官网的理论值,现总结下项目实战中常用的技巧。
注册常用的用户、Request、Response、工具类到上下文,以便于在表达式中引用业务无关的对象。
- ExpressionParser parser = new SpelExpressionParser();// 这个是线程安全的 定义为全局变量。
 - String expression = "#{user.id + request.getQuringString()}";
 - Expression exp = parser.parseExpression(expression);
 - EvaluationContext context = new StandardEvaluationContext();
 - context.setVariable("user", user);
 - context.setVariable("request", request);
 - context.setVariable("dateUtils", dateUtils);
 - String value = (String) exp.getValue(context);
 
要访问 bean 对象,那么EvaluationContext中需要包含 bean 对象才行,可以借助BeanResolver来实现,如context.setBeanResolver(new BeanFactoryResolver(applicationContext)),访问 bean 的前缀修饰为@符号。
我们需要获取ApplicationContext,可以继承ApplicationContextAware,或者使用@Autowired获取。
- StandardEvaluationContext context = new StandardEvaluationContext();
 - context.setBeanResolver(new BeanFactoryResolver(applicationContext));
 - // 获取bean对象
 - LakerService lakerService = parser.parseExpression("@lakerService").getValue(context, LakerService.class);
 - System.out.println("lakerService : " + lakerService);
 - // 访问bean方法
 - String result = parser.parseExpression("@lakerService.print('lakernote')").getValue(context, String.class);
 - System.out.println("return result : " + result);
 
1.定义自定义注解
- @Target(ElementType.METHOD)
 - @Retention(RetentionPolicy.RUNTIME)
 - @Documented
 - public @interface Laker {
 - String value();
 - }
 
2.针对自定义注解定义切面拦截
- @Aspect
 - @Component
 - @Slf4j
 - public class LakerAspect {
 - private SpelExpressionParser parserSpel = new SpelExpressionParser();
 - private DefaultParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
 - @Pointcut("@annotation(com.laker.map.moudle.spel.Laker)")
 - private void elPoint() {
 - }
 - @Around("elPoint()")
 - public void cache(ProceedingJoinPoint pjp) {
 - Method method = ((MethodSignature) pjp.getSignature()).getMethod();
 - Laker laker = method.getAnnotation(Laker.class);
 - String value = getValue(laker.value(), pjp);
 - log.info(value);
 - try {
 - pjp.proceed();
 - } catch (Throwable e) {
 - log.error("", e);
 - }
 - }
 - public String getValue(String key, ProceedingJoinPoint pjp) {
 - Expression expression = parserSpel.parseExpression(key);
 - EvaluationContext context = new StandardEvaluationContext();
 - User user = new User();
 - user.id = 123L;
 - context.setVariable("user", user);// 模拟设置用户信息
 - MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
 - Object[] args = pjp.getArgs();
 - String[] paramNames = parameterNameDiscoverer.getParameterNames(methodSignature.getMethod());
 - for (int i = 0; i < args.length; i++) {
 - context.setVariable(paramNames[i], args[i]);
 - }
 - return expression.getValue(context).toString();
 - }
 - class User {
 - public Long id;
 - }
 - }
 
3.在业务类上使用自定义注解
- @Service
 - public class LakerService {
 - @Laker("#user.id + #msg") //要符合SpEL表达式格式
 - public void print(String msg) {
 - System.out.println(msg);
 - }
 - }
 
参考:
                网页标题:从零搭建开发脚手架 Spring EL表达式的简介和实战应用
                
                网站URL:http://www.csdahua.cn/qtweb/news11/486561.html
            
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网