Mybatis解析存储在数据库中的动态SQL

  1. 从数据库中读取存储的动态SQL
  2. 根据传入参数解析标签,Sql存在了map的queryScript中
  private void replaceMybatisTags(Map<String, Object> parameterMap) {
        String sql = "<script>" + parameterMap.get("queryScript") + "</script>";
        SqlSource queryScript = iacScriptBuilder.parseScriptNode(sql);
        if (queryScript instanceof DynamicSqlSource){
            MetaObject metaObject = SystemMetaObject.forObject(queryScript);
            Configuration configuration = (Configuration) metaObject.getValue("configuration");
            SqlNode rootSqlNode = (SqlNode) metaObject.getValue("rootSqlNode");
            DynamicContext context = new DynamicContext(configuration, parameterMap);
            rootSqlNode.apply(context);
            parameterMap.putAll(context.getBindings());
            parameterMap.put("queryScript",context.getSql());
        }
    }
@Slf4j
public class IacScriptBuilder extends org.apache.ibatis.builder.BaseBuilder {

    private final Class<?> parameterType;
    private final Map<String, IacScriptBuilder.NodeHandler> nodeHandlerMap = new HashMap<>();


    public IacScriptBuilder(Configuration configuration, Class<?> parameterType) {
        super(configuration);
        this.parameterType = parameterType;
        initNodeHandlerMap();
    }


    private void initNodeHandlerMap() {
        nodeHandlerMap.put("trim", new IacScriptBuilder.TrimHandler());
        nodeHandlerMap.put("where", new IacScriptBuilder.WhereHandler());
        nodeHandlerMap.put("set", new IacScriptBuilder.SetHandler());
        nodeHandlerMap.put("foreach", new IacScriptBuilder.ForEachHandler());
        nodeHandlerMap.put("if", new IacScriptBuilder.IfHandler());
        nodeHandlerMap.put("choose", new IacScriptBuilder.ChooseHandler());
        nodeHandlerMap.put("when", new IacScriptBuilder.IfHandler());
        nodeHandlerMap.put("otherwise", new IacScriptBuilder.OtherwiseHandler());
        nodeHandlerMap.put("bind", new IacScriptBuilder.BindHandler());
    }

    public SqlSource parseScriptNode(String script) {
        // 解析Sql
        XPathParser parser = null;
        try{
            parser = new XPathParser(script, false, configuration.getVariables(), new XMLMapperEntityResolver());
        }catch (Exception e){
            return null;
        }
        XNode context = parser.evalNode("/script");
        DynamicResult dynamicResult = parseDynamicTags(context);
        SqlSource sqlSource = null;
        if (dynamicResult.isDynamic) {
            sqlSource = new DynamicSqlSource(configuration, dynamicResult.mixedSqlNode);
        } else {
            sqlSource = new RawSqlSource(configuration, dynamicResult.mixedSqlNode, parameterType);
        }
        return sqlSource;
    }

