之前仿照mybatis写了一个sql语句与代码解耦的工具类,最一开始的设想是,应用程序能加载xml文件中的sql语句,并能对sql语句的形参赋值,完成sql的正确执行即可,但是这样不具有扩展性。
回想sql语句与代码耦合的场景,会有通过分支判断进行sql拼接的情况,所以今天又把mybatis的代码扒拉了一番,学学人家的if语法怎么实现正确解析的。
前提;自己搭好mybatis源代码环境(源码地址:GitHub - mybatis/mybatis-3: MyBatis SQL mapper framework for Java 下载下来导入idea即可)
一番debug进入org.apache.ibatis.scripting.xmltags.IfSqlNode.java 的apply 方法
@Override
public boolean apply(DynamicContext context) {
if (evaluator.evaluateBoolean(test, context.getBindings())) {
contents.apply(context);
return true;
}
return false;
}
再进入org.apache.ibatis.scripting.xmltags.ExpressionEvaluator.java 的evaluateBoolean方法
public boolean evaluateBoolean(String expression, Object parameterObject) {
Object value = OgnlCache.getValue(expression, parameterObject);
if (value instanceof Boolean) {
return (Boolean) value;
}
if (value instanceof Number) {
return new BigDecimal(String.valueOf(value)).compareTo(BigDecimal.ZERO) != 0;
}
return value != null;
}
重点要来了,进入org.apache.ibatis.scripting.xmltags.OgnlCache.java 的getValue 方法
public static Object getValue(String expression, Object root) {
try {
Map context = Ognl.createDefaultContext(root, MEMBER_ACCESS, CLASS_RESOLVER, null);
return Ognl.getValue(parseExpression(expression), context, root);
} catch (OgnlException e) {
throw new BuilderException("Error evaluating expression '" + expression + "'. Cause: " + e, e);
}
}
附其中调用的 parseExpression方法内容:
private static Object parseExpression(String expression) throws OgnlException {
Object node = expressionCache.get(expression);
if (node == null) {
node = Ognl.parseExpression(expression);
expressionCache.put(expression, node);
}
return node;
}
已经很明显了:mybatis通过调用ognl的类库实现mapper文件的if语法判断。具体ognl里边的源码就不往下看了,到这已经达到我的研究目的了。
最后附上一个main方法,便于读者学习测试,将下方main方法添加到org.apache.ibatis.scripting.xmltags.OgnlCache.java中即可
public static void main(String[] args)
{
String expression = null;
try {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("user", "xuliang");
hashMap.put("pwd", "7788");
expression = "(user != null and pwd == '2345') or pwd=='7788'";
Map context = Ognl.createDefaultContext(hashMap, MEMBER_ACCESS, CLASS_RESOLVER, null);
System.out.println(Ognl.getValue(parseExpression(expression), context, hashMap));
} catch (OgnlException e) {
throw new BuilderException("Error evaluating expression '" + expression + "'. Cause: " + e, e);
}
}