这是我参与更文挑战的第12天
用于解析静态方法
org.apache.ibatis.scripting.xmltags.TextSqlNode.BindingTokenParser#handleToken
org.apache.ibatis.scripting.xmltags.OgnlCache#getValue
org.apache.ibatis.scripting.xmltags.OgnlCache#parseExpression解析表达式
org.apache.ibatis.ognl.Ognl#parseExpression
org.apache.ibatis.ognl.OgnlParser#staticReference
org.apache.ibatis.ognl.OgnlParser#staticMethodCall
org.apache.ibatis.ognl.OgnlRuntime#callStaticMethod
在SQL映射语句中可以支持引入以下几种方式:
<select id="getUserById" resultMap="BaseResultMap">
select * from user
<if test="id != null">
<where>
name = #{name}
and id =${id}
and id = ${user.id}
and id = ${@@abs(-12345678)}
and id = ${@@parseInt("654")}
and id='${@cn.followtry.mybatis.bean.User@name()}'
and id='${new cn.followtry.mybatis.bean.User()}'
and id=${@cn.followtry.mybatis.bean.User@haha}
and id='${@cn.followtry.mybatis.bean.User@arr[1]}'
and id='${@cn.followtry.mybatis.bean.User@list[1]}'
and id='${@cn.followtry.mybatis.bean.User@map.get("123")}'
and id='${@cn.followtry.mybatis.bean.CodeTypeEnum@THREE.ordinal()}'
</where>
</if>
limit 100
</select>
-
变量:
id =${id} -
属性:
id = ${user.id} -
静态方法(public):
id='${@cn.followtry.mybatis.bean.User@name()}' -
静态属性(public):
id=${@cn.followtry.mybatis.bean.User@aaa} -
数组索引:
id='${@cn.followtry.mybatis.bean.User@arr[1]}' -
集合:
'${@cn.followtry.mybatis.bean.User@list[1]}' -
Map:
id='${@cn.followtry.mybatis.bean.User@map.get("123")}'id='${@cn.followtry.mybatis.bean.User@map}'- Enum:
id=${@cn.followtry.mybatis.bean.CodeTypeEnum@THREE.ordinal()}
-
构造方法:
id='${new cn.followtry.mybatis.bean.User()}' -
java.lang.Math方法:
id = ${@@abs(-12345678)}可以省略class的编写,方法的默认class是java.lang.Math
${}语法中通过两个@字符,前者定位到Java类,后者定位到类中的方法或属性,这里只列出的其中一部分,对于Mybatis支持的${}语法,可以参见OGNL语法手册。
- 对
<bind>参数的调用可以通过#{}或${}方式获取,#{}可以防止注入:<bind>的value值会使用OGNL计算
<bind name="username_bind" value='@java.util.UUID@randomUUID().toString().replace("-", "")' />
- 使用OGNL实现单表的分表功能
分表这个功能是通用Mapper中的新功能,允许在运行的时候指定一个表名,通过指定的表名对表进行操作。这个功能实现就是使用了OGNL。
首先并不是所有的表都需要该功能,因此定义了一个接口,当参数(接口方法只有实体类一个参数)对象继承该接口的时候,就允许使用动态表名。
public interface IDynamicTableName {
/**
* 获取动态表名 - 只要有返回值,不是null和'',就会用返回值作为表名
* @return
*/
String getDynamicTableName();
}
然后在XML中写表名的时候使用:
<if test="@tk.mybatis.mapper.util.OGNL@isDynamicParameter(_parameter)
and dynamicTableName != null
and dynamicTableName != ''">
${dynamicTableName}
</if>
<if test="@tk.mybatis.mapper.util.OGNL@isNotDynamicParameter(_parameter)
or dynamicTableName == null
or dynamicTableName == ''">
defaultTableName
</if>
由于我需要判断_parameter是否继承了IDynamicTableName接口,简单的写法已经无法实现,所以使用了静态方法,这两个方法如下:
/**
* 判断参数是否支持动态表名
*
* @param parameter
* @return true支持,false不支持
*/
public static boolean isDynamicParameter(Object parameter) {
if (parameter != null && parameter instanceof IDynamicTableName) {
return true;
}
return false;
}
/**
* 判断参数是否b支持动态表名
*
* @param parameter
* @return true不支持,false支持
*/
public static boolean isNotDynamicParameter(Object parameter) {
return !isDynamicParameter(parameter);
}
根据<if>判断的结果来选择使用那个表名。另外注意XML判断中有一个dynamicTableName,这个参数是根据getDynamicTableName方法得到的,MyBatis使用属性对应的getter方法来获取值,不是根据field来获取值。