关于spel表达式参照我另一篇文章:SPEL 表达式在自定义注解中的应用
package com.haoyu.sip.utils.spring;
import com.haoyu.sip.utils.StringUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.expression.*;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Pattern;
/**
* SPEL表达式解析工具类
*
* @author trumans
*/
@Component
public class SpelPaserUtil {
private static Logger logger = LoggerFactory.getLogger(SpelPaserUtil.class);
/**
* 确保#{}整个捕获
*/
private static final Pattern ELVIS_PATTERN = Pattern.compile("(#\\{(.*?)\\?(.*?):(.*?[\\u4e00-\\u9fa5>\\w!@#$%^&*_+=])})");
private static final Pattern IS_ELVIS_PATTERN = Pattern.compile(".*?\\?.*?:.*");
private static final String PREFIX = "#{";
private static final String SUFFIX = "}";
private static ExpressionParser parser = new SpelExpressionParser();
/**
* 标准表达式环境上下文,字符串只能是纯spel表达式,不能是夹杂spel表达式的字符串
*/
private static StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
/**
* 字符串模板的解析器上下文
*/
private static TemplateParserContext templateParserContext = new TemplateParserContext();
private static ApplicationContext applicationContext;
/**
* spel表达式获取spring容器中的bean的关键
*/
private static BeanFactoryResolver beanFactoryResolver;
@Autowired(required = false)
public void setApplicationContext(ApplicationContext applicationContext) {
if (SpelPaserUtil.applicationContext == null && null != applicationContext) {
SpelPaserUtil.applicationContext = applicationContext;
}
if (null == SpelPaserUtil.beanFactoryResolver && SpelPaserUtil.applicationContext != null) {
/*如果执行了,就可以使用@beanName方式获取容器中的bean。详见spel语法*/
SpelPaserUtil.beanFactoryResolver = new BeanFactoryResolver(SpelPaserUtil.applicationContext);
SpelPaserUtil.evaluationContext.setBeanResolver(SpelPaserUtil.beanFactoryResolver);
}
}
/**
* 基本方法
*
* @param expressionStr
* @param root
* @param desiredResultType
* @param parserContext
* @param
* @return
*/
public static T parseExpression(String expressionStr, Object root, Class desiredResultType, EvaluationContext evaluationContext, ParserContext parserContext) {
T value = null;
try {
Expression expression = SpelPaserUtil.parser.parseExpression(expressionStr, parserContext);
if (evaluationContext instanceof StandardEvaluationContext && null == evaluationContext.getBeanResolver()) {
// 保证非内置StandardEvaluationContext的evaluationContext可以使用spring容器中的bean
((StandardEvaluationContext) evaluationContext).setBeanResolver(SpelPaserUtil.beanFactoryResolver);
}
value = expression.getValue(evaluationContext, root, desiredResultType);
}catch (Exception e){
// logger.error("{} {} {}",e.getClass().getSimpleName(),e.getMessage(),e.getStackTrace());
}
return value;
}
public static T parseExpression(String expressionStr, Map rootMap, Class valueType) {
T parserResult = null;
if (MapUtils.isNotEmpty(rootMap)) {
StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
evaluationContext.setVariables(rootMap);
parserResult = parseExpression(expressionStr, rootMap, valueType, evaluationContext, null);
} else {
parserResult = parseExpression(expressionStr, valueType);
}
return parserResult;
}
public static String parseExpression(String expressionStr, Map rootMap) {
return parseExpression(expressionStr, rootMap, String.class);
}
public static T parseExpression(String expressionStr, Object root, Class desiredResultType) {
return parseExpression(expressionStr, root, desiredResultType, SpelPaserUtil.evaluationContext, null);
}
public static T parseExpression(String expressionStr, Class desiredResultType) {
return parseExpression(expressionStr, TypedValue.NULL.getValue(), desiredResultType);
}
public static String parseExpression(String expressionStr, Object root) {
return parseExpression(expressionStr, root, String.class);
}
public static String parseExpression(String expressionStr) {
return parseExpression(expressionStr, TypedValue.NULL.getValue());
}
//-------------------template parser context method--------------------
public static String parseTemplateExpression(String expressionStr, Object root, EvaluationContext evaluationContext) {
return parseExpression(expressionStr, root, String.class, evaluationContext, SpelPaserUtil.templateParserContext);
}
public static String parseTemplateExpression(String expressionStr, Object root) {
return parseTemplateExpression(expressionStr, root, SpelPaserUtil.evaluationContext);
}
public static String parseTemplateExpression(String expressionStr) {
return parseTemplateExpression(expressionStr, TypedValue.NULL.getValue());
}
/**
* 处理spel模板字符串。例如: this is #{#name} 。#{和}定界符将spel表达式嵌套在了字符串中
*
* @param expressionStr
* @param rootMap
* @return
* @throws Exception
*/
public static String parseTemplateExpression(String expressionStr, Map rootMap) {
String parserResult = expressionStr;
if (MapUtils.isNotEmpty(rootMap)) {
StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
evaluationContext.setVariables(rootMap);
parserResult = parseTemplateExpression(expressionStr, rootMap, evaluationContext);
} else {
parserResult = parseTemplateExpression(expressionStr);
}
return parserResult;
}
/**
* 用来解决spel表达式在三元操作符的局限性(即无法在三元操作符中的true or false 部分继续书写spel template模板表达式)
* 三元操作的logic expression部分,使用非TemplateExpression,true or false 部分可以继续使用TemplateExpression一直递归。但必须保证,整个三元操作符是TemplateExpression。
* 已无效:注意:#{ 与 } 前后千万别有空格 因为正则表达式没有进行配对匹配。后期可能修正,未知;
* 可供参考,加以修改
* @param expressionStr
* @param rootMap
* @return
* @throws Exception
*/
public static String elvisRecursive(String expressionStr, Map rootMap) {
try {
Stack logicSymbol = new Stack();
List coordinate = new ArrayList<>();
int ti = expressionStr.indexOf("?", 0);
if (ti != -1) {
logicSymbol.push(ti);
coordinate.add(ti);
}
for (int i = ti + 1; i < expressionStr.length(); i++) {
/*确定正确的?:位置*/
if (!logicSymbol.empty()) {
if (StringUtils.equals("?", String.valueOf(expressionStr.charAt(i)))) {
/*如果logicSymbol栈中没有了元素,就表明当前coordinate栈中存放的就是?和:的位置*/
logicSymbol.push(i);
coordinate.add(i);
} else if (StringUtils.equals(":", String.valueOf(expressionStr.charAt(i)))) {
coordinate.add(i);
logicSymbol.pop();
}
} else {
break;
}
}
if (CollectionUtils.isNotEmpty(coordinate) && coordinate.size() > 1) {
coordinate.set(1, coordinate.get(coordinate.size() - 1));
/*保证表达式有递归Elvis表达式,因为从?号之前的字符串中最末尾的 #{ 标志就是整个模板开始*/
int prefixIndex = expressionStr.lastIndexOf(PREFIX, coordinate.get(0));
/*prefixStack 保存 #{ 或者 { 的位置 */
Stack prefixStack = new Stack();
/*suffixStack保存 } 的位置*/
Stack suffixStack = new Stack();
for (int j = coordinate.get(1); j < expressionStr.length(); ) {
/*整体算法是,每找到一个#{ 或者 { ,向prefixStack其中加入一个值;每找到一个suffixStack,则向suffixStack加入,同时将prefixStack弹出一个;如果prefixStack为空时,就是匹配的 } 位置*/
if (StringUtils.equals(String.valueOf(expressionStr.charAt(j)), SUFFIX)) {
if (prefixStack.empty()) {
suffixStack.push(j);
break;
} else {
prefixStack.pop();
}
j = j + SUFFIX.length();
} else if (j < expressionStr.length() - 1 && StringUtils.equals(String.valueOf(new char[]{expressionStr.charAt(j), expressionStr.charAt(j + 1)}), PREFIX)) {
/*确保可以在表达式中使用内建map表达式*/
prefixStack.push(j);
j = j + PREFIX.length();
} else if (StringUtils.equals(String.valueOf(expressionStr.charAt(j)), "{")) {
/*确保可以在表达式中使用内建map表达式*/
prefixStack.push(j);
j += 1;
} else {
j += 1;
}
}
int suffixIndex = suffixStack.pop();
/*分离出 logic ? true : false 三元表达式中 logic,true,false 三部分*/
String elvisExp = StringUtils.subNoException(expressionStr, prefixIndex, suffixIndex + 1);
String logicExp = StringUtils.subNoException(expressionStr, prefixIndex + PREFIX.length(), coordinate.get(0));
String trueExp = StringUtils.subNoException(expressionStr, coordinate.get(0) + 1, coordinate.get(1));
String falseExp = StringUtils.subNoException(expressionStr, coordinate.get(1) + 1, suffixIndex);
String subElvisResult = "";
String logicRs = SpelPaserUtil.parseExpression(logicExp, rootMap);
logicRs = logicRs == null ? "true" : logicRs;
if (Boolean.valueOf(logicRs)) {
subElvisResult = elvisRecursive(trueExp, rootMap);
} else {
subElvisResult = elvisRecursive(falseExp, rootMap);
}
int elvisIndex = expressionStr.indexOf(elvisExp, 0);
expressionStr = expressionStr.replace(elvisExp, subElvisResult);
if (IS_ELVIS_PATTERN.matcher(expressionStr).find(elvisIndex)) {
/*如果还有三元表达式,继续解析*/
subElvisResult = elvisRecursive(expressionStr, rootMap);
expressionStr = subElvisResult;/*如果已经到了这条代码,就证明在整个表达式中Elvis已经没有了,并且全部的SPEL解析完成了*/
}
}
expressionStr = SpelPaserUtil.parseTemplateExpression(expressionStr, rootMap);
return expressionStr;
} catch (Throwable e) {
// logger.info("elvis happend error . current expression is {}", expressionStr);
// e.printStackTrace();
}
return "";
}
}