Mybatis-Generator生成Mapper檔案中的問題解答
寫在前面
由於開源了專案的緣故,很多使用了My Blog專案的朋友遇到問題也都會聯絡我去解決,有的是把問題留在專案的issue裡提出,有的是在我的私人部落格裡留言,還有的則是直接新增我的qq來找我講自己遇到的問題,有些問題比較簡單直接就解決了,有些問題的解決記錄也留在issue記錄裡,有些則是網上有相關教程,而剩下問題的解決方案,如果時間允許我都會單獨的做一篇部落格來解答。
問題描述
當時的聊天記錄:
截圖中提到的程式碼(節選):
ContentVoMapper.xml:
<sql id="Example_Where_Clause">
<where >
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue" >
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
CommentVoExample:
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
...
問題整理:在GeneratedCriteria類中並沒有valid這一屬性,僅僅只有一個isValid()
方法,但是在Mapper檔案中mybatis的<if test>
語法中,卻有criteria.valid
的表示式,而且程式可以正常執行,這是怎麼回事呢?
思路整理
首先,我剛看到這個問題的時候也是有點懵,因為這個程式碼其實不是我寫的,Mapper檔案是我通過Mybatis-Generator自動生成的,所以這段程式碼我也是有點陌生的,哈哈哈哈。
但是看了一遍程式碼之後,我覺得應該是mybatis根據valid屬性自動找到了isValid()方法,然後執行了邏輯判斷,當然,這都是個人感覺,沒什麼依據,隱隱約約覺得應該是這麼個道理。但是呢,畢竟這位朋友是來問問題的,我不能就簡簡單單的回覆這麼一句話,而且是連我自己都不確定的答案。
疑惑的問題有:
- 並不知道mybatis是不是這個執行流程;
- 即使是如上的流程,那麼為什麼根本沒有的屬性會被mybatis正常解析;
- 為什麼mybatis會去執行
isValid()
方法而不去執行其他的方法。
解決過程
帶著以上的問題和心中的不確定,我唯一能做的就是去檢視這部分過程的原始碼了,最終也如願得到了答案,通過IDEA的debug功能得到了程式碼的執行過程,可以自行執行檢視一下整個過程:
- 在
IfSqlNode
類中,獲取了if test
標籤中表達式的值:criteria.valid
;
- 接著是在
ObjectPropertyAccessor
類中解析到了需要操作的屬性值Criteria
類中的valid
;
- 然後是在
OgnlRuntime
類中得到了表示式對應執行的MethodisValid()
方法。
接下來就是執行方法並獲取返回值了,就不再截圖了。
上面的前兩個問題就有了答案:
- 由
<if test="criteria.valid">
到執行isValid()
方法的執行流程找到了,雖然過程較多但是幾個重要的節點就是以上三點,獲取Mapper表示式中的類名和屬性值,然後獲取需要執行的方法,最終實現整個功能。 - mybatis並沒有去關注是否存在這個屬性,而是根據屬性去找到對應的方法並執行。
至於第三個問題,我也做了一下擴充套件,如果其他帶有valid字串的方法會不會也被執行到,結果是肯定回答,如圖:
將isValid()
改為getValid()
OgnlRuntime
類中得到了對應執行的MethodgetValid()
方法
當兩個方法都存在時,會執行isValid()
方法,因為if test
需要的是一個boolean返回值,當只存在getValid()
方法時,則會執行getValid()
。
結語
首發於我的個人部落格。
如果有問題或者有一些好的創意,歡迎給我留言,也感謝向我指出專案中存在問題的朋友,關於這篇文章,特別感謝一下@libinghui
。