Mybatis-Generator生成Mapper文件中的問題解答

寫在前面

《Docker+SpringBoot+Mybatis+thymeleaf的Java博客系統開源啦》

由於開源了項目的緣故,很多使用了My Blog項目的朋友遇到問題也都會聯繫我去解決,有的是把問題留在項目的issue裏提出,有的是在我的私人博客裏留言,還有的則是直接添加我的qq來找我講自己遇到的問題,有些問題比較簡單直接就解決了,有些問題的解決記錄也留在issue記錄裏,有些則是網上有相關教程,而剩下問題的解決方案,如果時間允許我都會單獨的做一篇博客來解答。

問題描述

當時的聊天記錄:
question

截圖中提到的代碼(節選):

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()方法,然後執行了邏輯判斷,當然,這都是個人感覺,沒什麼依據,隱隱約約覺得應該是這麼個道理。但是呢,畢竟這位朋友是來問問題的,我不能就簡簡單單的回覆這麼一句話,而且是連我自己都不確定的答案。

jingxi

疑惑的問題有:

  • 並不知道mybatis是不是這個執行流程;
  • 即使是如上的流程,那麼爲什麼根本沒有的屬性會被mybatis正常解析;
  • 爲什麼mybatis會去執行isValid()方法而不去執行其他的方法。

解決過程

帶着以上的問題和心中的不確定,我唯一能做的就是去查看這部分過程的源碼了,最終也如願得到了答案,通過IDEA的debug功能得到了代碼的執行過程,可以自行執行查看一下整個過程:

  • IfSqlNode類中,獲取了if test標籤中表達式的值:criteria.valid;

IfSqlNode

  • 接着是在ObjectPropertyAccessor類中解析到了需要操作的屬性值Criteria類中的valid;

ObjectPropertyAccessor

  • 然後是在OgnlRuntime類中得到了表達式對應執行的MethodisValid()方法。

OgnlRuntime

接下來就是執行方法並獲取返回值了,就不再截圖了。

上面的前兩個問題就有了答案:

  • <if test="criteria.valid">到執行isValid()方法的執行流程找到了,雖然過程較多但是幾個重要的節點就是以上三點,獲取Mapper表達式中的類名和屬性值,然後獲取需要執行的方法,最終實現整個功能。
  • mybatis並沒有去關注是否存在這個屬性,而是根據屬性去找到對應的方法並執行。

至於第三個問題,我也做了一下擴展,如果其他帶有valid字符串的方法會不會也被執行到,結果是肯定回答,如圖:

isValid()改爲getValid()

getValid

OgnlRuntime類中得到了對應執行的MethodgetValid()方法

OgnlRuntime-get

當兩個方法都存在時,會執行isValid()方法,因爲if test需要的是一個boolean返回值,當只存在getValid()方法時,則會執行getValid()

結語

首發於我的個人博客

如果有問題或者有一些好的創意,歡迎給我留言,也感謝向我指出項目中存在問題的朋友,關於這篇文章,特別感謝一下@libinghui

代碼和這次的問題都是My Blog項目中的,如果你想繼續瞭解該項目可以查看整個系列文章Java開源博客My-Blog(SpringBoot+Docker)系列文章,也可以到我的GitHub倉庫或者開源中國代碼倉庫中查看源碼及詳細的部署過程和使用文檔。

發佈了81 篇原創文章 · 獲贊 62 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章