使用 Mybatis 框架时,我们经常使用 “<if test="email != null and email != ''">” 来进行非空判断,但感觉这种方式不够优雅,比如需要代码层面进行 trim 操作,如果把此逻辑加在 test 中只会使得 xml 更加冗长,那能不能让 test 内部调用 java 代码呢?可以的,可以使用 @ 符号实现,例如:“<if test="@org.apache.commons.lang3.StringUtils@isNotBlank(email)">”,但是包名太长,能不能这样呢:“<if test="isNotBlank(email)">”,启动报错,不符合语法,那如果就想这样写,还要满足语法呢?
思路就是在某个步骤拦截一下解析出来的 if 标签的 test 属性,将 “isNotBlank(email)” 手动替换成 “@org.apache.commons.lang3.StringUtils@isNotBlank(email)”,于是搜索了下 mybatis 的拦截器,发现如下所示代码貌似可以获取 sql:
@Component
@Intercepts({
@Signature(
type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class
})
})
public class MySqlInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 方法一
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
//先拦截到RoutingStatementHandler,里面有个StatementHandler类型的delegate变量,其实现类是BaseStatementHandler,然后就到BaseStatementHandler的成员变量mappedStatement
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
//id为执行的mapper方法的全路径名,如com.uv.dao.UserMapper.insertUser
String id = mappedStatement.getId();
//sql语句类型 select、delete、insert、update
String sqlCommandType = mappedStatement.getSqlCommandType().toString();
BoundSql boundSql = statementHandler.getBoundSql();
//获取到原始sql语句
String sql = boundSql.getSql();
String mSql = sql;
//TODO 修改自己的mySql
//通过反射修改sql语句
Field field = boundSql.getClass().getDeclaredField("sql");
field.setAccessible(true);
field.set(boundSql, mSql);
return invocation.proceed();
}
}
但是获取到的 sql 是去掉 “<if” 等标签之后的,如果是简单的在后面加上 limit 实现自定义分页插件是可以的,但是实现我这个需求貌似不行,可能如果花时间继续探索兴许可以找到一个通过实现 mybatis 提供的接口解决的方案,但是由于时间有限,最重要的是想尝试一下修改 mybatis 源代码,我对 mybatis 的加载顺序不是很了解,但是我知道一定有类似 “String test = getAttr( "test" )” 的逻辑,如果能找到,那么判断一下 test 是否以 “isNotBlank” 开头,然后将其替换成 “@org.apache.commons.lang3.StringUtils@isNotBlank” 就可以了,但是类似 “String test = getAttr( "test" )” 的代码又在哪里呢?于是百度了下:
进入第一个全局搜索 "test",找到:
现在心里有底了,开始准备 mybatis源码:
ide 快捷键 ctrl + shift +r 搜索"XMLScriptBuilder",找到:
'
进入maven本地仓库目录寻找 源码,发现没有:
点击 "Download Sources"下载源码:
此时源码已经下载成功了:
解压源码jar
新建一个maven工程( 不要选择 create from archetype ),三维坐标按照下图中的 pom.properties 文件中的设置:
用上图中的 pom.xml替换掉新建的额工程中的pom.xml,并将源码目录下的 org 目录整个复制到工程中的 src/main/java 下,如下图所示:
修改源码:
然后 执行 mvn install,不出意外的话,此时 maven 本地仓库中的 mybatis-3.5.3.jar 已经替换成了 编译生成的jar