- 从数据库中读取存储的动态SQL
- 根据传入参数解析标签,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) {
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) {
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() {
}
@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() {
}
@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() {
}
@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() {
}
@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() {
}
@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() {
}
@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() {
}
@Override
public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle).mixedSqlNode;
targetContents.add(mixedSqlNode);
}
}
private class ChooseHandler implements NodeHandler {
public ChooseHandler() {
}
@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;
}
}
}
- 执行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>