VariableTokenHandler.handleToken 传入String变量globalId,将其替换成1并返回。
public String handleToken(String content) {
//variables里面存放全局的变量,为空直接return
if (variables != null) {
String key = content;
//是否存在默认值,默认是false
if (enableDefaultValue) {
final int separatorIndex = content.indexOf(defaultValueSeparator);
String defaultValue = null;
if (separatorIndex >= 0) {
key = content.substring(0, separatorIndex);
defaultValue = content.substring(separatorIndex + defaultValueSeparator.length());
}
if (defaultValue != null) {
return variables.getProperty(key, defaultValue);
}
}
//variables是用来存放全局变量的容器。
//这里会从全局变量中找到我们定义的globalId,然后将对应的值返回,这样我们的sql就拼接完成了
if (variables.containsKey(key)) {
return variables.getProperty(key);
}
}
return “${” + content + “}”;
}
}
解析器代码,根据传入的标记开始解析,这里传入开始标记KaTeX parse error: Expected '}', got 'EOF' at end of input: {和结束标记}。在这之后还会用来解析#{}。代码比较长,最好打个断点进去看。
//GenericTokenParser.parse
public String parse(String text) {
if (text == null || text.isEmpty()) {
return “”;
}
//查找开始标记,如果不存在返回-1 ,存在返回偏移量
int start = text.indexOf(openToken);
if (start == -1) {
return text;
}
char[] src = text.toCharArray();
int offset = 0;
final StringBuilder builder = new StringBuilder();
//这个变量用来存放中间的字符,如${id}中的id
StringBuilder expression = null;
//如果存在开始标志
while (start > -1) {
//这里将从offset开始,一直到start的字符先放入builder中
//例如select * from user where id =
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 = 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);
//取到中间字符globalId
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 = end + closeToken.length();
end = text.indexOf(closeToken, offset);
} else {
expression.append(src, offset, end - offset);
break;
}
}
if (end == -1) {
// close token was not found.
builder.append(src, start, src.length - start);
offset = src.length;
} else {
//这里根据不同的处理器会有不同的操作,刚才传入的是VariableTokenHandler
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);
}
return builder.toString();
}
到这里全局变量就解析完成了,那么如果在全局变量中没有找到对 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》开源 应的值该怎么办呢?例如我这里使用的sql是select * from user where id = i d , 而 不 是 {id},而不是 id,而不是{globalId},那么根据VariableTokenHandler处理器,它会原封不动的进行返回,等待后文的解析。
顺便一提,这一部分的解析实在解析我们的配置文件的时候就发生了,方法入口为context.evalNodes(“select|insert|update|delete”),在解析配置的时候,其他节点也大量使用了context.evalNodes()方法去解,所以只要当配置mybatis.xml文件中的properties节点解析完成之后,里面的变量就是能全局使用了,这也是为什么properties节点要放在第一个解析。
又由于这个通用解析器只解析${XXX}格式的变量,所以全局的变量不能写成#{xxx}.
入参${}的解析
List get(Integer id);
select * from user where id =