    protected DynamicResult parseDynamicTags(XNode node) {
        DynamicResult dynamicResult = new DynamicResult();
        List<SqlNode> contents = new ArrayList<>();
        NodeList children = node.getNode().getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            XNode child = node.newXNode(children.item(i));
            if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {
                String data = child.getStringBody("");
                TextSqlNode textSqlNode = new TextSqlNode(data);
                if (textSqlNode.isDynamic()) {
                    contents.add(textSqlNode);
                    dynamicResult.isDynamic = true;
                } else {
                    contents.add(new StaticTextSqlNode(data));
                }
            } else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) {
                // issue #628
                String nodeName = child.getNode().getNodeName();
                NodeHandler handler = nodeHandlerMap.get(nodeName);
                if (handler == null) {
                    throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement.");
                }
                handler.handleNode(child, contents);
                dynamicResult.isDynamic = true;
            }
        }
        dynamicResult.mixedSqlNode = new MixedSqlNode(contents);
        return dynamicResult;
    }

    /**
     * 结果集类
     */
    private class DynamicResult {
        MixedSqlNode mixedSqlNode;
        boolean isDynamic;
    }

    private interface NodeHandler {
        void handleNode(XNode nodeToHandle, List<SqlNode> targetContents);
    }

    private class BindHandler implements NodeHandler {
        public BindHandler() {
            // Prevent Synthetic Access
        }

        @Override
        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
            final String name = nodeToHandle.getStringAttribute("name");
            final String expression = nodeToHandle.getStringAttribute("value");
            final VarDeclSqlNode node = new VarDeclSqlNode(name, expression);
            targetContents.add(node);
        }
    }

    private class TrimHandler implements NodeHandler {
        public TrimHandler() {
            // Prevent Synthetic Access
        }

        @Override
        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
            MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle).mixedSqlNode;
            String prefix = nodeToHandle.getStringAttribute("prefix");
            String prefixOverrides = nodeToHandle.getStringAttribute("prefixOverrides");
            String suffix = nodeToHandle.getStringAttribute("suffix");
            String suffixOverrides = nodeToHandle.getStringAttribute("suffixOverrides");
            TrimSqlNode trim = new TrimSqlNode(configuration, mixedSqlNode, prefix, prefixOverrides, suffix, suffixOverrides);
            targetContents.add(trim);
        }
    }

    private class WhereHandler implements NodeHandler {
        public WhereHandler() {
            // Prevent Synthetic Access
        }

        @Override
        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
            MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle).mixedSqlNode;
            WhereSqlNode where = new WhereSqlNode(configuration, mixedSqlNode);
            targetContents.add(where);
        }
    }

    private class SetHandler implements NodeHandler {
        public SetHandler() {
            // Prevent Synthetic Access
        }

        @Override
        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
            MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle).mixedSqlNode;
            SetSqlNode set = new SetSqlNode(configuration, mixedSqlNode);
            targetContents.add(set);
        }
    }

    private class ForEachHandler implements NodeHandler {
        public ForEachHandler() {
            // Prevent Synthetic Access
        }

        @Override
        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
            MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle).mixedSqlNode;
            String collection = nodeToHandle.getStringAttribute("collection");
            String item = nodeToHandle.getStringAttribute("item");
            String index = nodeToHandle.getStringAttribute("index");
            String open = nodeToHandle.getStringAttribute("open");
            String close = nodeToHandle.getStringAttribute("close");
            String separator = nodeToHandle.getStringAttribute("separator");
            ForEachSqlNode forEachSqlNode = new ForEachSqlNode(configuration, mixedSqlNode, collection, index, item, open, close, separator);
            targetContents.add(forEachSqlNode);
        }
    }

    private class IfHandler implements NodeHandler {
        public IfHandler() {
            // Prevent Synthetic Access
        }

        @Override
        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
            MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle).mixedSqlNode;
            String test = nodeToHandle.getStringAttribute("test");
            IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test);
            targetContents.add(ifSqlNode);
        }
    }

    private class OtherwiseHandler implements NodeHandler {
        public OtherwiseHandler() {
            // Prevent Synthetic Access
        }

        @Override
        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
            MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle).mixedSqlNode;
            targetContents.add(mixedSqlNode);
        }
    }

    private class ChooseHandler implements NodeHandler {
        public ChooseHandler() {
            // Prevent Synthetic Access
        }

        @Override
        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
            List<SqlNode> whenSqlNodes = new ArrayList<>();
            List<SqlNode> otherwiseSqlNodes = new ArrayList<>();
            handleWhenOtherwiseNodes(nodeToHandle, whenSqlNodes, otherwiseSqlNodes);
            SqlNode defaultSqlNode = getDefaultSqlNode(otherwiseSqlNodes);
            ChooseSqlNode chooseSqlNode = new ChooseSqlNode(whenSqlNodes, defaultSqlNode);
            targetContents.add(chooseSqlNode);
        }

        private void handleWhenOtherwiseNodes(XNode chooseSqlNode, List<SqlNode> ifSqlNodes, List<SqlNode> defaultSqlNodes) {
            List<XNode> children = chooseSqlNode.getChildren();
            for (XNode child : children) {
                String nodeName = child.getNode().getNodeName();
                NodeHandler handler = nodeHandlerMap.get(nodeName);
                if (handler instanceof IfHandler) {
                    handler.handleNode(child, ifSqlNodes);
                } else if (handler instanceof OtherwiseHandler) {
                    handler.handleNode(child, defaultSqlNodes);
                }
            }
        }

        private SqlNode getDefaultSqlNode(List<SqlNode> defaultSqlNodes) {
            SqlNode defaultSqlNode = null;
            if (defaultSqlNodes.size() == 1) {
                defaultSqlNode = defaultSqlNodes.get(0);
            } else if (defaultSqlNodes.size() > 1) {
                throw new BuilderException("Too many default (otherwise) elements in choose statement.");
            }
            return defaultSqlNode;
        }
    }
}

  1. 执行mapper
List<Map<String, Object>> callQuery(Map<String, Object> parameterMap);
 <select id="callQuery" statementType="CALLABLE" parameterType="java.util.Map"
        resultType="com.xxxx.cis.capi.common.util.CamelKeyMap">
	<![CDATA[ ${queryScript} ]]>
</select>
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值