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

前面已經(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的生成。