mybatis标签解析教程

mybatis标签解析

标签结构

我们在mapper的xml文件中,使用动态SQL,那么这些标签<where>、<if>、<set>、<ForEach>、<Choose>、<Trim> 等是怎么解析的呢?我们先看包的结构
在这里插入图片描述

包结构中,script -> xmltags下面的类便是这些动态标签对象,我们在看看这些动态的tag的关系,如下

在这里插入图片描述

这些动态标签都实现了SqlNode接口

public interface SqlNode {
  boolean apply(DynamicContext context);
}

标签处理器

那么mybatis是如何解析这些动态标签的呢?

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
    }
  }
}

到此解析完成,其他标签解析过程类似

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罗罗的1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值