001package com.mybatisflex.spring.datasource.processor;
002
003import com.mybatisflex.core.datasource.processor.DataSourceProcessor;
004import com.mybatisflex.core.util.StringUtil;
005import org.springframework.context.expression.MethodBasedEvaluationContext;
006import org.springframework.core.DefaultParameterNameDiscoverer;
007import org.springframework.core.ParameterNameDiscoverer;
008import org.springframework.expression.BeanResolver;
009import org.springframework.expression.ExpressionParser;
010import org.springframework.expression.ParserContext;
011import org.springframework.expression.spel.standard.SpelExpressionParser;
012import org.springframework.expression.spel.support.StandardEvaluationContext;
013
014import java.lang.reflect.Method;
015
016/**
017 * SpEL表达式支持处理器
018 *
019 * @author Alay
020 * @since 2024-12-07 15:48
021 */
022public class SpelExpressionDataSourceProcessor implements DataSourceProcessor {
023    /**
024     * 动态表达式前缀
025     */
026    private static final String DYNAMIC_PREFIX = "#";
027    /**
028     * 参数发现器
029     */
030    private static final ParameterNameDiscoverer NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
031    /**
032     * Express语法解析器
033     */
034    private static final ExpressionParser PARSER = new SpelExpressionParser();
035
036    private BeanResolver beanResolver;
037    /**
038     * 解析上下文的模板 对于默认不设置的情况下,从参数中取值的方式 #param1
039     * 设置指定模板 ParserContext. TEMPLATE_EXPRESSION{@link ParserContext#TEMPLATE_EXPRESSION} 后的取值方式: #{#param1}
040     */
041    private ParserContext parserContext = new ParserContext() {
042
043        @Override
044        public boolean isTemplate() {
045            return false;
046        }
047
048        @Override
049        public String getExpressionPrefix() {
050            return null;
051        }
052
053        @Override
054        public String getExpressionSuffix() {
055            return null;
056        }
057    };
058
059
060    @Override
061    public String process(String dataSourceKey, Object mapper, Method method, Object[] arguments) {
062        if (StringUtil.noText(dataSourceKey)) return null;
063        if (!dataSourceKey.startsWith(DYNAMIC_PREFIX)) return null;
064        if (arguments.length == 0) return null;
065
066        RootObject rootObject = new RootObject(method, arguments, mapper);
067        StandardEvaluationContext context = new MethodBasedEvaluationContext(rootObject, method, arguments, NAME_DISCOVERER);
068        context.setBeanResolver(beanResolver);
069        final Object value = PARSER.parseExpression(dataSourceKey, parserContext).getValue(context);
070        return value == null ? null : value.toString();
071    }
072
073
074    public void setBeanResolver(BeanResolver beanResolver) {
075        this.beanResolver = beanResolver;
076    }
077
078    public void setParserContext(ParserContext parserContext) {
079        this.parserContext = parserContext;
080    }
081
082    public static class RootObject {
083        private final Method method;
084        private final Object[] args;
085        private final Object target;
086
087        public RootObject(Method method, Object[] args, Object target) {
088            this.method = method;
089            this.args = args;
090            this.target = target;
091        }
092
093        public Method getMethod() {
094            return method;
095        }
096
097        public Object[] getArgs() {
098            return args;
099        }
100
101        public Object getTarget() {
102            return target;
103        }
104    }
105
106}