首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

MyBatis 逆向工程進階(二):修改源碼實現自定義模板生成 Mapper/XML/Entity

     編輯:Java 綜合教學

前言:為什麼要改 MyBatis Generator 源碼?

MyBatis Generator (MBG) 默認生成代碼風格往往不符合團隊規範:方法命名、參數類型、XML 結構、註解格式等。與其用插件機制勉強適配(功能受限、文檔稀缺),不如直接修改 MBG 核心源碼重新打包,獲得完全可控的生成能力。本文完整演示:源碼獲取 → Eclipse 導入 → 修改 Mapper 接口生成 → 修改 XML 生成 → Maven 打包 → 驗證成果。

一、環境準備與源碼導入

1.1 獲取源碼 (版本 1.3.2)

Maven 中央倉庫下載 mybatis-generator-core-1.3.2-sources.jar 或從 GitHub 下載完整項目源碼:
MBG 1.3.2 源碼

1.2 Eclipse 導入 Maven 項目

  1. File → Import → Maven → Existing Maven Projects
  2. 選中源碼根目錄 (含 pom.xml),Finish
  3. 等待依賴下載,項目結構如下:
    項目結構

二、目標生成代碼風格預覽

我們期望生成:

  • Mapper 接口:void update(Map<String, Object> dataMap); (而非默認實體對象參數)
  • XML:動態 <set> + <if> 非空判斷 + <where> 主鍵條件

目標 Mapper 接口
目標 XML
目標 Entity

三、核心修改點:Mapper 方法生成器

3.1 修改類:UpdateByPrimaryKeyWithoutBLOBsMethodGenerator

路徑:org.mybatis.generator.codegen.mybatis3.javamapper.elements


public class UpdateByPrimaryKeyWithoutBLOBsMethodGenerator extends AbstractJavaMapperMethodGenerator {
    @Override
    public void addInterfaceElements(Interface interfaze) {
        Set<FullyQualifiedJavaType> importedTypes = new TreeSet<>();
        // 1. 返回類型 void
        FullyQualifiedJavaType voidType = FullyQualifiedJavaType.getVoidInstance(); // 或 new FullyQualifiedJavaType("void")
        
        // 2. 參數類型 Map
        FullyQualifiedJavaType mapType = FullyQualifiedJavaType.getMyMapInstance(); // 需在 FullyQualifiedJavaType 添加靜態方法
        // 簡化寫法:new FullyQualifiedJavaType("java.util.Map")
        // 但需處理泛型,建議擴展 FullyQualifiedJavaType 支持參數化類型
        
        Method method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setReturnType(voidType);
        method.setName(introspectedTable.getUpdateByPrimaryKeyStatementId()); // "updateByPrimaryKey"
        
        // 關鍵:設置參數為 Map
        Parameter parameter = new Parameter(mapType, "dataMap");
        method.addParameter(parameter);
        
        context.getCommentGenerator().addGeneralMethodComment(method, introspectedTable);
        addMapperAnnotations(interfaze, method);
        
        if (context.getPlugins().clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated(method, interfaze, introspectedTable)) {
            interfaze.addImportedTypes(importedTypes);
            interfaze.addMethod(method);
        }
    }
}

關鍵擴展:在 FullyQualifiedJavaType 中添加 getMyMapInstance() 返回 Map<String, Object> 類型,或直接構造泛型類型 (需修改該類支持參數化)。

四、核心修改點:XML 元素生成器

4.1 修改類:UpdateByPrimaryKeyWithoutBLOBsElementGenerator

路徑:org.mybatis.generator.codegen.mybatis3.xmlmapper.elements


public class UpdateByPrimaryKeyWithoutBLOBsElementGenerator extends AbstractXmlElementGenerator {
    @Override
    public void addElements(XmlElement parentElement) {
        XmlElement answer = new XmlElement("update");
        answer.addAttribute(new Attribute("id", introspectedTable.getUpdateByPrimaryKeyStatementId()));
        answer.addAttribute(new Attribute("parameterType", "Map")); // 關鍵:參數類型 Map
        
        context.getCommentGenerator().addComment(answer);
        
        //  內容構建
        StringBuilder sb = new StringBuilder();
        sb.append("update ").append(introspectedTable.getFullyQualifiedTableNameAtRuntime());
        answer.addElement(new TextElement(sb.toString()));
        
        //  動態設置非空字段
        XmlElement setElement = new XmlElement("set");
        List<IntrospectedColumn> columns = introspectedTable.getAllColumns();
        Iterator<IntrospectedColumn> iter = columns.iterator();
        
        while (iter.hasNext()) {
            IntrospectedColumn col = iter.next();
            String colName = MyBatis3FormattingUtilities.getEscapedColumnName(col);
            
            XmlElement ifElement = new XmlElement("if");
            ifElement.addAttribute(new Attribute("test", colName + " != null and " + colName + " != ''"));
            
            sb.setLength(0);
            sb.append(colName).append(" = ").append(MyBatis3FormattingUtilities.getParameterClause(col));
            if (iter.hasNext()) sb.append(',');
            
            ifElement.addElement(new TextElement(sb.toString()));
            setElement.addElement(ifElement);
        }
        answer.addElement(setElement);
        
        //  主鍵條件
        XmlElement whereElement = new XmlElement("where");
        for (IntrospectedColumn pkCol : introspectedTable.getPrimaryKeyColumns()) {
            sb.setLength(0);
            sb.append(MyBatis3FormattingUtilities.getEscapedColumnName(pkCol))
              .append(" = ")
              .append(MyBatis3FormattingUtilities.getParameterClause(pkCol));
            whereElement.addElement(new TextElement(sb.toString()));
        }
        answer.addElement(whereElement);
        
        if (context.getPlugins().sqlMapUpdateByPrimaryKeyWithoutBLOBsElementGenerated(answer, introspectedTable)) {
            parentElement.addElement(answer);
        }
    }
}

