解析一個Mybatis Generator 插件

【原創(chuàng)文章,轉(zhuǎn)載請注明原文章地址,謝謝!】

Paste_Image.png

前面已經(jīng)了解了MyBatis Generator Plugin的相關(guān)知識,包括生命周期和主要的方法,我們就先來看兩個MBG提供的內(nèi)置的Plugin,然后我們自己來完成一個我們的Plugin。

org.mybatis.generator.plugins.ToStringPlugin##

前面我們已經(jīng)介紹了ToStringPlugin插件的作用,是為KeyClass,Record Class和BlobClass提供toString方法的。首先我們了解一下ToStringPlugin的用法。
在generatorConfig.xml中加上配置:

<plugin type="org.mybatis.generator.plugins.ToStringPlugin" />

在做配置的時候,注意一點就是這個插件是不需要配置參數(shù)的。運行MBG,查看生成的代碼
在KeyClass中生成的toString方法:

@Override
public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append(getClass().getSimpleName());
    sb.append(" [");
    sb.append("Hash = ").append(hashCode());
    sb.append("]");
    return sb.toString();
}

在recordClass中生成的toString方法:

@Override
public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append(getClass().getSimpleName());
    sb.append(" [");
    sb.append("Hash = ").append(hashCode());
    sb.append(", username=").append(username);
    sb.append(", password=").append(password);
    sb.append(", email=").append(email);
    sb.append(", age=").append(age);
    sb.append(", deptId=").append(deptId);
    sb.append(", admin=").append(admin);
    sb.append("]");
    return sb.toString();
}

在看代碼之前,首先我們要自己做一些分析,第一,我們要明確,我們看這個ToStringPlugin插件的目的是什么,很明顯,我們學(xué)習(xí)這個插件,就可以很明確的學(xué)習(xí)到幾個內(nèi)容:

  • 很明顯我們能學(xué)習(xí)到怎么在生成的Java代碼中添加方法;
  • 那么第二個問題,就是我們能夠?qū)W習(xí)到怎么去遍歷生成的類中的屬性和屬性的值;
  • 推廣開來,我們從這個ToStringPlugin中基本能夠了解MBG中對于Java類的一個DOM封裝的結(jié)構(gòu);

明確了我們的看代碼的目標,接下來還要自己去設(shè)想一下這個Plugin的實現(xiàn)方法,雖然我們對MBG的代碼結(jié)構(gòu)不是很了解,但是我們大概能夠通過MBG Plugin的生命周期想到,我們應(yīng)該會擴展生成keyClass和生成recordClass和生成blobClass的方法,在這個方法中,添加一個方法的DOM,并且在這個DOM里面遍歷當(dāng)前類的屬性,并拼裝對應(yīng)的StringBuilder;

OK,下面才正式進去ToStringPlugin的代碼看看:

public class ToStringPlugin extends PluginAdapter {

首先該類確實是繼承了插件的適配類

public boolean validate(List<String> warnings) {
    return true;
}

其次,實現(xiàn)了validate方法,validate方法是所有的plugin都必須實現(xiàn)的方法,一般在該方法中對參數(shù)進行驗證,因為ToStringPlugin沒有參數(shù),所以直接返回了true;

public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass,
        IntrospectedTable introspectedTable) {
    generateToString(introspectedTable, topLevelClass);
    return true;
}

實現(xiàn)了modelBaseRecordClassGenerated方法,該方法就是前面提到,在MBG生成record類的時候調(diào)用的插件的方法,在該方法中,傳入兩個參數(shù),

  • 一個是topLevelClass,該類的實例就是表示當(dāng)前正在生成的類的DOM結(jié)構(gòu),

  • 第二個introspectedTable是代表的runtime環(huán)境,包含了所有context中的配置,一般從這個類中去查詢生成對象的一些規(guī)則;
    可以看到,這個方法僅僅只是調(diào)用了generateToString方法,很好理解,因為要為三個類生成toString方法,所以抽取了一下,另外,這個方法總是返回了true,讓后面的實現(xiàn)了相同方法的插件能正常運行;

    public boolean modelPrimaryKeyClassGenerated(TopLevelClass topLevelClass,
          IntrospectedTable introspectedTable) {
      generateToString(introspectedTable, topLevelClass);
      return true;
    }
    

實現(xiàn)了modelBaseRecordClassGenerated方法,該方法就是前面提到,在MBG生成key Class類的時候調(diào)用的插件的方法,也只是調(diào)用了generateToString方法,

  public boolean modelRecordWithBLOBsClassGenerated(
        TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
    generateToString(introspectedTable, topLevelClass);
    return true;
  }

實現(xiàn)了modelBaseRecordClassGenerated方法,該方法就是前面提到,在MBG生成blob Class類的時候調(diào)用的插件的方法;
到此,三個方法的實現(xiàn)和我們之前預(yù)想的一致,接下來就是看具體怎么添加方法:

/**
 * 具體生成toString方法
 * @param introspectedTable
 * @param topLevelClass
 */
