Mybatis动态标签解析
# 表达式解析
mybatis框架中解析动态表达式采用了ognl框架实现,但其封装了两个类:
OgnlCache:用于缓存表达式解析结果
ExpressionEvaluator:实际解析表达式结果
我们可以通过以下代码来测试表达式的解析结果:
public static void testOgnl() {
User user = new User();
user.setId("wyt");
user.setName("wyt");
String expression = "user.id != null and user.id != ''";
Map<String, Object> context = new ConcurrentHashMap<>(10);
context.put("user", user);
ExpressionEvaluator expressionEvaluator = new ExpressionEvaluator();
boolean ret = expressionEvaluator.evaluateBoolean(expression, context);
System.out.println("ret:" + ret);
}
输出结果为:
ret:true
# 动态标签解析与执行
XMLScriptBuilder.java中将各类标签封装成类(如:IfHandler类):
NodeHandler nodeHandlers(String nodeName) {
Map<String, NodeHandler> map = new HashMap<String, NodeHandler>();
map.put("trim", new TrimHandler());
map.put("where", new WhereHandler());
map.put("set", new SetHandler());
map.put("foreach", new ForEachHandler());
map.put("if", new IfHandler());
map.put("choose", new ChooseHandler());
map.put("when", new IfHandler());
map.put("otherwise", new OtherwiseHandler());
map.put("bind", new BindHandler());
return map.get(nodeName);
}
如果获取到子节点中包含节点,则说明为动态节点:
List<SqlNode> parseDynamicTags(XNode node) {
List<SqlNode> contents = new ArrayList<SqlNode>();
NodeList children = node.getNode().getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
XNode child = node.newXNode(children.item(i));
if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {
String data = child.getStringBody("");
TextSqlNode textSqlNode = new TextSqlNode(data);
if (textSqlNode.isDynamic()) {
contents.add(textSqlNode);
isDynamic = true;
} else {
contents.add(new StaticTextSqlNode(data));
}
} else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) { // issue #628 这里是动态节点解析
String nodeName = child.getNode().getNodeName();
NodeHandler handler = nodeHandlers(nodeName);
if (handler == null) {
throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement.");
}
handler.handleNode(child, contents);
isDynamic = true;
}
}
return contents;
}
IfNode解析后生成IfSqlNode对象:
private class IfHandler implements NodeHandler {
public IfHandler() {
// Prevent Synthetic Access
}
@Override
public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
//动态标签则为包含预填充参数的标签
List<SqlNode> contents = parseDynamicTags(nodeToHandle);
MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
String test = nodeToHandle.getStringAttribute("test");
IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test);
targetContents.add(ifSqlNode);
}
}
解析完成就是执行标签了,执行标签的时候尤其是表达式则通过ognl表达式解析:
public IfSqlNode(SqlNode contents, String test) {
this.test = test;
this.contents = contents;
this.evaluator = new ExpressionEvaluator();
}
@Override
public boolean apply(DynamicContext context) {
if (evaluator.evaluateBoolean(test, context.getBindings())) {
contents.apply(context);
return true;
}
return false;
}
apply方法实现如下:
@Override
public boolean apply(DynamicContext context) {
GenericTokenParser parser = createParser(new BindingTokenParser(context, injectionFilter));
context.appendSql(parser.parse(text));
return true;
}
当执行结果完成后如何影响生成的SQL语句呢?如果是一个动态的语句,解析完成后追加SQL
@Override
public boolean apply(DynamicContext context) {
GenericTokenParser parser = createParser(new BindingTokenParser(context, injectionFilter));
context.appendSql(parser.parse(text));
return true;
}
SQL语句是追加到最终执行的语句了,但还有预填充的值,这个该如何处理呢?BindingTokenParser解析就是将预填充参数写入到最终参数中。
@Override
public String handleToken(String content) {
Object parameter = context.getBindings().get("_parameter");
if (parameter == null) {
context.getBindings().put("value", null);
} else if (SimpleTypeRegistry.isSimpleType(parameter.getClass())) {
context.getBindings().put("value", parameter);
}
Object value = OgnlCache.getValue(content, context.getBindings());
String srtValue = (value == null ? "" : String.valueOf(value)); // issue #274 return "" instead of "null"
checkInjection(srtValue);
return srtValue;
}
如果是foreachNode则会预填充很多的参数及SQL语句以及展开的参数信息。
原文地址:https://blog.csdn.net/u014291956/article/details/145089349
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!