Skip to content

Commit 40b7967

Browse files
committed
GenericTokenParser 源码
1 parent 95f485e commit 40b7967

File tree

2 files changed

+175
-0
lines changed

2 files changed

+175
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# GenericTokenParser
2+
- Author: [HuiFer](https://github.com/huifer)
3+
4+
```java
5+
/**
6+
* Copyright 2009-2019 the original author or authors.
7+
* <p>
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
* <p>
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
* <p>
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
package org.apache.ibatis.parsing;
21+
22+
/**
23+
* @author Clinton Begin
24+
*/
25+
public class GenericTokenParser {
26+
27+
/**
28+
* 开始标记
29+
*/
30+
private final String openToken;
31+
/**
32+
* 结束标记
33+
*/
34+
private final String closeToken;
35+
/**
36+
* 标记处理器
37+
*/
38+
private final TokenHandler handler;
39+
40+
public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) {
41+
this.openToken = openToken;
42+
this.closeToken = closeToken;
43+
this.handler = handler;
44+
}
45+
46+
/**
47+
* 核心处理方法 , 看测试类{@link org.apache.ibatis.parsing.GenericTokenParserTest}
48+
* @param text
49+
* @return
50+
*/
51+
public String parse(String text) {
52+
// 判断是否空
53+
if (text == null || text.isEmpty()) {
54+
return "";
55+
}
56+
// search open token
57+
// 判断 openToken 所在的位置-1不存在
58+
int start = text.indexOf(openToken);
59+
if (start == -1) {
60+
return text;
61+
}
62+
char[] src = text.toCharArray();
63+
int offset = 0;
64+
final StringBuilder builder = new StringBuilder();
65+
StringBuilder expression = null;
66+
67+
// 循环处理 assertEquals("James T Kirk reporting.", parser.parse("${first_name} ${initial} ${last_name} reporting."));
68+
// 将${} 转换成正常文本
69+
while (start > -1) {
70+
if (start > 0 && src[start - 1] == '\\') {
71+
// `\` 忽略这个参数
72+
// this open token is escaped. remove the backslash and continue.
73+
builder.append(src, offset, start - offset - 1).append(openToken);
74+
// offset 重新计算进行下一步循环
75+
offset = start + openToken.length();
76+
} else {
77+
// found open token. let's search close token.
78+
if (expression == null) {
79+
expression = new StringBuilder();
80+
} else {
81+
expression.setLength(0);
82+
}
83+
builder.append(src, offset, start - offset);
84+
offset = start + openToken.length();
85+
int end = text.indexOf(closeToken, offset);
86+
while (end > -1) {
87+
if (end > offset && src[end - 1] == '\\') {
88+
// 遇到`\`该参数不需要处理
89+
// this close token is escaped. remove the backslash and continue.
90+
expression.append(src, offset, end - offset - 1).append(closeToken);
91+
// 计算offset重新推算替换的字符串
92+
offset = end + closeToken.length();
93+
end = text.indexOf(closeToken, offset);
94+
} else {
95+
expression.append(src, offset, end - offset);
96+
break;
97+
}
98+
}
99+
if (end == -1) {
100+
// end == -1 closeToken 不存在,获取后面的所有字符串, openToken - closeToken 之间的内容
101+
// close token was not found.
102+
builder.append(src, start, src.length - start);
103+
offset = src.length;
104+
} else {
105+
// closeToken存在 继续执行
106+
builder.append(handler.handleToken(expression.toString()));
107+
offset = end + closeToken.length();
108+
}
109+
}
110+
start = text.indexOf(openToken, offset);
111+
}
112+
if (offset < src.length) {
113+
builder.append(src, offset, src.length - offset);
114+
}
115+
// 返回的是一个替换后的sql脚本
116+
return builder.toString();
117+
}
118+
}
119+
120+
```
121+
122+
123+
- 一个具体的例子`org.apache.ibatis.builder.SqlSourceBuilder.ParameterMappingTokenHandler`
124+
- 具体类`org.apache.ibatis.builder.SqlSourceBuilder`
125+
```java
126+
/**
127+
* ? 的来源
128+
*
129+
* @param content
130+
* @return
131+
*/
132+
@Override
133+
public String handleToken(String content) {
134+
parameterMappings.add(buildParameterMapping(content));
135+
return "?";
136+
}
137+
138+
```
139+
```java
140+
/**
141+
* sql 参数类型 , 返回值
142+
*
143+
* <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
144+
* <!--@mbg.generated-->
145+
* select
146+
* <include refid="Base_Column_List" />
147+
* from hs_sell
148+
* where ID = #{id,jdbcType=INTEGER}
149+
* </select>
150+
* => 替换成问号
151+
* select
152+
* <p>
153+
* <p>
154+
* ID, USER_ID, GOOD_ID, PRICE, `SIZE`, COMPANY_ID, GROUP_ID, VERSION, DELETED, CREATE_USER,
155+
* CREATE_TIME, UPDATE_USER, UPDATE_TIME, WORK_ORDER_ID
156+
* <p>
157+
* from hs_sell
158+
* where ID = ?
159+
*
160+
* @param originalSql sql文本
161+
* @param parameterType 默认 object
162+
* @param additionalParameters
163+
* @return
164+
*/
165+
public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {
166+
ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);
167+
// org.apache.ibatis.builder.SqlSourceBuilder.ParameterMappingTokenHandler.handleToken
168+
GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
169+
String sql = parser.parse(originalSql);
170+
return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
171+
}
172+
173+
```
174+
175+
![image-20191219100446796](/images/mybatis/image-20191219100446796.png)
106 KB
Loading

0 commit comments

Comments
 (0)