diff --git a/docs/Mybatis/HuiFer-Mybats-GenericTokenParser.md b/docs/Mybatis/HuiFer-Mybats-GenericTokenParser.md new file mode 100644 index 0000000..041c090 --- /dev/null +++ b/docs/Mybatis/HuiFer-Mybats-GenericTokenParser.md @@ -0,0 +1,175 @@ +# GenericTokenParser +- Author: [HuiFer](https://github.com/huifer) + +```java +/** + * Copyright 2009-2019 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.parsing; + +/** + * @author Clinton Begin + */ +public class GenericTokenParser { + + /** + * 开始标记 + */ + private final String openToken; + /** + * 结束标记 + */ + private final String closeToken; + /** + * 标记处理器 + */ + private final TokenHandler handler; + + public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) { + this.openToken = openToken; + this.closeToken = closeToken; + this.handler = handler; + } + + /** + * 核心处理方法 , 看测试类{@link org.apache.ibatis.parsing.GenericTokenParserTest} + * @param text + * @return + */ + public String parse(String text) { + // 判断是否空 + if (text == null || text.isEmpty()) { + return ""; + } + // search open token + // 判断 openToken 所在的位置-1不存在 + int start = text.indexOf(openToken); + if (start == -1) { + return text; + } + char[] src = text.toCharArray(); + int offset = 0; + final StringBuilder builder = new StringBuilder(); + StringBuilder expression = null; + + // 循环处理 assertEquals("James T Kirk reporting.", parser.parse("${first_name} ${initial} ${last_name} reporting.")); + // 将${} 转换成正常文本 + while (start > -1) { + if (start > 0 && src[start - 1] == '\\') { + // `\` 忽略这个参数 + // this open token is escaped. remove the backslash and continue. + builder.append(src, offset, start - offset - 1).append(openToken); + // offset 重新计算进行下一步循环 + offset = start + openToken.length(); + } else { + // found open token. let's search close token. + if (expression == null) { + expression = new StringBuilder(); + } else { + expression.setLength(0); + } + builder.append(src, offset, start - offset); + offset = start + openToken.length(); + int end = text.indexOf(closeToken, offset); + while (end > -1) { + if (end > offset && src[end - 1] == '\\') { + // 遇到`\`该参数不需要处理 + // this close token is escaped. remove the backslash and continue. + expression.append(src, offset, end - offset - 1).append(closeToken); + // 计算offset重新推算替换的字符串 + offset = end + closeToken.length(); + end = text.indexOf(closeToken, offset); + } else { + expression.append(src, offset, end - offset); + break; + } + } + if (end == -1) { + // end == -1 closeToken 不存在,获取后面的所有字符串, openToken - closeToken 之间的内容 + // close token was not found. + builder.append(src, start, src.length - start); + offset = src.length; + } else { + // closeToken存在 继续执行 + builder.append(handler.handleToken(expression.toString())); + offset = end + closeToken.length(); + } + } + start = text.indexOf(openToken, offset); + } + if (offset < src.length) { + builder.append(src, offset, src.length - offset); + } + // 返回的是一个替换后的sql脚本 + return builder.toString(); + } +} + +``` + + +- 一个具体的例子`org.apache.ibatis.builder.SqlSourceBuilder.ParameterMappingTokenHandler` + - 具体类`org.apache.ibatis.builder.SqlSourceBuilder` +```java + /** + * ? 的来源 + * + * @param content + * @return + */ + @Override + public String handleToken(String content) { + parameterMappings.add(buildParameterMapping(content)); + return "?"; + } + +``` +```java + /** + * sql 参数类型 , 返回值 + * + * + * => 替换成问号 + * select + *

+ *

+ * ID, USER_ID, GOOD_ID, PRICE, `SIZE`, COMPANY_ID, GROUP_ID, VERSION, DELETED, CREATE_USER, + * CREATE_TIME, UPDATE_USER, UPDATE_TIME, WORK_ORDER_ID + *

+ * from hs_sell + * where ID = ? + * + * @param originalSql sql文本 + * @param parameterType 默认 object + * @param additionalParameters + * @return + */ + public SqlSource parse(String originalSql, Class parameterType, Map additionalParameters) { + ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters); +// org.apache.ibatis.builder.SqlSourceBuilder.ParameterMappingTokenHandler.handleToken + GenericTokenParser parser = new GenericTokenParser("#{", "}", handler); + String sql = parser.parse(originalSql); + return new StaticSqlSource(configuration, sql, handler.getParameterMappings()); + } + +``` + +![image-20191219100446796](/images/mybatis/image-20191219100446796.png) \ No newline at end of file diff --git a/images/mybatis/image-20191219100446796.png b/images/mybatis/image-20191219100446796.png new file mode 100644 index 0000000..20bd937 Binary files /dev/null and b/images/mybatis/image-20191219100446796.png differ