五、驗證配置與運行

5.1 generatorConfig.xml


<generatorConfiguration>
    <classPathEntry location="mysql-connector-java-5.1.13-bin.jar" />
    <context id="infoGuardian" targetRuntime="MyBatis3">
        <commentGenerator>
            <property name="suppressAllComments" value="true"/>
            <property name="suppressDate" value="true"/>
        </commentGenerator>
        <jdbcConnection driverClass="com.mysql.jdbc.Driver" 
            connectionURL="jdbc:mysql://localhost:3306/login?characterEncoding=UTF-8"
            userId="root" password="root"/>
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>
        <javaModelGenerator targetPackage="pojo" targetProject="mybatis3">
            <property name="enableSubPackages" value="true"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <sqlMapGenerator targetPackage="mapper" targetProject="mybatis3">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>
        <javaClientGenerator type="XMLMAPPER" targetPackage="mapper" targetProject="mybatis3">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>
        <table tableName="login" domainObjectName="Login" 
            enableCountByExample="false" enableDeleteByExample="false"
            enableSelectByExample="false" enableUpdateByExample="false"/>
    </context>
</generatorConfiguration>

5.2 啟動類


public class StartUp {
    public static void main(String[] args) throws Exception {
        List<String> warnings = new ArrayList<>();
        File configFile = new File(StartUp.class.getResource("/generatorConfig.xml").toURI());
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(configFile);
        DefaultShellCallback callback = new DefaultShellCallback(true);
        MyBatisGenerator generator = new MyBatisGenerator(config, callback, warnings);
        generator.generate(null);
        System.out.println(warnings);
    }
}

六、Maven 打包發布:生成可直接使用的 JAR 包

6.1 關鍵 pom.xml 配置 (maven-jar-plugin + maven-assembly-plugin)


<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.4</version>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <mainClass>org.mybatis.generator.api.ShellRunner</mainClass>
            </manifest>
        </archive>
        <includes><include>**/org/**</include></includes> <!-- 只打包 org 包 -->
    </configuration>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <appendAssemblyId>false</appendAssemblyId>
        <descriptors><descriptor>src/main/assembly/src.xml</descriptor></descriptors>
    </configuration>
    <executions>
        <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals><goal>single</goal></goals>
        </execution>
    </executions>
</plugin>

6.2 組裝描述符 src/main/assembly/src.xml


<assembly>
    <id>bundle</id>
    <formats><format>zip</format></formats>
    <fileSets>
        <fileSet>
            <directory>src/main/resources</directory>
            <outputDirectory>/</outputDirectory>
            <includes><include>generatorConfig.xml</include></includes>
            <excludes><exclude>log4j.properties</exclude></excludes>
        </fileSet>
        <fileSet>
            <directory>src/main/scripts</directory>
            <outputDirectory>/</outputDirectory>
            <includes><include>run.bat</include></includes>
        </fileSet>
        <fileSet>
            <directory>${project.build.directory}</directory>
            <outputDirectory>/</outputDirectory>
            <includes><include>${project.artifactId}-${project.version}.jar</include></includes>
        </fileSet>
    </fileSets>
</assembly>

6.3 運行腳本 src/main/scripts/run.bat


java -jar mybatis-generator-core-1.3.2.jar -configfile generatorConfig.xml -overwrite
pause

6.4 打包命令


mvn clean package -DskipTests

產出:target/mybatis-generator-core-1.3.2.jar + generatorConfig.xml + run.bat 打包 zip,解壓即用。

七、驗證成果

生成文件結構
Mapper 接口
XML 文件

生成的 Mapper 接口包含 void update(Map<String, Object> dataMap);,XML 包含動態 <set>/<if>/<where>,完全符合預期。

八、擴展指南:新增自定義方法

參考:MBG 添加自定義方法完整教程
核心步驟:
1. 創建新的 XxxMethodGenerator 實現 JavaMapperMethodGenerator
2. 創建新的 XxxElementGenerator 實現 XmlElementGenerator
3. 在 context 配置中註冊 (或硬編碼在 JavaMapperGenerator/XmlMapperGenerator 中調用)
4. 重新打包

九、總結

通過直接修改 MBG 源碼,我們獲得了完全可控的代碼生成能力:方法簽名、參數類型、XML 結構、註解風格均符合團隊規範。雖然維護成本略高 (升級 MBG 版本需重新移植修改),但對於長期穩定的項目,一次投入、長期收益,極大提升開發效率與代碼質量一致性。建議將修改後的 JAR 發布至團隊私有 Maven 倉庫,統一依賴版本。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved