mybatis标签解析
标签结构
我们在mapper的xml文件中,使用动态SQL,那么这些标签<where>、<if>、<set>、<ForEach>、<Choose>、<Trim>
等是怎么解析的呢?我们先看包的结构
包结构中,script -> xmltags 便是这些动态标签对象,我们在看看这些动态的tag的关系,如下
SqlNode类如下
public interface SqlNode {
boolean apply(DynamicContext context);
}
标签处理器
现在那么是如何解析这些的呢?
public class XMLScriptBuilder extends BaseBuilder {
private final XNode context;
private boolean isDynamic; //是否是动态sql, 根据占位符#{},${}来判断,有就是动态的
private final Class<?> parameterType;
private final Map<String, NodeHandler> nodeHandlerMap = new HashMap<>();
public XMLScriptBuilder(Configuration configuration, XNode context, Class<?> parameterType) {
super(configuration);
this.context = context;
this.parameterType = parameterType;
//初始化的标签处理器
initNodeHandlerMap();
}
private void initNodeHandlerMap() {
nodeHandlerMap.put("trim", new TrimHandler());
nodeHandlerMap.put("where", new WhereHandler());
nodeHandlerMap.put("set", new SetHandler());
nodeHandlerMap.put("foreach", new ForEachHandler());
nodeHandlerMap.put("if", new IfHandler());
nodeHandlerMap.put("choose", new ChooseHandler());
nodeHandlerMap.put("when", new IfHandler());
nodeHandlerMap.put("otherwise", new OtherwiseHandler());
nodeHandlerMap.put("bind", new BindHandler());
}
}
我们看看这些标签处理器,都实现了NodeHandler接口
public class XMLScriptBuilder extends BaseBuilder {
//内部类NodeHandler,提供了各种具体的标签Handler
private interface NodeHandler {
void handleNode(XNode nodeToHandle, List<SqlNode> targetContents);
}
private class BindHandler implements NodeHandler {}
private class TrimHandler implements NodeHandler {}
private class WhereHandler implements NodeHandler {}
private class SetHandler implements NodeHandler {}
private class ForEachHandler implements NodeHandler {}
private class IfHandler implements NodeHandler {}
private class OtherwiseHandler implements NodeHandler {}
private class ChooseHandler implements NodeHandler {}
}
where
标签示例
我们用 where
标签示例,解析的时候根据xml中node的名称where
名称获取对应的Handler,也就是WhereHandler
private class WhereHandler implements NodeHandler {
public WhereHandler() {
// Prevent Synthetic Access
}
@Override
public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);
//解析where标签,mixedSqlNode 就是where标签里面的内容
WhereSqlNode where = new WhereSqlNode(configuration, mixedSqlNode);
targetContents.add(where);
}
}
我们继续看下这个WhereSqlNode
是怎么处理的
public class WhereSqlNode extends TrimSqlNode {
//前缀,目测是删除where条件后面的第一个运算法,where and a = 1 这种情况
private static List<String> prefixList = Arrays.asList("AND ","OR ","AND\n", "OR\n", "AND\r", "OR\r", "AND\t", "OR\t");
public WhereSqlNode(Configuration configuration, SqlNode contents) {
super(configuration, contents, "WHERE", prefixList, null, null);
}
}
我们看到是直接走父类TrimSqlNode
去了
public void applyAll() {
sqlBuffer = new StringBuilder(sqlBuffer.toString().trim());
String trimmedUppercaseSql = sqlBuffer.toString().toUpperCase(Locale.ENGLISH);
if (trimmedUppercaseSql.length() > 0) {
applyPrefix(sqlBuffer, trimmedUppercaseSql);
applySuffix(sqlBuffer, trimmedUppercaseSql);
}
delegate.appendSql(sqlBuffer.toString());
}
private void applyPrefix(StringBuilder sql, String trimmedUppercaseSql) {
if (!prefixApplied) {
prefixApplied = true;
if (prefixesToOverride != null) {
//遍历运算符,删除where前缀
for (String toRemove : prefixesToOverride) {
if (trimmedUppercaseSql.startsWith(toRemove)) {
sql.delete(0, toRemove.trim().length());
break;
}
}
}
if (prefix != null) {
sql.insert(0, " ");//首位添加空格
sql.insert(0, prefix);//然后添加where
}
}
}
到此解析完成