private void generateToString(IntrospectedTable introspectedTable,
        TopLevelClass topLevelClass) {
    //首先創(chuàng)建一個Method對象,注意,這個Method是org.mybatis.generator.api.dom.java.Method,
    //這個Method是MBG中對對象DOM的一個抽象;因為我們要添加方法,所以先創(chuàng)建一個;
    Method method = new Method();
    
    //設(shè)置這個方法的可見性為public,代碼已經(jīng)在一步一步構(gòu)建這個方法了
    method.setVisibility(JavaVisibility.PUBLIC);
    
    //設(shè)置方法的返回類型,這里注意一下的就是,returnType是一個FullyQualifiedJavaType;
    //這個FullyQualifiedJavaType是MGB中對Java中的類型的一個DOM封裝,這個類在整個MBG中大量使用;
    //FullyQualifiedJavaType提供了幾個靜態(tài)的方法,比如getStringInstance,就直接返回了一個對String類型的封裝;
    method.setReturnType(FullyQualifiedJavaType.getStringInstance());
    
    //設(shè)置方法的名稱,至此,方法簽名已經(jīng)裝配完成;
    method.setName("toString"); //$NON-NLS-1$
    
    //判斷當(dāng)前MBG運行的環(huán)境是否支持Java5(這里就可以看出來IntrospectedTable類的作用了,主要是查詢生成環(huán)境的作用)
    if (introspectedTable.isJava5Targeted()) {
        //如果支持Java5,就在方法上面生成一個@Override標簽;
        method.addAnnotation("@Override"); //$NON-NLS-1$
    }
    //訪問上下文對象(這個context對象是在PluginAdapter初始化完成后,通過setContext方法設(shè)置進去的,
    //通過getCommentGenerator方法得到注釋生成器,并調(diào)用addGeneralMethodComment為當(dāng)前生成的方法添加注釋;
    //因為我們沒有提供自己的注釋生成器,所以默認的注釋生成器只是說明方法是通過MBG生成的,對應(yīng)的是哪個表而已;
    //這句代碼其實非常有意義,通過這句代碼,我們基本就可能了解到MBG中對于方法注釋的生成方式了;
    context.getCommentGenerator().addGeneralMethodComment(method,
            introspectedTable);

    //OK,調(diào)用addBodyLine開始為方法添加代碼了
    //可以看到,確實,只是簡單的把要生成的代碼通過String拼裝到了method的body中而已;
    //想到了什么?確實,我想到了Servelt的輸出方法。MBG默認的方法體具體的實現(xiàn),就是像Servlet那樣通過String輸出的;
    //所以,這才會為我們后面準備用Velocity來重寫MBG提供了依據(jù),我們只是給MBG添加一個MVC的概念;
    method.addBodyLine("StringBuilder sb = new StringBuilder();"); //$NON-NLS-1$
    method.addBodyLine("sb.append(getClass().getSimpleName());"); //$NON-NLS-1$
    method.addBodyLine("sb.append(\" [\");"); //$NON-NLS-1$
    method.addBodyLine("sb.append(\"Hash = \").append(hashCode());"); //$NON-NLS-1$
    
    //接下來要準備拼裝類的字段了;
    StringBuilder sb = new StringBuilder();
    
    //通過topLevelClass得到當(dāng)前類的所有字段,注意,這里的Field是org.mybatis.generator.api.dom.java.Field
    //這個Field是MBG對字段的一個DOM封裝
    for (Field field : topLevelClass.getFields()) {
        //得到字段的名稱;
        String property = field.getName();
        //重置StringBuilder;
        sb.setLength(0);
        
        //添加字段的輸出代碼;
        sb.append("sb.append(\"").append(", ").append(property) //$NON-NLS-1$ //$NON-NLS-2$
                .append("=\")").append(".append(").append(property) //$NON-NLS-1$ //$NON-NLS-2$
                .append(");"); //$NON-NLS-1$
        
        //把這個字段的toString輸出到代碼中;所以才看到我們最后生成的代碼結(jié)果中,每一個字段在toString方法中各占一行;
        method.addBodyLine(sb.toString());
    }

    method.addBodyLine("sb.append(\"]\");"); //$NON-NLS-1$
    method.addBodyLine("return sb.toString();"); //$NON-NLS-1$
    
    //把拼裝好的方法DOM添加到topLevelClass中,完成方法添加;
    topLevelClass.addMethod(method);
}

我已經(jīng)把該方法涉及到的有價值的內(nèi)容用注釋詳細標注出來了,基本上,通過這個方法,我們已經(jīng)能夠完成絕大情況的為Java類添加方法的情況了;

接下來,我們再分析一個插件org.mybatis.generator.plugins.MapperConfigPlugin,來看看怎么添加額外的XML和處理XML的生成。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 【原創(chuàng)文章,轉(zhuǎn)載請注明原文章地址,謝謝!】 在本文中,我們再來看一個MyBatis Generator插件:org...
    叩丁狼教育閱讀 3,567評論 4 3
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,941評論 25 709
  • WebSocket-Swift Starscream的使用 WebSocket 是 HTML5 一種新的協(xié)議。它實...
    香橙柚子閱讀 24,730評論 8 183
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,643評論 18 399
  • “慢養(yǎng)項目,慢養(yǎng)心,千錘百煉得真金”中國式眾籌的精髓,同時又驗證了我以前一位銀行領(lǐng)導(dǎo)教導(dǎo)的一句話“做事業(yè)付出最大的...
    夏天的眾籌閱讀 239評論 0 0

友情鏈接更多精彩內(nèi)容