com.ideaaedi.commonspring.parser.SpelUtil Maven / Gradle / Ivy
The newest version!
package com.ideaaedi.commonspring.parser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.StandardReflectionParameterNameDiscoverer;
import org.springframework.expression.BeanResolver;
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;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Map;
/**
* spel工具类
*
* @author JustryDeng
* @since 2022/5/17 10:11
*/
@Slf4j
public class SpelUtil {
private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
private static final StandardReflectionParameterNameDiscoverer DISCOVERER =
new StandardReflectionParameterNameDiscoverer();
private static final TemplateParserContext TEMPLATE_PARSER_CONTEXT = new TemplateParserContext();
private static BeanResolver beanResolver;
/**
* 初始化bean解析器
*
* 当需要调用spring-bean的方法时,需要先初始化 bean解析器
*/
public static void initBeanResolver(BeanResolver beanResolver) {
if (SpelUtil.beanResolver != null && !SpelUtil.beanResolver.equals(beanResolver)) {
throw new IllegalStateException("beanResolver already been initialized.");
}
synchronized (SpelUtil.class) {
if (SpelUtil.beanResolver != null) {
if (SpelUtil.beanResolver.equals(beanResolver)) {
return;
}
throw new IllegalStateException("beanResolver already been initialized.");
}
SpelUtil.beanResolver = beanResolver;
}
}
/**
* 解析spel
*
* @see SpelUtil#parseSpel(Method, Object[], Class, String)
*/
@Nullable
public static T parseSpel(Method method, Object[] argValues, String spel) {
//noinspection unchecked
return (T) parseSpel(method, argValues, Object.class, spel);
}
/**
* 解析spel
*
* @see SpelUtil#parseSpel(Map, Method, Object[], Class, String)
*/
@Nullable
public static T parseSpel(Method method, Object[] argValues, Class clazz, String spel) {
return parseSpel(Collections.emptyMap(), method, argValues, clazz, spel);
}
/**
* 解析spel
*
* @param appendContext
* 附加的上下文解析参数
* @param method
* 方法
* @param argValues
* 方法的参数值
* @param clazz
* 解析结果的数据类型
* @param spel
* spel表达式(注:因为本方法中用到了{@link TemplateParserContext}, 所以需要使用#{}将原生的spel包起来,形成最终的表达式)
*
* 1、获取属性示例:#{#param1.fieldA}
*
* 2、调用方法示例:#{#param2.methodA()}
*
* 3、调用spring-bean示例:#{@userService.getUsername(#userId)},
*
注:使用之前需要初始化bean解析器{@link SpelUtil#initBeanResolver(BeanResolver)}
*
初始化bean解析器示例:SpelUtil.initBeanResolver(new BeanFactoryResolver(applicationContext));
*
* 4、调用静态字段示例:#{T(org.springframework.core.Ordered).HIGHEST_PRECEDENCE}
*
注:若调用的是java.lang.包下的类,可以不指定包名
*
* 5、调用静态方法示例:#{T(java.util.Objects).nonNull(#returnObj)}
*
注:若调用的是java.lang.包下的类,可以不指定包名
*
* 6、判断示例1:#{#code == 200}
*
* 7、判断示例2:#{#user == null}
*
* 8、......
*
* @return 解析结果
*/
@Nullable
public static T parseSpel(Map appendContext, Method method, Object[] argValues, Class clazz, String spel) {
try {
String[] params = DISCOVERER.getParameterNames(method);
StandardEvaluationContext context = new StandardEvaluationContext();
if (beanResolver != null) {
context.setBeanResolver(beanResolver);
}
if (params != null) {
for (int i = 0; i < params.length; i++) {
context.setVariable(params[i], argValues[i]);
}
}
if (appendContext != null && appendContext.size() > 0) {
appendContext.forEach(context::setVariable);
}
Expression expression = EXPRESSION_PARSER.parseExpression(spel, TEMPLATE_PARSER_CONTEXT);
return expression.getValue(context, clazz);
} catch (Exception e) {
log.warn("method -> {}, argValues -> {}, clazz -> {}, parser -> {}", method, argValues, clazz, spel);
throw e;
}
}
/**
* 解析spel
*
* @see SpelUtil#parseSpel(Map, Class, String)
*/
@Nullable
public static T parseSpel(Map argNameValueMap, String spel) {
//noinspection unchecked
return (T) parseSpel(argNameValueMap, Object.class, spel);
}
/**
* 解析spel
*
* 提示:在获取实例字段时,是通过getter去反向解析字段的。如果获取失败,请确保有对应的getter方法
*
* @param argNameValueMap
* 参数名-参数值 map
* @param clazz
* 解析结果的数据类型
* @param spel
* spel表达式(注:因为本方法中用到了{@link TemplateParserContext}, 所以需要使用#{}将原生的spel包起来,形成最终的表达式)
*
* 1、获取属性示例:#{#param1.fieldA}
*
* 2、调用方法示例:#{#param2.methodA()}
*
* 3、调用spring-bean示例:#{@userService.getUsername(#userId)},
*
注:使用之前需要初始化bean解析器{@link SpelUtil#initBeanResolver(BeanResolver)}
*
初始化bean解析器示例:SpelUtil.initBeanResolver(new BeanFactoryResolver(applicationContext));
*
* 4、调用静态字段示例:#{T(org.springframework.core.Ordered).HIGHEST_PRECEDENCE}
*
注:若调用的是java.lang.包下的类,可以不指定包名
*
* 5、调用静态方法示例:#{T(java.util.Objects).nonNull(#returnObj)}
*
注:若调用的是java.lang.包下的类,可以不指定包名
*
* 6、枚举示例1:{T(com.ideaaedi.demo.enums.CachePrefixEnum).USER_ACCOUNT_PHONE.name()}
*
注:和调用静态方法是一样的
*
* 7、枚举示例2:#{T(com.ideaaedi.demo.enums.CachePrefixEnum).USER_ACCOUNT_PHONE.key(#user.account, #user.phone)}
*
注:和调用静态方法是一样的
*
* 8、判断示例1:#{#code == 200}
*
* 9、判断示例2:#{#user == null}
*
* 10、......
*
* @return 解析结果
*/
@Nullable
public static T parseSpel(Map argNameValueMap, Class clazz, String spel) {
try {
StandardEvaluationContext context = new StandardEvaluationContext();
if (beanResolver != null) {
context.setBeanResolver(beanResolver);
}
if (!CollectionUtils.isEmpty(argNameValueMap)) {
argNameValueMap.forEach(context::setVariable);
}
Expression expression = EXPRESSION_PARSER.parseExpression(spel, TEMPLATE_PARSER_CONTEXT);
return expression.getValue(context, clazz);
} catch (Exception e) {
log.warn("argNameValueMap -> {}, clazz -> {}, parser -> {}", argNameValueMap, clazz, spel);
throw e;
}
}
}