cn.k7g.alloy.mold.impl.SpelMoldService Maven / Gradle / Ivy
package cn.k7g.alloy.mold.impl;
import cn.k7g.alloy.mold.BaseMold;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.expression.BeanExpressionContextAccessor;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.expression.EnvironmentAccessor;
import org.springframework.context.expression.MapAccessor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.MethodResolver;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import javax.annotation.PostConstruct;
import java.lang.reflect.Method;
import java.util.stream.Collectors;
@Slf4j
public class SpelMoldService extends AbstractMoldService {
final ExpressionParser expressionParser = new SpelExpressionParser();
SimpleEvaluationContext simpleEvaluationContext;
StandardEvaluationContext standardEvaluationContext;
StandardEvaluationContext uncontrolledEvaluationContext;
final MethodResolver methodResolver = (context, targetObject, name, argumentTypes) -> {
try {
DelegateMethod method;
if (targetObject instanceof GlobalVal) {
method = globalMethod.get(name).stream().filter(o -> {
if (o.originMethod.getParameterCount() != argumentTypes.size()) {
return false;
}
for (int i = 0; i < o.originMethod.getParameterCount(); i++) {
if (!o.originMethod.getParameters()[i].getType().isAssignableFrom(argumentTypes.get(i).getType())) {
return false;
}
}
return true;
}).findFirst().orElse(null);
if (method == null) {
throw new NoSuchMethodException("mold 未注册方法: " + name);
}
} else {
Class[] classes = argumentTypes.stream().map(o -> o.getType()).collect(Collectors.toList()).toArray(new Class[0]);
Method m = targetObject.getClass().getMethod(name, classes);
method = new DelegateMethod(targetObject, m);
}
return new AbstractMoldService.DelegateExecutor(method);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
};
public SpelMoldService() {
}
@PostConstruct
public void init() {
simpleEvaluationContext = new SimpleEvaluationContext.Builder(new ReflectivePropertyAccessor(), new MapAccessor()).build();
standardEvaluationContext = new StandardEvaluationContext();
standardEvaluationContext.addPropertyAccessor(new ReflectivePropertyAccessor());
standardEvaluationContext.addPropertyAccessor(new MapAccessor());
standardEvaluationContext.addMethodResolver(methodResolver);
uncontrolledEvaluationContext = new StandardEvaluationContext();
uncontrolledEvaluationContext.addPropertyAccessor(new ReflectivePropertyAccessor());
uncontrolledEvaluationContext.addPropertyAccessor(new MapAccessor());
uncontrolledEvaluationContext.addPropertyAccessor(new EnvironmentAccessor());
uncontrolledEvaluationContext.addPropertyAccessor(new BeanExpressionContextAccessor());
uncontrolledEvaluationContext.addMethodResolver(methodResolver);
uncontrolledEvaluationContext.setBeanResolver(new BeanFactoryResolver(context));
}
/**
* 仅支持数据值的调用,不支持方法调用
* @param baseMold
* @return
*/
@Override
public Object createContent(BaseMold baseMold) {
return exec(simpleEvaluationContext, baseMold);
}
/**
* 支持方法的调用, 注意如果有前端提交的内容,不建议使用此方法。可能是造成安全问题。
* 优先考虑采用 createVal 方法
* @param baseMold
* @return
*/
@Override
public Object createContentMixUnsafe(BaseMold baseMold) {
return exec(standardEvaluationContext, baseMold);
}
@Override
public Object createContentUncontrolled(BaseMold baseMold) {
return exec(uncontrolledEvaluationContext, baseMold);
}
public Object exec(EvaluationContext evaluationContext, BaseMold baseMold) {
GlobalVal params = readyVar(baseMold);
Object value = expressionParser.parseExpression(baseMold.getContent(), new TemplateParserContext()).getValue(evaluationContext, params);
if (log.isDebugEnabled()) {
log.debug("mold执行结果\nmoldContent: {} \nmoldParams: {}\nmodlResult: {} \n", baseMold.getContent(), params, value);
}
return value;
}
}