MyBatis Generator code automatic generator

1. What is reverse engineering?

The reverse engineering of Mybatis is to use the code generator to generate the code and mapping files we need. When we write Mybatis programs, we basically focus on the pojo class, Mapper interface, Mapper.xml file and other files. If there are many tables in the database during actual development, then we need to manually write the pojo class, Mapper interface, and Mapper. It’s hard to rule out mistakes. Therefore, in actual development, we generally use reverse engineering to automatically generate the required files. This is also a very common method in enterprises.

注意:在使用逆向工程生成代码文件的时候,最好额外创建一个项目,不要在原来的项目中使用,因为如果你在原项目中有相同名字的文件,那么就会被新生成的文件所覆盖,导致之前写的代码没了,有一定的风险。所以实际开发中,我们一般新建一个项目,然后将生成的文件复制到自己的所需的工程中。

Insert image description here

1. Introduction to MGB

Official document: http://mybatis.org/generator/Download
address of reverse engineering package: https://github.com/mybatis/generator/releases/tag/mybatis-generator-1.3.2

(1)MyBatis Generator:即MBG

(2) MBG is a code generator specially customized for MyBatis framework users

(3) MBG can quickly generate corresponding mapping files, interfaces, and bean classes based on the table

(4) Only single-table CRUD can be generated, but the definitions of complex SQL such as table connections and stored procedures require us to write them manually.

2. Write the MBG configuration file mbg.xml (several important configurations)

The corresponding configuration file can be found in the official documentation

Insert image description here

Slide down

Insert image description hereInsert image description here
The above configuration file is the official sample configuration file. Later, the relevant parts will be changed to match the content of your own module.

3. Run the program (code generator)

Insert image description here

2. Reverse engineering to generate code

①. First create a maven project

1. Overall project directory:

Insert image description here

2. Import maven dependencies:


<!-- Mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.6</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.21</version>
</dependency>
<!-- 日志处理 -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
<!-- 逆向工程 -->
<dependency>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-core</artifactId>
    <version>1.4.0</version>
</dependency>

②. Create log file log4j.properties


# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE
 
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

③.Create generatorConfig.xml configuration file


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
 
<generatorConfiguration>

    <!--targetRuntime="MyBatis3Simple"表示生成简易版本,这里创建原始版本,参数为MyBatis3-->
    <context id="testTables" targetRuntime="MyBatis3">
    
        <commentGenerator>
            <!-- 是否去除自动生成的注释。true:是;false:否 -->
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
        
        <!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8"
                        userId="root"
                        password="root">
        </jdbcConnection>
 
        <!-- 默认false,把JDBC DECIMAL和NUMERIC类型解析为Integer,为true时把JDBC DECIMAL 和
            NUMERIC 类型解析为java.math.BigDecimal -->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>
 
        <!-- targetProject:POJO类生成的位置 -->
        <javaModelGenerator targetPackage="com.example.pojo"
                            targetProject="./src/main/java">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
            <!-- 从数据库返回的值被清理前后的空格 -->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        
        <!-- targetProject:mapper映射文件生成的位置 -->
        <sqlMapGenerator targetPackage="com.example.mapper"
                         targetProject="./src/main/resources">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>
        
        <!-- targetPackage:mapper接口生成的位置 -->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.example.mapper"
                             targetProject="./src/main/java">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>

        
<!--生成全部表tableName设为%-->
<!--        可选:-->
<!--        1,schema:数据库的schema;-->
<!--        2,catalog:数据库的catalog;-->
<!--        3,alias:为数据表设置的别名,如果设置了alias,那么生成的所有的SELECT SQL语句中,列名会变成:alias_actualColumnName-->
<!--        4,domainObjectName:生成的domain类的名字,如果不设置,直接使用表名作为domain类的名字;可以设置为somepck.domainName,那么会自动把domainName类再放到somepck包里面;-->
<!--        5,enableInsert(默认true):指定是否生成insert语句;-->
<!--        6,enableSelectByPrimaryKey(默认true):指定是否生成按照主键查询对象的语句(就是getById或get);-->
<!--        7,enableSelectByExample(默认true):MyBatis3Simple为false,指定是否生成动态查询语句;-->
<!--        8,enableUpdateByPrimaryKey(默认true):指定是否生成按照主键修改对象的语句(即update);-->
<!--        9,enableDeleteByPrimaryKey(默认true):指定是否生成按照主键删除对象的语句(即delete);-->
<!--        10,enableDeleteByExample(默认true):MyBatis3Simple为false,指定是否生成动态删除语句;-->
<!--        11,enableCountByExample(默认true):MyBatis3Simple为false,指定是否生成动态查询总条数语句(用于分页的总条数查询);-->
<!--        12,enableUpdateByExample(默认true):MyBatis3Simple为false,指定是否生成动态修改语句(只修改对象中不为空的属性);-->
<!--        13,modelType:参考context元素的defaultModelType,相当于覆盖;-->
<!--        14,delimitIdentifiers:参考tableName的解释,注意,默认的delimitIdentifiers是双引号,如果类似MYSQL这样的数据库,使用的是`(反引号,那么还需要设置context的beginningDelimiter和endingDelimiter属性)-->
<!--        15,delimitAllColumns:设置是否所有生成的SQL中的列名都使用标识符引起来。默认为false,delimitIdentifiers参考context的属性-->


         <!-- 指定生成哪些数据库表,要和数据库中对应,不能写错了,这里以t_user表为例,可以写多个;domainObjectName是要生成的实体类名称-->
        <!-- 指定数据库表 [SQLServer] schema=""必须为空 -->
        <table schema="mybatis" tableName="t_user"/>
        <!-- 有些表的字段需要指定java类型  -->
        <!-- <table schema="" tableName="">
            <columnOverride column="" javaType="" />
        </table> -->
        
    </context>
</generatorConfiguration>

注意:serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8中的 & 要改成转义字符 &amp; 这里传上来页面自动给转成了 &。

Insert image description here
Also, different databases cannot contain the same table. For example, database A has a t_user table, and database B also has a t_user table. Then the code will not know which one to generate, and the one I happened to generate is the one we don't need. ah? Didn't you say that the database was specified above? How could you read the tables in other databases? Sorry, I tried more than ten times. Finally, I deleted the tables with the same name in other databases and succeeded. It's better if you don't have this situation.

④. Create the reverse engineering core generation code GeneratorSql.java


package com.thr.generator;
 
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
 
import java.io.File;
import java.util.ArrayList;
import java.util.List;
 
/**
 * 逆向工程核心生成代码
 */
public class GeneratorSql {
    
    
    public void generator() throws Exception {
    
    
        List<String> warnings = new ArrayList<>();
        boolean overwrite = true;
        // 指定逆向工程配置文件
        String file = GeneratorSql.class.getResource("/generatorConfig.xml").getFile();
        File configFile = new File(file);
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(configFile);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        myBatisGenerator.generate(null);
    }
    // 执行main方法以生成代码
    public static void main(String[] args) {
    
    
        try {
    
    
            GeneratorSql generatorSql = new GeneratorSql();
            generatorSql.generator();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
 
}

⑤. Run the reverse engineering core to generate code

Run the above program. If the console prints the following log, it means the code generation is successful.

Insert image description here
Then when we look at the project, we will find that the following files have been generated:

Insert image description here

3. Examples of reverse engineering

First we copy the files generated above into the target project. Before using reverse engineering as an example, let’s first introduce what the generated files include:

(1) Introduction to the method of generating the TUserMapper interface:

Insert image description hereInsert image description here

  1. long countByExample(TUserExample example): Count by condition
  2. int deleteByExample(TUserExample example): Delete conditionally
  3. int deleteByPrimaryKey(Integer id): delete by primary key
  4. int insert(TUser record): Insert data (return value is ID)
  5. int insertSelective(TUser record): insert data, only insert fields whose values ​​are not null, internal dynamic sql judgment
  6. List selectByExample(TUserExample example): Query by condition, passing in null means querying all
  7. TUser selectByPrimaryKey(Integer id): Query by primary key
  8. int updateByExampleSelective(@Param(“record”) TUser record, @Param(“example”) TUserExample example): Conditionally update fields whose values ​​are not null
  9. int updateByExample(@Param(“record”) TUser record, @Param(“example”) TUserExample example): Update by condition
  10. int updateByPrimaryKeySelective(TUser record): Update fields whose values ​​are not null by primary key
  11. int updateByPrimaryKey(TUser record): update by primary key

Test methods without conditions:


//Mybatis的测试
public class MybatisTest {
    
    
    //定义 SqlSession
    private SqlSession sqlSession = null;
    //定义 TUserMapper对象
    private TUserMapper mapper = null;
 
    @Before//在测试方法执行之前执行
    public void getSqlSession(){
    
    
        //1、加载 mybatis 全局配置文件
        InputStream is = MybatisTest.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
        //2、创建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        //3、根据 sqlSessionFactory 产生session
        sqlSession = sqlSessionFactory.openSession();
        //4、创建Mapper接口的的代理对象,getMapper方法底层会通过动态代理生成TUserMapper的代理实现类
        mapper = sqlSession.getMapper(TUserMapper.class);
    }
 
    @After//在测试方法执行完成之后执行
    public void destroy() throws IOException {
    
    
        sqlSession.commit();
        sqlSession.close();
    }
    //查询所有用户信息
    @Test
    public void selectAllUser(){
    
    
        List<TUser> tUsers = mapper.selectByExample(null);//传入null表示查询所有
        for (TUser tUser : tUsers) {
    
    
            System.out.println(tUser);
        }
    }
    //根据用户id查询用户
    @Test
    public void selectByUserId(){
    
    
        TUser tUser = mapper.selectByPrimaryKey(1);
        System.out.println(tUser);
    }
    //添加用户信息
    @Test
    public void insertUser(){
    
    
        TUser tUser = new TUser();
        tUser.setUsername("凡尔赛");
        tUser.setAge(18);
        tUser.setBirthday(new Date());
        tUser.setSex("0");
        tUser.setAddress("漂亮国");
        int i = mapper.insertSelective(tUser);
        System.out.println(i>0?"添加成功":"添加失败");
    }
    //更新用户信息
    @Test
    public void updateUser(){
    
    
        TUser tUser = new TUser();
        tUser.setId(8);//这里要设置id才能修改成功,否则不知道修改哪一条数据
        tUser.setUsername("川建国");
        tUser.setAge(50);
        tUser.setBirthday(new Date());
        tUser.setSex("1");
        tUser.setAddress("漂亮国");
        int i = mapper.updateByPrimaryKeySelective(tUser);
        System.out.println(i>0?"修改成功":"修改失败");
    }
    //删除用户信息
    @Test
    public void deleteUser(){
    
    
        int i = mapper.deleteByPrimaryKey(8);
        System.out.println(i>0?"删除成功":"删除失败");
    }
}

(2) Introduction to TUserExample condition extension class:

The above test method is an operation without conditions, so let’s learn how to perform add, delete, modify and check operations according to conditions. We have generated this class TUserExample in reverse engineering. This class is a conditional extension class, which defines a series of Methods are used to make conditions, such as: sorting, deduplication, greater than, less than, equal to, fuzzy query, data between certain, etc.

We can see in the TUserExample class that an internal class GeneratedCriteria is defined. This internal class defines a series of conditional methods. These conditions will eventually be spliced ​​into SQL, but we generally do not use it and use its subclass Criteria. To operate, Criteria inherits the inner class GeneratedCriteria.

Insert image description here
Simple example:


//Mybatis的测试
public class MybatisTest1 {
    
    
    //定义 SqlSession
    private SqlSession sqlSession = null;
    //定义 UserMapper对象
    private TUserMapper mapper = null;
 
    @Before//在测试方法执行之前执行
    public void getSqlSession(){
    
    
        //1、加载 mybatis 全局配置文件
        InputStream is = MybatisTest1.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
        //2、创建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        //3、根据 sqlSessionFactory 产生session
        sqlSession = sqlSessionFactory.openSession();
        //4、创建Mapper接口的的代理对象,getMapper方法底层会通过动态代理生成UserMapper的代理实现类
        mapper = sqlSession.getMapper(TUserMapper.class);
    }
 
    @After//在测试方法执行完成之后执行
    public void destroy() throws IOException {
    
    
        sqlSession.commit();
        sqlSession.close();
    }
    //模糊查询用户信息
    @Test
    public void selectUserLike(){
    
    
        TUserExample example = new TUserExample();
        TUserExample.Criteria criteria = example.createCriteria();
        //模糊条件
        criteria.andUsernameLike("%三%");
        /*sql语句相当于:select id, username, age, birthday, sex, address 
                        from t_user WHERE ( username like ? )*/
        List<TUser> tUsers = mapper.selectByExample(example);
        for (TUser tUser : tUsers) {
    
    
            System.out.println(tUser);
        }
    }
    //查询年龄在18-30岁之间的用户信息
    @Test
    public void selectUserBetween(){
    
    
        TUserExample example = new TUserExample();
        TUserExample.Criteria criteria = example.createCriteria();
        //Between条件
        criteria.andAgeBetween(18,30);
        example.or(criteria);
        example.setDistinct(true);
        /*sql语句相当于:select distinct id, username, age, birthday, sex, address 
                        from t_user WHERE ( age between ? and ? ) or( age between ? and ? )*/
        List<TUser> tUsers = mapper.selectByExample(example);
        for (TUser tUser : tUsers) {
    
    
            System.out.println(tUser);
        }
    }
    //查询用户名A或B
    @Test
    public void selectUserOr(){
    
    
        TUserExample example = new TUserExample();
        TUserExample.Criteria criteria1 = example.createCriteria();
        criteria1.andUsernameEqualTo("黄飞鸿");
 
        TUserExample.Criteria criteria2 = example.createCriteria();
        criteria2.andUsernameEqualTo("马保国");
        //将criteria2条件拼接在 or 关键字字后面
        example.or(criteria2);
        /*sql语句相当于:select id, username, age, birthday, sex, address
            from t_user WHERE ( username = ? ) or( username = ? )*/
        List<TUser> tUsers = mapper.selectByExample(example);
        for (TUser tUser : tUsers) {
    
    
            System.out.println(tUser);
        }
    }
    //根据用户名删除用户
    @Test
    public void deleteUserExample(){
    
    
        TUserExample example = new TUserExample();
        TUserExample.Criteria criteria = example.createCriteria();
        criteria.andUsernameEqualTo("凡尔赛");
        //sql语句相当于:delete from t_user WHERE ( username = ? )
        int i = mapper.deleteByExample(example);
        System.out.println(i>0?"删除成功":"删除失败");
    }
}

At this point, the reverse engineering of Mybatis has been fully introduced. It is not particularly difficult. As long as you implement it step by step and understand it, it is very simple. The XxxExample class may be more complicated, but if you give a few more examples, The example is not difficult either.

4. Reverse engineering code expansion

Question: Why doesn't MyBatis Generator generate the service layer and controller layer?
Answer: mybatis is a persistence layer framework.

①. Custom annotation generator

1. Create a custom comment generator CommentGenerator.java


import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.CompilationUnit;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.internal.DefaultCommentGenerator;
import org.mybatis.generator.internal.util.StringUtility;
 
import java.util.Properties;
 
/**
 * 自定义注释生成器
 * Created by macro on 2018/4/26.
 */
public class CommentGenerator extends DefaultCommentGenerator {
    
    
    private boolean addRemarkComments = false;
    private static final String EXAMPLE_SUFFIX="Example";
    private static final String API_MODEL_PROPERTY_FULL_CLASS_NAME="io.swagger.annotations.ApiModelProperty";
 
    /**
     * 设置用户配置的参数
     */
    @Override
    public void addConfigurationProperties(Properties properties) {
    
    
        super.addConfigurationProperties(properties);
        this.addRemarkComments = StringUtility.isTrue(properties.getProperty("addRemarkComments"));
    }
 
    /**
     * 给字段添加注释
     */
    @Override
    public void addFieldComment(Field field, IntrospectedTable introspectedTable,
                                IntrospectedColumn introspectedColumn) {
    
    
        String remarks = introspectedColumn.getRemarks();
        //根据参数和备注信息判断是否添加备注信息
        if(addRemarkComments&&StringUtility.stringHasValue(remarks)){
    
    
//            addFieldJavaDoc(field, remarks);
            //数据库中特殊字符需要转义
            if(remarks.contains("\"")){
    
    
                remarks = remarks.replace("\"","'");
            }
            //给model的字段添加swagger注解
            field.addJavaDocLine("@ApiModelProperty(value = \""+remarks+"\")");
        }
    }
 
    /**
     * 给model的字段添加注释
     */
    private void addFieldJavaDoc(Field field, String remarks) {
    
    
        //文档注释开始
        field.addJavaDocLine("/**");
        //获取数据库字段的备注信息
        String[] remarkLines = remarks.split(System.getProperty("line.separator"));
        for(String remarkLine:remarkLines){
    
    
            field.addJavaDocLine(" * "+remarkLine);
        }
        addJavadocTag(field, false);
        field.addJavaDocLine(" */");
    }
 
    @Override
    public void addJavaFileComment(CompilationUnit compilationUnit) {
    
    
        super.addJavaFileComment(compilationUnit);
        //只在model中添加swagger注解类的导入
        if(!compilationUnit.isJavaInterface()&&!compilationUnit.getType().getFullyQualifiedName().contains(EXAMPLE_SUFFIX)){
    
    
            compilationUnit.addImportedType(new FullyQualifiedJavaType(API_MODEL_PROPERTY_FULL_CLASS_NAME));
        }
    }
}

2. Add generatorConfig.xml configuration

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
 
<generatorConfiguration>
    <properties resource="generator.properties"/>
    <context id="MySqlContext" targetRuntime="MyBatis3" defaultModelType="flat">
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>
        <property name="javaFileEncoding" value="UTF-8"/>
        <!-- 为模型生成序列化方法-->
        <plugin type="org.mybatis.generator.plugins.SerializablePlugin"/>
        <!-- 为生成的Java模型创建一个toString方法 -->
        <plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>
        <!--生成mapper.xml时覆盖原文件-->
        <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin" />
        
        <commentGenerator type="com.jzxs.etp.mbg.CommentGenerator">
            <!-- 是否去除自动生成的注释 true:是 : false:否 -->
            <property name="suppressAllComments" value="true"/>
            <property name="suppressDate" value="true"/>
            <property name="addRemarkComments" value="true"/>
        </commentGenerator>
 
        <jdbcConnection driverClass="${jdbc.driverClass}"
                        connectionURL="${jdbc.connectionURL}"
                        userId="${jdbc.userId}"
                        password="${jdbc.password}">
            <!--解决mysql驱动升级到8.0后不生成指定数据库代码的问题-->
            <property name="nullCatalogMeansCurrent" value="true" />
        </jdbcConnection>
 
        <!--指定生成model的路径-->
        <javaModelGenerator targetPackage="com.jzxs.etp.mbg.model"
                            targetProject="./src/main/java"/>
        <!--指定生成mapper.xml的路径-->
        <sqlMapGenerator targetPackage="com.jzxs.etp.mbg.mapper"
                         targetProject="./src/main/resources"/>
        <!--指定生成mapper接口的的路径-->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.jzxs.etp.mbg.mapper"
                             targetProject="./src/main/java"/>
       
        <!--生成全部表tableName设为%-->
        <table tableName="history_picture"></table>
        
    </context>
</generatorConfiguration>

②. Customized Controller and Service plug-ins

1. Customize the templates for generating Controller and Service.


package com.jzxs.etp.mbg;
 
import org.mybatis.generator.api.GeneratedJavaFile;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
 
import java.util.ArrayList;
import java.util.List;
 
import static org.mybatis.generator.internal.util.StringUtility.stringHasValue;
import static org.mybatis.generator.internal.util.messages.Messages.getString;
 
public class ServiceAndControllerGeneratorPlugin extends PluginAdapter  {
    
    
 
    // 项目目录,一般为 src/main/java
    private String targetProject;
 
    // service包名,如:com.thinkj2ee.cms.service.service
    private String servicePackage;
 
    // service实现类包名,如:com.thinkj2ee.cms.service.service.impl
    private String serviceImplPackage;
    // Controlle类包名,如:com.thinkj2ee.cms.service.controller
    private String controllerPackage;
    // service接口名前缀
    private String servicePreffix;
 
    // service接口名后缀
    private String serviceSuffix;
 
    // service接口的父接口
    private String superServiceInterface;
 
    // service实现类的父类
    private String superServiceImpl;
    // controller类的父类
    private String superController;
 
    // dao接口基类
    private String superDaoInterface;
 
    // Example类的包名
    private String examplePacket;
 
    private String recordType;
 
    private String modelName;
 
    private FullyQualifiedJavaType model;
 
    private String serviceName;
    private String serviceImplName;
    private String controllerName;
 
    @Override
    public boolean validate(List<String> warnings) {
    
    
        boolean valid = true;
 
       /* if (!stringHasValue(properties
                .getProperty("targetProject"))) { //$NON-NLS-1$
            warnings.add(getString("ValidationError.18", //$NON-NLS-1$
                    "MapperConfigPlugin", //$NON-NLS-1$
                    "targetProject")); //$NON-NLS-1$
            valid = false;
        }
        if (!stringHasValue(properties.getProperty("servicePackage"))) { //$NON-NLS-1$
            warnings.add(getString("ValidationError.18", //$NON-NLS-1$
                    "MapperConfigPlugin", //$NON-NLS-1$
                    "servicePackage")); //$NON-NLS-1$
            valid = false;
        }
        if (!stringHasValue(properties.getProperty("serviceImplPackage"))) { //$NON-NLS-1$
            warnings.add(getString("ValidationError.18", //$NON-NLS-1$
                    "MapperConfigPlugin", //$NON-NLS-1$
                    "serviceImplPackage")); //$NON-NLS-1$
            valid = false;
        }
*/
        targetProject = properties.getProperty("targetProject");
        servicePackage = properties.getProperty("servicePackage");
        serviceImplPackage = properties.getProperty("serviceImplPackage");
        servicePreffix = properties.getProperty("servicePreffix");
        servicePreffix = stringHasValue(servicePreffix) ? servicePreffix : "";
        serviceSuffix = properties.getProperty("serviceSuffix");
        serviceSuffix = stringHasValue(serviceSuffix) ? serviceSuffix : "";
        superServiceInterface = properties.getProperty("superServiceInterface");
        superServiceImpl = properties.getProperty("superServiceImpl");
        superDaoInterface = properties.getProperty("superDaoInterface");
        controllerPackage = properties.getProperty("controllerPackage");
        superController = properties.getProperty("superController");
 
        return valid;
    }
 
    @Override
    public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {
    
    
        recordType = introspectedTable.getBaseRecordType();
        modelName = recordType.substring(recordType.lastIndexOf(".") + 1);
        model = new FullyQualifiedJavaType(recordType);
        serviceName = servicePackage + "." + servicePreffix + modelName + serviceSuffix;
        serviceImplName = serviceImplPackage + "." + modelName + serviceSuffix+"Impl";
        examplePacket=recordType.substring(0,recordType.lastIndexOf("."));
        controllerName=controllerPackage.concat(".").concat(modelName).concat("Controller");
        List<GeneratedJavaFile> answer = new ArrayList<>();
        GeneratedJavaFile gjf = generateServiceInterface(introspectedTable);
        GeneratedJavaFile gjf2 = generateServiceImpl(introspectedTable);
        GeneratedJavaFile gjf3 = generateController(introspectedTable);
        answer.add(gjf);
        answer.add(gjf2);
        answer.add(gjf3);
        return answer;
    }
 
    // 生成service接口
    private GeneratedJavaFile generateServiceInterface(IntrospectedTable introspectedTable) {
    
    
        FullyQualifiedJavaType service = new FullyQualifiedJavaType(serviceName);
        Interface serviceInterface = new Interface(service);
        serviceInterface.setVisibility(JavaVisibility.PUBLIC);
        // 添加父接口
        if(stringHasValue(superServiceInterface)) {
    
    
            String superServiceInterfaceName = superServiceInterface.substring(superServiceInterface.lastIndexOf(".") + 1);
            serviceInterface.addImportedType(new FullyQualifiedJavaType(superServiceInterface));
            serviceInterface.addImportedType(new FullyQualifiedJavaType(recordType));
            serviceInterface.addSuperInterface(new FullyQualifiedJavaType(superServiceInterfaceName + "<" + modelName + ">"));
        }
        GeneratedJavaFile gjf = new GeneratedJavaFile(serviceInterface, targetProject, context.getJavaFormatter());
        return gjf;
    }
 
    // 生成serviceImpl实现类
    private GeneratedJavaFile generateServiceImpl(IntrospectedTable introspectedTable) {
    
    
        FullyQualifiedJavaType service = new FullyQualifiedJavaType(serviceName);
        FullyQualifiedJavaType serviceImpl = new FullyQualifiedJavaType(serviceImplName);
        TopLevelClass clazz = new TopLevelClass(serviceImpl);
        //描述类的作用域修饰符
        clazz.setVisibility(JavaVisibility.PUBLIC);
        //描述类 引入的类
        clazz.addImportedType(service);
        //描述类 的实现接口类
        clazz.addSuperInterface(service);
        if(stringHasValue(superServiceImpl)) {
    
    
            String superServiceImplName = superServiceImpl.substring(superServiceImpl.lastIndexOf(".") + 1);
            clazz.addImportedType(superServiceImpl);
            clazz.addImportedType(recordType);
            clazz.setSuperClass(superServiceImplName + "<" + modelName + ">");
        }
        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.stereotype.Service"));
        clazz.addAnnotation("@Service");
 
        String daoFieldType = introspectedTable.getMyBatis3JavaMapperType();
        String daoFieldName = firstCharToLowCase(daoFieldType.substring(daoFieldType.lastIndexOf(".") + 1));
        //描述类的成员属性
        Field daoField = new Field(daoFieldName, new FullyQualifiedJavaType(daoFieldType));
        clazz.addImportedType(new FullyQualifiedJavaType(daoFieldType));
        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.beans.factory.annotation.Autowired"));
        //描述成员属性 的注解
        daoField.addAnnotation("@Autowired");
        //描述成员属性修饰符
        daoField.setVisibility(JavaVisibility.PRIVATE);
        clazz.addField(daoField);
 
        //描述 方法名
        Method method = new Method("getMapper");
        //方法注解
        method.addAnnotation("@Override");
        FullyQualifiedJavaType methodReturnType = new FullyQualifiedJavaType("Object");
        //返回值
        method.setReturnType(methodReturnType);
        //方法体,逻辑代码
        method.addBodyLine("return " + daoFieldName + ";");
        //修饰符
        method.setVisibility(JavaVisibility.PUBLIC);
        clazz.addMethod(method);
 
 
        Method method1 = new Method("getExample");
        method1.addAnnotation("@Override");
        FullyQualifiedJavaType methodReturnType1 = new FullyQualifiedJavaType("Object");
        clazz.addImportedType(new FullyQualifiedJavaType(examplePacket.concat(".").concat(modelName).concat("Example")));
        method1.setReturnType(methodReturnType1);
        method1.addBodyLine("return new " + modelName + "Example();");
        method1.setVisibility(JavaVisibility.PUBLIC);
        clazz.addMethod(method1);
 
        GeneratedJavaFile gjf2 = new GeneratedJavaFile(clazz, targetProject, context.getJavaFormatter());
        return gjf2;
    }
 
 
    // 生成controller类
    private GeneratedJavaFile generateController(IntrospectedTable introspectedTable) {
    
    
 
        FullyQualifiedJavaType controller = new FullyQualifiedJavaType(controllerName);
        TopLevelClass clazz = new TopLevelClass(controller);
        //描述类的作用域修饰符
        clazz.setVisibility(JavaVisibility.PUBLIC);
 
        //添加@Controller注解,并引入相应的类
        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RestController"));
        clazz.addAnnotation("@RestController");
        //添加@RequestMapping注解,并引入相应的类
        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RequestMapping"));
        clazz.addAnnotation("@RequestMapping(\"/"+firstCharToLowCase(modelName)+"\")");
        //添加@Api注解,并引入相应的类
        clazz.addImportedType(new FullyQualifiedJavaType("io.swagger.annotations.Api"));
        String controllerSimpleName = controllerName.substring(controllerName.lastIndexOf(".") + 1);
        clazz.addAnnotation("@Api(tags = \""+controllerSimpleName+"\", description = \""+controllerSimpleName+"\")");
 
        //引入controller的父类和model,并添加泛型
        if(stringHasValue(superController)) {
    
    
            clazz.addImportedType(superController);
            clazz.addImportedType(recordType);
            FullyQualifiedJavaType superInterfac = new FullyQualifiedJavaType(superController+"<"+modelName+">");
            clazz.addSuperInterface(superInterfac);
        }
 
        //引入Service
        FullyQualifiedJavaType service = new FullyQualifiedJavaType(serviceName);
        clazz.addImportedType(service);
 
        //添加Service成员变量
        String serviceFieldName = firstCharToLowCase(serviceName.substring(serviceName.lastIndexOf(".") + 1));
        Field daoField = new Field(serviceFieldName, new FullyQualifiedJavaType(serviceName));
        clazz.addImportedType(new FullyQualifiedJavaType(serviceName));
        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.beans.factory.annotation.Autowired"));
        //描述成员属性 的注解
        daoField.addAnnotation("@Autowired");
        //描述成员属性修饰符
        daoField.setVisibility(JavaVisibility.PRIVATE);
        clazz.addField(daoField);
 
 
        //描述 方法名
        Method method = new Method("getService");
        //方法注解
        method.addAnnotation("@Override");
        String simpleSuperServiceName = superServiceInterface.substring(superServiceInterface.lastIndexOf(".") + 1);
        FullyQualifiedJavaType methodReturnType = new FullyQualifiedJavaType(simpleSuperServiceName+"<"+modelName+">");
        //返回类型
        method.setReturnType(methodReturnType);
        //方法体,逻辑代码
        method.addBodyLine("return " + serviceFieldName + ";");
        //修饰符
        method.setVisibility(JavaVisibility.PUBLIC);
        clazz.addImportedType(superServiceInterface);
        clazz.addMethod(method);
 
 
        GeneratedJavaFile gjf2 = new GeneratedJavaFile(clazz, targetProject, context.getJavaFormatter());
        return gjf2;
    }
 
 
    private String firstCharToLowCase(String str) {
    
    
        char[] chars = new char[1];
        //String str="ABCDE1234";
        chars[0] = str.charAt(0);
        String temp = new String(chars);
        if(chars[0] >= 'A'  &&  chars[0] <= 'Z') {
    
    
            return str.replaceFirst(temp,temp.toLowerCase());
        }
        return str;
    }
}


2. Add generatorConfig.xml configuration


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
 
<generatorConfiguration>
    <properties resource="generator.properties"/>
    <context id="MySqlContext" targetRuntime="MyBatis3" defaultModelType="flat">
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>
        <property name="javaFileEncoding" value="UTF-8"/>
        <!-- 为模型生成序列化方法-->
        <plugin type="org.mybatis.generator.plugins.SerializablePlugin"/>
        <!-- 为生成的Java模型创建一个toString方法 -->
        <plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>
        <!--生成mapper.xml时覆盖原文件-->
        <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin" />
        <plugin type="com.jzxs.etp.mbg.ServiceAndControllerGeneratorPlugin" >
            <property name="targetProject" value="./src/main/java"/>
            <property name="servicePackage" value="com.jzxs.etp.service"/>
            <property name="serviceImplPackage" value="com.jzxs.etp.service.impl"/>
            <property name="controllerPackage" value="com.jzxs.etp.controller"/>
            <!--UserService,该值则为Service-->
            <property name="serviceSuffix" value="Service"/>
            <!--Service接口的父接口-->
            <property name="superServiceInterface" value="org.aurochsframework.boot.commons.service.GeneralService"/>
            <!--ServiceImpl的父类-->
            <property name="superServiceImpl" value="org.aurochsframework.boot.commons.service.AbstractGeneralService"/>
            <!--controller的父类接口-->
            <property name="superController" value="org.aurochsframework.boot.commons.controller.GeneralCrudController"/>
        </plugin>
        <commentGenerator type="com.jzxs.etp.mbg.CommentGenerator">
            <!-- 是否去除自动生成的注释 true:是 : false:否 -->
            <property name="suppressAllComments" value="true"/>
            <property name="suppressDate" value="true"/>
            <property name="addRemarkComments" value="true"/>
        </commentGenerator>
 
        <jdbcConnection driverClass="${jdbc.driverClass}"
                        connectionURL="${jdbc.connectionURL}"
                        userId="${jdbc.userId}"
                        password="${jdbc.password}">
            <!--解决mysql驱动升级到8.0后不生成指定数据库代码的问题-->
            <property name="nullCatalogMeansCurrent" value="true" />
        </jdbcConnection>
 
        <!--指定生成model的路径-->
        <javaModelGenerator targetPackage="com.jzxs.etp.mbg.model"
                            targetProject="./src/main/java"/>
        <!--指定生成mapper.xml的路径-->
        <sqlMapGenerator targetPackage="com.jzxs.etp.mbg.mapper"
                         targetProject="./src/main/resources"/>
        <!--指定生成mapper接口的的路径-->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.jzxs.etp.mbg.mapper"
                             targetProject="./src/main/java"/>
 
        <table tableName="test"></table>
    </context>
</generatorConfiguration>


五、MyBatis Generator Gui

mybatis-generator-gui is an interface tool developed based on mybatis generator. This tool allows you to easily and quickly generate Mybatis' Java POJO files and database Mapping files. The officially provided xml configuration is very flexible, which may be preferred by familiar students. This tool can be easier for novices to use.

①, core features

1. Easily generate code according to the interface steps, eliminating the tedious learning and configuration process of XML

2. Save the database connection and Generator configuration, and easily handle each code generation.

3. Built-in commonly used plug-ins, such as offset paging and optional removal of comments that are not friendly to version management, so that the regenerated files when adding or deleting fields are clearer.

4. Currently supports Mysql, Oracle and PostgreSQL

Download address: https://github.com Search mybatis-generator-gui and download any one. You
can also download it from gitee and gitcode.

② Download the code and compile it


# 下载代码
git clone https://github.com/zouzg/mybatis-generator-gui

# 进入 mybatis-generator-gui 目录
cd mybatis-generator-gui
# 执行 maven 命令
mvn jfx:jar
# 进入 target/jfx/app/ 目录
cd target/jfx/app/
# 运行jar 包
java -jar mybatis-generator-gui.jar

③, interface effect

Insert image description here

Insert image description here
Insert image description here
Insert image description here

④. Overall project directory:

Insert image description here
Insert image description here

⑤, MyBatis Generator reverse engineering code extension

Here we are mainly talking about the reverse engineering code extension of Chapter 4 MyBatis Generator. How to write it in the MyBatis Generator gui, because there is no generatorConfig.xml configuration here. As for
other knowledge, such as how to write Java FX, please study the relevant content first.

②. Customized Controller and Service plug-ins

1. Customize the templates for generating Controller and Service.


package com.jzxs.etp.mbg;
 
import org.mybatis.generator.api.GeneratedJavaFile;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
 
import java.util.ArrayList;
import java.util.List;
 
import static org.mybatis.generator.internal.util.StringUtility.stringHasValue;
import static org.mybatis.generator.internal.util.messages.Messages.getString;
 
public class ServiceAndControllerGeneratorPlugin extends PluginAdapter  {
    
    
 
    // 项目目录,一般为 src/main/java
    private String targetProject;
 
    // service包名,如:com.thinkj2ee.cms.service.service
    private String servicePackage;
 
    // service实现类包名,如:com.thinkj2ee.cms.service.service.impl
    private String serviceImplPackage;
    // Controlle类包名,如:com.thinkj2ee.cms.service.controller
    private String controllerPackage;
    // service接口名前缀
    private String servicePreffix;
 
    // service接口名后缀
    private String serviceSuffix;
 
    // service接口的父接口
    private String superServiceInterface;
 
    // service实现类的父类
    private String superServiceImpl;
    // controller类的父类
    private String superController;
 
    // dao接口基类
    private String superDaoInterface;
 
    // Example类的包名
    private String examplePacket;
 
    private String recordType;
 
    private String modelName;
 
    private FullyQualifiedJavaType model;
 
    private String serviceName;
    private String serviceImplName;
    private String controllerName;
 
    @Override
    public boolean validate(List<String> warnings) {
    
    
        boolean valid = true;
 
       /* if (!stringHasValue(properties
                .getProperty("targetProject"))) { //$NON-NLS-1$
            warnings.add(getString("ValidationError.18", //$NON-NLS-1$
                    "MapperConfigPlugin", //$NON-NLS-1$
                    "targetProject")); //$NON-NLS-1$
            valid = false;
        }
        if (!stringHasValue(properties.getProperty("servicePackage"))) { //$NON-NLS-1$
            warnings.add(getString("ValidationError.18", //$NON-NLS-1$
                    "MapperConfigPlugin", //$NON-NLS-1$
                    "servicePackage")); //$NON-NLS-1$
            valid = false;
        }
        if (!stringHasValue(properties.getProperty("serviceImplPackage"))) { //$NON-NLS-1$
            warnings.add(getString("ValidationError.18", //$NON-NLS-1$
                    "MapperConfigPlugin", //$NON-NLS-1$
                    "serviceImplPackage")); //$NON-NLS-1$
            valid = false;
        }
*/
        targetProject = properties.getProperty("targetProject");
        servicePackage = properties.getProperty("servicePackage");
        serviceImplPackage = properties.getProperty("serviceImplPackage");
        servicePreffix = properties.getProperty("servicePreffix");
        servicePreffix = stringHasValue(servicePreffix) ? servicePreffix : "";
        serviceSuffix = properties.getProperty("serviceSuffix");
        serviceSuffix = stringHasValue(serviceSuffix) ? serviceSuffix : "";
        superServiceInterface = properties.getProperty("superServiceInterface");
        superServiceImpl = properties.getProperty("superServiceImpl");
        superDaoInterface = properties.getProperty("superDaoInterface");
        controllerPackage = properties.getProperty("controllerPackage");
        superController = properties.getProperty("superController");
 
        return valid;
    }
 
    @Override
    public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {
    
    
        recordType = introspectedTable.getBaseRecordType();
        modelName = recordType.substring(recordType.lastIndexOf(".") + 1);
        model = new FullyQualifiedJavaType(recordType);
        serviceName = servicePackage + "." + servicePreffix + modelName + serviceSuffix;
        serviceImplName = serviceImplPackage + "." + modelName + serviceSuffix+"Impl";
        examplePacket=recordType.substring(0,recordType.lastIndexOf("."));
        controllerName=controllerPackage.concat(".").concat(modelName).concat("Controller");
        List<GeneratedJavaFile> answer = new ArrayList<>();
        GeneratedJavaFile gjf = generateServiceInterface(introspectedTable);
        GeneratedJavaFile gjf2 = generateServiceImpl(introspectedTable);
        GeneratedJavaFile gjf3 = generateController(introspectedTable);
        answer.add(gjf);
        answer.add(gjf2);
        answer.add(gjf3);
        return answer;
    }
 
    // 生成service接口
    private GeneratedJavaFile generateServiceInterface(IntrospectedTable introspectedTable) {
    
    
        FullyQualifiedJavaType service = new FullyQualifiedJavaType(serviceName);
        Interface serviceInterface = new Interface(service);
        serviceInterface.setVisibility(JavaVisibility.PUBLIC);
        // 添加父接口
        if(stringHasValue(superServiceInterface)) {
    
    
            String superServiceInterfaceName = superServiceInterface.substring(superServiceInterface.lastIndexOf(".") + 1);
            serviceInterface.addImportedType(new FullyQualifiedJavaType(superServiceInterface));
            serviceInterface.addImportedType(new FullyQualifiedJavaType(recordType));
            serviceInterface.addSuperInterface(new FullyQualifiedJavaType(superServiceInterfaceName + "<" + modelName + ">"));
        }
        GeneratedJavaFile gjf = new GeneratedJavaFile(serviceInterface, targetProject, context.getJavaFormatter());
        return gjf;
    }
 
    // 生成serviceImpl实现类
    private GeneratedJavaFile generateServiceImpl(IntrospectedTable introspectedTable) {
    
    
        FullyQualifiedJavaType service = new FullyQualifiedJavaType(serviceName);
        FullyQualifiedJavaType serviceImpl = new FullyQualifiedJavaType(serviceImplName);
        TopLevelClass clazz = new TopLevelClass(serviceImpl);
        //描述类的作用域修饰符
        clazz.setVisibility(JavaVisibility.PUBLIC);
        //描述类 引入的类
        clazz.addImportedType(service);
        //描述类 的实现接口类
        clazz.addSuperInterface(service);
        if(stringHasValue(superServiceImpl)) {
    
    
            String superServiceImplName = superServiceImpl.substring(superServiceImpl.lastIndexOf(".") + 1);
            clazz.addImportedType(superServiceImpl);
            clazz.addImportedType(recordType);
            clazz.setSuperClass(superServiceImplName + "<" + modelName + ">");
        }
        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.stereotype.Service"));
        clazz.addAnnotation("@Service");
 
        String daoFieldType = introspectedTable.getMyBatis3JavaMapperType();
        String daoFieldName = firstCharToLowCase(daoFieldType.substring(daoFieldType.lastIndexOf(".") + 1));
        //描述类的成员属性
        Field daoField = new Field(daoFieldName, new FullyQualifiedJavaType(daoFieldType));
        clazz.addImportedType(new FullyQualifiedJavaType(daoFieldType));
        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.beans.factory.annotation.Autowired"));
        //描述成员属性 的注解
        daoField.addAnnotation("@Autowired");
        //描述成员属性修饰符
        daoField.setVisibility(JavaVisibility.PRIVATE);
        clazz.addField(daoField);
 
        //描述 方法名
        Method method = new Method("getMapper");
        //方法注解
        method.addAnnotation("@Override");
        FullyQualifiedJavaType methodReturnType = new FullyQualifiedJavaType("Object");
        //返回值
        method.setReturnType(methodReturnType);
        //方法体,逻辑代码
        method.addBodyLine("return " + daoFieldName + ";");
        //修饰符
        method.setVisibility(JavaVisibility.PUBLIC);
        clazz.addMethod(method);
 
 
        Method method1 = new Method("getExample");
        method1.addAnnotation("@Override");
        FullyQualifiedJavaType methodReturnType1 = new FullyQualifiedJavaType("Object");
        clazz.addImportedType(new FullyQualifiedJavaType(examplePacket.concat(".").concat(modelName).concat("Example")));
        method1.setReturnType(methodReturnType1);
        method1.addBodyLine("return new " + modelName + "Example();");
        method1.setVisibility(JavaVisibility.PUBLIC);
        clazz.addMethod(method1);
 
        GeneratedJavaFile gjf2 = new GeneratedJavaFile(clazz, targetProject, context.getJavaFormatter());
        return gjf2;
    }
 
 
    // 生成controller类
    private GeneratedJavaFile generateController(IntrospectedTable introspectedTable) {
    
    
 
        FullyQualifiedJavaType controller = new FullyQualifiedJavaType(controllerName);
        TopLevelClass clazz = new TopLevelClass(controller);
        //描述类的作用域修饰符
        clazz.setVisibility(JavaVisibility.PUBLIC);
 
        //添加@Controller注解,并引入相应的类
        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RestController"));
        clazz.addAnnotation("@RestController");
        //添加@RequestMapping注解,并引入相应的类
        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RequestMapping"));
        clazz.addAnnotation("@RequestMapping(\"/"+firstCharToLowCase(modelName)+"\")");
        //添加@Api注解,并引入相应的类
        clazz.addImportedType(new FullyQualifiedJavaType("io.swagger.annotations.Api"));
        String controllerSimpleName = controllerName.substring(controllerName.lastIndexOf(".") + 1);
        clazz.addAnnotation("@Api(tags = \""+controllerSimpleName+"\", description = \""+controllerSimpleName+"\")");
 
        //引入controller的父类和model,并添加泛型
        if(stringHasValue(superController)) {
    
    
            clazz.addImportedType(superController);
            clazz.addImportedType(recordType);
            FullyQualifiedJavaType superInterfac = new FullyQualifiedJavaType(superController+"<"+modelName+">");
            clazz.addSuperInterface(superInterfac);
        }
 
        //引入Service
        FullyQualifiedJavaType service = new FullyQualifiedJavaType(serviceName);
        clazz.addImportedType(service);
 
        //添加Service成员变量
        String serviceFieldName = firstCharToLowCase(serviceName.substring(serviceName.lastIndexOf(".") + 1));
        Field daoField = new Field(serviceFieldName, new FullyQualifiedJavaType(serviceName));
        clazz.addImportedType(new FullyQualifiedJavaType(serviceName));
        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.beans.factory.annotation.Autowired"));
        //描述成员属性 的注解
        daoField.addAnnotation("@Autowired");
        //描述成员属性修饰符
        daoField.setVisibility(JavaVisibility.PRIVATE);
        clazz.addField(daoField);
 
 
        //描述 方法名
        Method method = new Method("getService");
        //方法注解
        method.addAnnotation("@Override");
        String simpleSuperServiceName = superServiceInterface.substring(superServiceInterface.lastIndexOf(".") + 1);
        FullyQualifiedJavaType methodReturnType = new FullyQualifiedJavaType(simpleSuperServiceName+"<"+modelName+">");
        //返回类型
        method.setReturnType(methodReturnType);
        //方法体,逻辑代码
        method.addBodyLine("return " + serviceFieldName + ";");
        //修饰符
        method.setVisibility(JavaVisibility.PUBLIC);
        clazz.addImportedType(superServiceInterface);
        clazz.addMethod(method);
 
 
        GeneratedJavaFile gjf2 = new GeneratedJavaFile(clazz, targetProject, context.getJavaFormatter());
        return gjf2;
    }
 
 
    private String firstCharToLowCase(String str) {
    
    
        char[] chars = new char[1];
        //String str="ABCDE1234";
        chars[0] = str.charAt(0);
        String temp = new String(chars);
        if(chars[0] >= 'A'  &&  chars[0] <= 'Z') {
    
    
            return str.replaceFirst(temp,temp.toLowerCase());
        }
        return str;
    }
}


2. Add MainUI.fxml function


<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.collections.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>

<BorderPane prefHeight="613.0" prefWidth="918.0" stylesheets="@../style.css" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.zzg.mybatis.generator.controller.MainUIController">
    <top>
        <VBox>
            <children>
                <ToolBar minHeight="70.0" prefHeight="81.0" prefWidth="918.0" BorderPane.alignment="CENTER">
                    <items>
                        <Label fx:id="connectionLabel" contentDisplay="TOP" text="数据库连接">
                            <cursor>
                                <Cursor fx:constant="HAND" />
                            </cursor>
                            <font>
                                <Font size="14.0" />
                            </font>
                            <padding>
                                <Insets left="10.0" right="10.0" />
                            </padding>
                        </Label>
                        <Label fx:id="configsLabel" contentDisplay="TOP" text="配置">
                            <padding>
                                <Insets right="10.0" />
                            </padding>
                        </Label>
                    </items>
                </ToolBar>
            </children>
        </VBox>
    </top>
    <center>
        <SplitPane dividerPositions="0.15">
            <items>
                <AnchorPane maxWidth="500.0" minWidth="100.0" prefHeight="818.0" prefWidth="200.0">
                    <children>
                        <TreeView fx:id="leftDBTree" layoutX="-14.0" maxWidth="134.0" prefHeight="503.0" prefWidth="134.0" AnchorPane.bottomAnchor="27.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
                        <TextField fx:id="filterTreeBox" layoutY="504.0" prefHeight="26.0" prefWidth="134.0" promptText="搜索" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" />
                    </children>
                </AnchorPane>
                <AnchorPane minWidth="400.0">
                    <children>
                        <VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
                            <children>
                                <GridPane alignment="TOP_RIGHT" layoutX="5.0" layoutY="29.0" prefHeight="805.0" prefWidth="766.0" vgap="5.0" AnchorPane.leftAnchor="-5.0" AnchorPane.rightAnchor="10.0">
                                    <columnConstraints>
                                        <ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES" maxWidth="157.0" minWidth="132.0" prefWidth="138.0" />
                                        <ColumnConstraints hgrow="SOMETIMES" maxWidth="688.0" minWidth="10.0" prefWidth="222.0" />
                                        <ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES" maxWidth="688.0" minWidth="69.0" prefWidth="76.0" />
                                        <ColumnConstraints hgrow="SOMETIMES" maxWidth="688.0" minWidth="10.0" prefWidth="108.0" />
                                        <ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES" maxWidth="688.0" minWidth="10.0" prefWidth="129.0" />
                                        <ColumnConstraints hgrow="SOMETIMES" maxWidth="688.0" minWidth="10.0" prefWidth="95.0" />
                                    </columnConstraints>
                                    <rowConstraints>
                                        <RowConstraints minHeight="10.0"  prefHeight="30.0"  />
                                        <RowConstraints minHeight="10.0"  prefHeight="30.0"  />
                                        <RowConstraints minHeight="10.0"  prefHeight="30.0"  />
                                        <RowConstraints minHeight="10.0"  prefHeight="30.0"  />
                                        <RowConstraints minHeight="10.0"  prefHeight="30.0"  />
                                        <RowConstraints minHeight="10.0"  prefHeight="30.0"  />
                                        <RowConstraints minHeight="10.0"  prefHeight="30.0"  />
                                        <RowConstraints minHeight="10.0"  prefHeight="30.0"  />
                                        <RowConstraints minHeight="10.0"  prefHeight="30.0"  />
                                        <RowConstraints minHeight="10.0"  prefHeight="30.0"  />
                                        <RowConstraints minHeight="10.0"  prefHeight="30.0"  />
                                        <RowConstraints minHeight="10.0"  prefHeight="200"   />
                                        <RowConstraints maxHeight="43.0"  minHeight="11.0"  prefHeight="43" />
                                    </rowConstraints>
                                    <children>
                                        <Label text="表名" />
                                        <TextField fx:id="tableNameField" disable="true" editable="false" prefHeight="27.0" prefWidth="156.0" promptText="person" GridPane.columnIndex="1">
                                            <GridPane.margin>
                                                <Insets left="5.0" right="5.0" />
                                            </GridPane.margin>
                                        </TextField>

                                        <Label text="Java实体类名" GridPane.rowIndex="1" />
                                        <HBox alignment="CENTER_LEFT" GridPane.columnIndex="1" GridPane.columnSpan="3" GridPane.rowIndex="1" GridPane.valignment="CENTER">
                                            <children>
                                                <TextField fx:id="domainObjectNameField" prefHeight="27.0" prefWidth="154.0" promptText="Person" GridPane.columnIndex="1" GridPane.rowIndex="2">
                                                    <GridPane.margin>
                                                        <Insets left="5.0" right="5.0" />
                                                    </GridPane.margin>
                                                    <HBox.margin>
                                                        <Insets right="5.0" />
                                                    </HBox.margin>
                                                </TextField>
                                                <Button mnemonicParsing="false" onAction="#openTableColumnCustomizationPage" text="定制列">
                                                    <styleClass>
                                                        <String fx:value="btn" />
                                                        <String fx:value="btn-default" />
                                                    </styleClass>
                                                </Button>
                                            </children>
                                            <GridPane.margin>
                                                <Insets left="5.0" />
                                            </GridPane.margin>
                                        </HBox>

                                        <Label text="主键(选填)" GridPane.rowIndex="2" />
                                        <HBox alignment="CENTER_LEFT" GridPane.columnIndex="1" GridPane.columnSpan="3" GridPane.rowIndex="2" GridPane.valignment="CENTER">
                                            <children>
                                                <TextField fx:id="generateKeysField" prefHeight="25.0" prefWidth="216.0" promptText="primary key, such as id" GridPane.columnIndex="1" GridPane.rowIndex="3">
                                                    <GridPane.margin>
                                                        <Insets left="5.0" right="5.0" />
                                                    </GridPane.margin>
                                                    <HBox.margin>
                                                        <Insets right="5.0" />
                                                    </HBox.margin>
                                                </TextField>
                                            </children>
                                            <GridPane.margin>
                                                <Insets left="5.0" />
                                            </GridPane.margin>
                                        </HBox>

                                        <Label text="项目所在目录" GridPane.rowIndex="3" />
                                        <HBox alignment="CENTER_LEFT" prefHeight="30.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.columnSpan="4" GridPane.rowIndex="3">
                                            <children>
                                                <TextField fx:id="projectFolderField" prefHeight="27.0" prefWidth="463.0" promptText="D:\workspace\example">
                                                    <HBox.margin>
                                                        <Insets left="5.0" right="5.0" />
                                                    </HBox.margin>
                                                </TextField>
                                                <Button mnemonicParsing="false" onAction="#chooseProjectFolder" text="选择">
                                                    <styleClass>
                                                        <String fx:value="btn" />
                                                        <String fx:value="btn-default" />
                                                    </styleClass>
                                                </Button>
                                            </children>
                                        </HBox>

                                        <Label text="Controller接口包名" GridPane.rowIndex="4" />
                                        <TextField fx:id="controllerTargetPackage" prefHeight="27.0" prefWidth="248.0" promptText="com.example.controller" text="com.example.controller" GridPane.columnIndex="1" GridPane.rowIndex="4">
                                            <HBox.margin>
                                                <Insets right="5.0" />
                                            </HBox.margin>
                                            <GridPane.margin>
                                                <Insets left="5.0" right="5.0" />
                                            </GridPane.margin>
                                        </TextField>
                                        <Label text="存放目录" GridPane.columnIndex="2" GridPane.rowIndex="4" />
                                        <TextField fx:id="controllerTargetProject" prefHeight="27.0" prefWidth="155.0" promptText="src/main/java" text="src/main/java" GridPane.columnIndex="3" GridPane.columnSpan="2" GridPane.rowIndex="4">
                                            <GridPane.margin>
                                                <Insets left="5.0" />
                                            </GridPane.margin>
                                        </TextField>

                                        <Label text="实体类名包名" GridPane.rowIndex="5" />
                                        <TextField fx:id="modelTargetPackage" prefHeight="27.0" prefWidth="152.0" promptText="com.example.model" text="com.example.model" GridPane.columnIndex="1" GridPane.rowIndex="5">
                                            <HBox.margin>
                                                <Insets right="5.0" />
                                            </HBox.margin>
                                            <GridPane.margin>
                                                <Insets left="5.0" right="5.0" />
                                            </GridPane.margin>
                                        </TextField>
                                        <Label text="存放目录" GridPane.columnIndex="2" GridPane.rowIndex="5" />
                                        <TextField fx:id="modelTargetProject" prefHeight="27.0" prefWidth="228.0" promptText="src/main/java" text="src/main/java" GridPane.columnIndex="3" GridPane.columnSpan="2" GridPane.rowIndex="5">
                                            <GridPane.margin>
                                                <Insets left="5.0" />
                                            </GridPane.margin>
                                        </TextField>

                                        <Label text="Service接口包名" GridPane.rowIndex="6" />
                                        <TextField fx:id="serviceTargetPackage" prefHeight="27.0" prefWidth="248.0" promptText="com.example.service" text="com.example.service" GridPane.columnIndex="1" GridPane.rowIndex="6">
                                            <HBox.margin>
                                                <Insets right="5.0" />
                                            </HBox.margin>
                                            <GridPane.margin>
                                                <Insets left="5.0" right="5.0" />
                                            </GridPane.margin>
                                        </TextField>
                                        <Label text="存放目录" GridPane.columnIndex="2" GridPane.rowIndex="6" />
                                        <TextField fx:id="serviceTargetProject" prefHeight="27.0" prefWidth="155.0" promptText="src/main/java" text="src/main/java" GridPane.columnIndex="3" GridPane.columnSpan="2" GridPane.rowIndex="6">
                                            <GridPane.margin>
                                                <Insets left="5.0" />
                                            </GridPane.margin>
                                        </TextField>

                                        <Label text="ServiceImpl接口包名" GridPane.rowIndex="7" />
                                        <TextField fx:id="serviceImplTargetPackage" prefHeight="27.0" prefWidth="248.0" promptText="com.example.service.impl" text="com.example.service.impl" GridPane.columnIndex="1" GridPane.rowIndex="7">
                                            <HBox.margin>
                                                <Insets right="5.0" />
                                            </HBox.margin>
                                            <GridPane.margin>
                                                <Insets left="5.0" right="5.0" />
                                            </GridPane.margin>
                                        </TextField>
                                        <Label text="存放目录" GridPane.columnIndex="2" GridPane.rowIndex="7" />
                                        <TextField fx:id="serviceImplTargetProject" prefHeight="27.0" prefWidth="155.0" promptText="src/main/java" text="src/main/java" GridPane.columnIndex="3" GridPane.columnSpan="2" GridPane.rowIndex="7">
                                            <GridPane.margin>
                                                <Insets left="5.0" />
                                            </GridPane.margin>
                                        </TextField>


                                        <Label text="Mapper接口包名" GridPane.rowIndex="8" />
                                        <TextField fx:id="daoTargetPackage" prefHeight="27.0" prefWidth="248.0" promptText="com.example.mapper" text="com.example.mapper" GridPane.columnIndex="1" GridPane.rowIndex="8">
                                            <HBox.margin>
                                                <Insets right="5.0" />
                                            </HBox.margin>
                                            <GridPane.margin>
                                                <Insets left="5.0" right="5.0" />
                                            </GridPane.margin>
                                        </TextField>
                                        <Label text="存放目录" GridPane.columnIndex="2" GridPane.rowIndex="8" />
                                        <TextField fx:id="daoTargetProject" prefHeight="27.0" prefWidth="155.0" promptText="src/main/java" text="src/main/java" GridPane.columnIndex="3" GridPane.columnSpan="2" GridPane.rowIndex="8">
                                            <GridPane.margin>
                                                <Insets left="5.0" />
                                            </GridPane.margin>
                                        </TextField>

                                        <Label text="自定义接口名称(选填)" GridPane.rowIndex="9">
                                            <padding>
                                                <Insets left="5.0" />
                                            </padding>
                                        </Label>
                                        <TextField fx:id="mapperName" prefHeight="27.0" prefWidth="532.0" promptText="PersonDAO" GridPane.columnIndex="1" GridPane.columnSpan="4" GridPane.rowIndex="9">
                                            <GridPane.margin>
                                                <Insets left="5.0" />
                                            </GridPane.margin>
                                        </TextField>

                                        <Label prefHeight="27.0" prefWidth="99.0" text="映射XML文件包名" GridPane.rowIndex="10" />
                                        <TextField fx:id="mapperTargetPackage" prefHeight="27.0" prefWidth="248.0" promptText="com.example" text="com.example" GridPane.columnIndex="1" GridPane.rowIndex="10">
                                            <HBox.margin>
                                                <Insets right="5.0" />
                                            </HBox.margin>
                                            <GridPane.margin>
                                                <Insets left="5.0" right="5.0" />
                                            </GridPane.margin>
                                        </TextField>
                                        <Label text="存放目录" GridPane.columnIndex="2" GridPane.rowIndex="10" />
                                        <TextField fx:id="mappingTargetProject" prefHeight="27.0" prefWidth="155.0" promptText="src/main/resources" text="src/main/resources" GridPane.columnIndex="3" GridPane.columnSpan="2" GridPane.rowIndex="10">
                                            <GridPane.margin>
                                                <Insets left="5.0" />
                                            </GridPane.margin>
                                        </TextField>

                                        <VBox prefHeight="53.0" prefWidth="536.0" spacing="10.0" GridPane.columnIndex="1" GridPane.columnSpan="4" GridPane.rowIndex="11">
                                            <children>
                                                <HBox alignment="CENTER_LEFT">
                                                    <children>
                                                        <Label text="生成文件的编码" />
                                                        <ChoiceBox fx:id="encodingChoice" prefHeight="23.0" prefWidth="71.0">
                                                            <items>
                                                                <FXCollections fx:factory="observableArrayList">
                                                                    <String fx:value="UTF-8" />
                                                                </FXCollections>
                                                            </items>
                                                        </ChoiceBox>
                                                    </children>
                                                </HBox>
                                                <HBox alignment="CENTER_LEFT" spacing="10.0" GridPane.columnIndex="1" GridPane.columnSpan="3">
<!--                                                     GridPane.rowIndex="8"-->
                                                    <children>
                                                        <CheckBox fx:id="useExample" minWidth="100.0" mnemonicParsing="false" text="使用Example" />
                                                        <CheckBox fx:id="offsetLimitCheckBox" disable="true" minWidth="100.0" mnemonicParsing="false" selected="true" text="分页插件(暂时只支持MySQL和PostgreSQL)" GridPane.columnIndex="1" />
<!--                                                         GridPane.rowIndex="8"-->
                                                    </children>
                                                </HBox>
                                                <HBox prefHeight="100.0" prefWidth="200.0" spacing="18.0">
                                                    <children>
                                                        <CheckBox fx:id="commentCheckBox" mnemonicParsing="false" selected="true" text="生成实体域注释(来自表注释)" />
                                                        <CheckBox fx:id="overrideXML" mnemonicParsing="false" selected="true" text="覆盖原XML" />
                                                    </children>
                                                </HBox>
                                                <HBox spacing="18.0">
                                                    <children>
                                                        <CheckBox fx:id="useLombokPlugin" mnemonicParsing="false" text="LombokPlugin" />
                                                        <CheckBox fx:id="needToStringHashcodeEquals" mnemonicParsing="false" selected="true" text="生成toString/hashCode/equals方法" />
                                                        <CheckBox fx:id="useSchemaPrefix" mnemonicParsing="false" text="使用Schema前缀" />
                                                    </children>
                                                </HBox>
                                                <HBox prefHeight="100.0" prefWidth="200.0" spacing="18.0">
                                                    <children>
                                                        <CheckBox fx:id="forUpdateCheckBox" mnemonicParsing="false" selected="false" text="select 增加ForUpdate" />
                                                        <CheckBox fx:id="annotationDAOCheckBox" mnemonicParsing="false" selected="true" text="DAO使用 @Repository 注解" />
                                                        <CheckBox fx:id="annotationMapperDAOCheckBox" mnemonicParsing="false" selected="false" text="DAO使用 @Mapper 注解" />
                                                    </children>
                                                </HBox>
                                                <HBox prefHeight="100.0" prefWidth="200.0">
                                                    <children>
                                                        <CheckBox fx:id="useDAOExtendStyle" mnemonicParsing="false" selected="true" text="DAO方法抽出到公共父接口">
                                                            <HBox.margin>
                                                                <Insets right="10.0" />
                                                            </HBox.margin>
                                                        </CheckBox>
                                                        <CheckBox fx:id="jsr310Support" mnemonicParsing="false" prefHeight="16.0" prefWidth="252.0" text="JSR310: Date and Time API" />
                                                    </children>
                                                </HBox>
                                                <HBox spacing="18.0">
                                                    <children>
                                                        <CheckBox fx:id="annotationCheckBox" mnemonicParsing="false" selected="false" text="生成JPA注解" />
                                                        <CheckBox fx:id="useActualColumnNamesCheckbox" mnemonicParsing="false" selected="false" text="使用实际的列名" />
                                                        <CheckBox fx:id="useTableNameAliasCheckbox" mnemonicParsing="false" selected="false" text="启用as别名查询" />
                                                    </children>
                                                </HBox>
                                                <HBox prefHeight="100.0" prefWidth="200.0" />
                                            </children>
                                            <padding>
                                                <Insets left="5.0" />
                                            </padding>
                                        </VBox>
                                        <HBox alignment="CENTER_LEFT" prefHeight="100.0" prefWidth="200.0" spacing="10.0" GridPane.columnIndex="1" GridPane.columnSpan="3" GridPane.rowIndex="12">
                                            <children>
                                                <Button mnemonicParsing="false" onAction="#generateCode" text="代码生成">
                                                    <styleClass>
                                                        <String fx:value="btn-success" />
                                                        <String fx:value="btn" />
                                                    </styleClass>
                                                </Button>
                                                <Button mnemonicParsing="false" onAction="#saveGeneratorConfig" text="保存配置">
                                                    <styleClass>
                                                        <String fx:value="btn" />
                                                        <String fx:value="btn-default" />
                                                    </styleClass>
                                                </Button>
                                                <Button mnemonicParsing="false" onAction="#openTargetFolder" text="打开生成文件夹">
                                                    <styleClass>
                                                        <String fx:value="btn" />
                                                        <String fx:value="btn-default" />
                                                    </styleClass>
                                                </Button>
                                            </children>
                                        </HBox>

                                    </children>
                                </GridPane>
                            </children>
                            <padding>
                                <Insets bottom="7.0" left="7.0" right="7.0" top="7.0" />
                            </padding>
                        </VBox>
                    </children>
                </AnchorPane>
            </items>
        </SplitPane>
    </center>
</BorderPane>


3. Add MainUIController function


package com.zzg.mybatis.generator.controller;

import com.jcraft.jsch.Session;
import com.zzg.mybatis.generator.bridge.MybatisGeneratorBridge;
import com.zzg.mybatis.generator.model.DatabaseConfig;
import com.zzg.mybatis.generator.model.GeneratorConfig;
import com.zzg.mybatis.generator.model.UITableColumnVO;
import com.zzg.mybatis.generator.util.ConfigHelper;
import com.zzg.mybatis.generator.util.DbUtil;
import com.zzg.mybatis.generator.util.MyStringUtils;
import com.zzg.mybatis.generator.view.AlertUtil;
import com.zzg.mybatis.generator.view.UIProgressCallback;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.TextFieldTreeCell;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.KeyEvent;
import javafx.stage.DirectoryChooser;
import javafx.util.Callback;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.mybatis.generator.config.ColumnOverride;
import org.mybatis.generator.config.IgnoredColumn;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.*;
import java.io.File;
import java.net.URL;
import java.sql.SQLRecoverableException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.ResourceBundle;

public class MainUIController extends BaseFXController {
    
    

    private static final Logger _LOG = LoggerFactory.getLogger(MainUIController.class);
    private static final String FOLDER_NO_EXIST = "部分目录不存在,是否创建";
    // tool bar buttons
    @FXML
    private Label connectionLabel;
    @FXML
    private Label configsLabel;
    @FXML
    private TextField modelTargetPackage;
    @FXML
    private TextField serviceTargetPackage;
    @FXML
    private TextField serviceImplTargetPackage;
    @FXML
    private TextField controllerTargetPackage;
    @FXML
    private TextField mapperTargetPackage;
    @FXML
    private TextField daoTargetPackage;
    @FXML
    private TextField tableNameField;
    @FXML
    private TextField domainObjectNameField;
    @FXML
    private TextField generateKeysField;	//主键ID
    @FXML
    private TextField modelTargetProject;
    @FXML
    private TextField serviceTargetProject;
    @FXML
    private TextField serviceImplTargetProject;
    @FXML
    private TextField controllerTargetProject;
    @FXML
    private TextField mappingTargetProject;
    @FXML
    private TextField daoTargetProject;
    @FXML
    private TextField mapperName;
    @FXML
    private TextField projectFolderField;
    @FXML
    private CheckBox offsetLimitCheckBox;
    @FXML
    private CheckBox commentCheckBox;
    @FXML
	private CheckBox overrideXML;
    @FXML
    private CheckBox needToStringHashcodeEquals;
    @FXML
    private CheckBox useLombokPlugin;
    @FXML
    private CheckBox forUpdateCheckBox;
    @FXML
    private CheckBox annotationDAOCheckBox;
    @FXML
    private CheckBox annotationMapperDAOCheckBox;
    @FXML
    private CheckBox useTableNameAliasCheckbox;
    @FXML
    private CheckBox annotationCheckBox;
    @FXML
    private CheckBox useActualColumnNamesCheckbox;
    @FXML
    private CheckBox useExample;
    @FXML
    private CheckBox useDAOExtendStyle;
    @FXML
    private CheckBox useSchemaPrefix;
    @FXML
    private CheckBox jsr310Support;
    @FXML
    private TreeView<String> leftDBTree;
    @FXML
    public TextField filterTreeBox;
    // Current selected databaseConfig
    private DatabaseConfig selectedDatabaseConfig;
    // Current selected tableName
    private String tableName;

    private List<IgnoredColumn> ignoredColumns;

    private List<ColumnOverride> columnOverrides;

    @FXML
    private ChoiceBox<String> encodingChoice;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
    
    
        ImageView dbImage = new ImageView("icons/computer.png");
        dbImage.setFitHeight(40);
        dbImage.setFitWidth(40);
        connectionLabel.setGraphic(dbImage);
        connectionLabel.setOnMouseClicked(event -> {
    
    
            TabPaneController controller = (TabPaneController) loadFXMLPage("新建数据库连接", FXMLPage.NEW_CONNECTION, false);
            controller.setMainUIController(this);
            controller.showDialogStage();
        });
        ImageView configImage = new ImageView("icons/config-list.png");
        configImage.setFitHeight(40);
        configImage.setFitWidth(40);
        configsLabel.setGraphic(configImage);
        configsLabel.setOnMouseClicked(event -> {
    
    
            GeneratorConfigController controller = (GeneratorConfigController) loadFXMLPage("配置", FXMLPage.GENERATOR_CONFIG, false);
            controller.setMainUIController(this);
            controller.showDialogStage();
        });
		useExample.setOnMouseClicked(event -> {
    
    
			if (useExample.isSelected()) {
    
    
				offsetLimitCheckBox.setDisable(false);
			} else {
    
    
				offsetLimitCheckBox.setDisable(true);
			}
		});
		// selectedProperty().addListener 解决应用配置的时候未触发Clicked事件
        useLombokPlugin.selectedProperty().addListener((observable, oldValue, newValue) -> {
    
    
            needToStringHashcodeEquals.setDisable(newValue);
        });

        leftDBTree.setShowRoot(false);
        leftDBTree.setRoot(new TreeItem<>());
        Callback<TreeView<String>, TreeCell<String>> defaultCellFactory = TextFieldTreeCell.forTreeView();
        filterTreeBox.addEventHandler(KeyEvent.KEY_PRESSED, ev -> {
    
    
            if (ev.getCode() == KeyCode.ENTER) {
    
    
                ObservableList<TreeItem<String>> schemas = leftDBTree.getRoot().getChildren();
                schemas.filtered(TreeItem::isExpanded).forEach(this::displayTables);
                ev.consume();
            }
        });
        leftDBTree.setCellFactory((TreeView<String> tv) -> {
    
    
            TreeCell<String> cell = defaultCellFactory.call(tv);

            cell.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
    
    
                int level = leftDBTree.getTreeItemLevel(cell.getTreeItem());
                TreeCell<String> treeCell = (TreeCell<String>) event.getSource();
                TreeItem<String> treeItem = treeCell.getTreeItem();
                if (level == 1) {
    
    
                    final ContextMenu contextMenu = new ContextMenu();
                    MenuItem item1 = new MenuItem("关闭连接");
                    item1.setOnAction(event1 -> treeItem.getChildren().clear());
	                MenuItem item2 = new MenuItem("编辑连接");
	                item2.setOnAction(event1 -> {
    
    
		                DatabaseConfig selectedConfig = (DatabaseConfig) treeItem.getGraphic().getUserData();
                        TabPaneController controller = (TabPaneController) loadFXMLPage("编辑数据库连接", FXMLPage.NEW_CONNECTION, false);
		                controller.setMainUIController(this);
		                controller.setConfig(selectedConfig);
		                controller.showDialogStage();
	                });
                    MenuItem item3 = new MenuItem("删除连接");
                    item3.setOnAction(event1 -> {
    
    
                        DatabaseConfig selectedConfig = (DatabaseConfig) treeItem.getGraphic().getUserData();
                        try {
    
    
                            ConfigHelper.deleteDatabaseConfig(selectedConfig);
                            this.loadLeftDBTree();
                        } catch (Exception e) {
    
    
                            AlertUtil.showErrorAlert("Delete connection failed! Reason: " + e.getMessage());
                        }
                    });
                    contextMenu.getItems().addAll(item1, item2, item3);
                    cell.setContextMenu(contextMenu);
                }
                if (event.getClickCount() == 2) {
    
    
                    if(treeItem == null) {
    
    
                        return ;
                    }
                    treeItem.setExpanded(true);
                    if (level == 1) {
    
    
                        displayTables(treeItem);
                    } else if (level == 2) {
    
     // left DB tree level3
                        String tableName = treeCell.getTreeItem().getValue();
                        selectedDatabaseConfig = (DatabaseConfig) treeItem.getParent().getGraphic().getUserData();
                        this.tableName = tableName;
                        tableNameField.setText(tableName);
                        domainObjectNameField.setText(MyStringUtils.dbStringToCamelStyle(tableName));
                        mapperName.setText(domainObjectNameField.getText().concat("DAO"));
                    }
                }
            });
            return cell;
        });
        loadLeftDBTree();
		setTooltip();
		//默认选中第一个,否则如果忘记选择,没有对应错误提示
        encodingChoice.getSelectionModel().selectFirst();
	}

	private void displayTables(TreeItem<String> treeItem) {
    
    
        if(treeItem == null) {
    
    
            return ;
        }
        if (!treeItem.isExpanded()) {
    
    
            return;
        }
        DatabaseConfig selectedConfig = (DatabaseConfig) treeItem.getGraphic().getUserData();
        try {
    
    
            String filter = filterTreeBox.getText();
            List<String> tables = DbUtil.getTableNames(selectedConfig, filter);
            if (tables.size() > 0) {
    
    
                ObservableList<TreeItem<String>> children = treeItem.getChildren();
                children.clear();
                for (String tableName : tables) {
    
    
                    TreeItem<String> newTreeItem = new TreeItem<>();
                    ImageView imageView = new ImageView("icons/table.png");
                    imageView.setFitHeight(16);
                    imageView.setFitWidth(16);
                    newTreeItem.setGraphic(imageView);
                    newTreeItem.setValue(tableName);
                    children.add(newTreeItem);
                }
            }else if (StringUtils.isNotBlank(filter)){
    
    
                treeItem.getChildren().clear();
            }
            if (StringUtils.isNotBlank(filter)) {
    
    
                ImageView imageView = new ImageView("icons/filter.png");
                imageView.setFitHeight(16);
                imageView.setFitWidth(16);
                imageView.setUserData(treeItem.getGraphic().getUserData());
                treeItem.setGraphic(imageView);
            }else {
    
    
                ImageView dbImage = new ImageView("icons/computer.png");
                dbImage.setFitHeight(16);
                dbImage.setFitWidth(16);
                dbImage.setUserData(treeItem.getGraphic().getUserData());
                treeItem.setGraphic(dbImage);
            }
        } catch (SQLRecoverableException e) {
    
    
            _LOG.error(e.getMessage(), e);
            AlertUtil.showErrorAlert("连接超时");
        } catch (Exception e) {
    
    
            _LOG.error(e.getMessage(), e);
            AlertUtil.showErrorAlert(e.getMessage());
        }
    }

	private void setTooltip() {
    
    
		encodingChoice.setTooltip(new Tooltip("生成文件的编码,必选"));
		generateKeysField.setTooltip(new Tooltip("insert时可以返回主键ID"));
		offsetLimitCheckBox.setTooltip(new Tooltip("是否要生成分页查询代码"));
		commentCheckBox.setTooltip(new Tooltip("使用数据库的列注释作为实体类字段名的Java注释 "));
		useActualColumnNamesCheckbox.setTooltip(new Tooltip("是否使用数据库实际的列名作为实体类域的名称"));
		useTableNameAliasCheckbox.setTooltip(new Tooltip("在Mapper XML文件中表名使用别名,并且列全部使用as查询"));
		overrideXML.setTooltip(new Tooltip("重新生成时把原XML文件覆盖,否则是追加"));
        useDAOExtendStyle.setTooltip(new Tooltip("将通用接口方法放在公共接口中,DAO接口留空"));
        forUpdateCheckBox.setTooltip(new Tooltip("在Select语句中增加for update后缀"));
        useLombokPlugin.setTooltip(new Tooltip("实体类使用Lombok @Data简化代码"));
	}

    void loadLeftDBTree() {
    
    
        TreeItem rootTreeItem = leftDBTree.getRoot();
        rootTreeItem.getChildren().clear();
        try {
    
    
            List<DatabaseConfig> dbConfigs = ConfigHelper.loadDatabaseConfig();
            for (DatabaseConfig dbConfig : dbConfigs) {
    
    
                TreeItem<String> treeItem = new TreeItem<>();
                treeItem.setValue(dbConfig.getName());
                ImageView dbImage = new ImageView("icons/computer.png");
                dbImage.setFitHeight(16);
                dbImage.setFitWidth(16);
                dbImage.setUserData(dbConfig);
                treeItem.setGraphic(dbImage);
                rootTreeItem.getChildren().add(treeItem);
            }
        } catch (Exception e) {
    
    
            _LOG.error("connect db failed, reason", e);
            AlertUtil.showErrorAlert(e.getMessage() + "\n" + ExceptionUtils.getStackTrace(e));
        }
    }

    @FXML
    public void chooseProjectFolder() {
    
    
        DirectoryChooser directoryChooser = new DirectoryChooser();
        File selectedFolder = directoryChooser.showDialog(getPrimaryStage());
        if (selectedFolder != null) {
    
    
            projectFolderField.setText(selectedFolder.getAbsolutePath());
        }
    }

    @FXML
    public void generateCode() {
    
    
        if (tableName == null) {
    
    
            AlertUtil.showWarnAlert("请先在左侧选择数据库表");
            return;
        }
        String result = validateConfig();
		if (result != null) {
    
    
			AlertUtil.showErrorAlert(result);
			return;
		}
        GeneratorConfig generatorConfig = getGeneratorConfigFromUI();
        if (!checkDirs(generatorConfig)) {
    
    
            return;
        }

        MybatisGeneratorBridge bridge = new MybatisGeneratorBridge();
        bridge.setGeneratorConfig(generatorConfig);
        bridge.setDatabaseConfig(selectedDatabaseConfig);
        bridge.setIgnoredColumns(ignoredColumns);
        bridge.setColumnOverrides(columnOverrides);
        UIProgressCallback alert = new UIProgressCallback(Alert.AlertType.INFORMATION);
        bridge.setProgressCallback(alert);
        alert.show();
        PictureProcessStateController pictureProcessStateController = null;
        try {
    
    
            //Engage PortForwarding
            Session sshSession = DbUtil.getSSHSession(selectedDatabaseConfig);
            DbUtil.engagePortForwarding(sshSession, selectedDatabaseConfig);

            if (sshSession != null) {
    
    
                pictureProcessStateController = new PictureProcessStateController();
                pictureProcessStateController.setDialogStage(getDialogStage());
                pictureProcessStateController.startPlay();
            }

            bridge.generate();

            if (pictureProcessStateController != null) {
    
    
                Task task = new Task<Void>() {
    
    
                    @Override
                    protected Void call() throws Exception {
    
    
                        Thread.sleep(3000);
                        return null;
                    }
                };
                PictureProcessStateController finalPictureProcessStateController = pictureProcessStateController;
                task.setOnSucceeded(event -> {
    
    
                    finalPictureProcessStateController.close();
                });
                task.setOnFailed(event -> {
    
    
                    finalPictureProcessStateController.close();
                });
                new Thread(task).start();
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
            AlertUtil.showErrorAlert(e.getMessage());
            if (pictureProcessStateController != null) {
    
    
                pictureProcessStateController.close();
                pictureProcessStateController.playFailState(e.getMessage(), true);
            }
        }
    }

	private String validateConfig() {
    
    
		String projectFolder = projectFolderField.getText();
		if (StringUtils.isEmpty(projectFolder))  {
    
    
			return "项目目录不能为空";
		}
		if (StringUtils.isEmpty(domainObjectNameField.getText()))  {
    
    
			return "类名不能为空";
		}
		if (StringUtils.isAnyEmpty(modelTargetPackage.getText(),
                mapperTargetPackage.getText(),
                daoTargetPackage.getText(),
                serviceTargetPackage.getText(),
                serviceImplTargetPackage.getText(),
                controllerTargetPackage.getText())) {
    
    
			return "包名不能为空";
		}
		return null;
	}

	@FXML
    public void saveGeneratorConfig() {
    
    
        TextInputDialog dialog = new TextInputDialog("");
        dialog.setTitle("保存当前配置");
        dialog.setContentText("请输入配置名称");
        Optional<String> result = dialog.showAndWait();
        if (result.isPresent()) {
    
    
            String name = result.get();
            if (StringUtils.isEmpty(name)) {
    
    
                AlertUtil.showErrorAlert("名称不能为空");
                return;
            }
            _LOG.info("user choose name: {}", name);
            try {
    
    
                GeneratorConfig generatorConfig = getGeneratorConfigFromUI();
                generatorConfig.setName(name);
                ConfigHelper.deleteGeneratorConfig(name);
                ConfigHelper.saveGeneratorConfig(generatorConfig);
            } catch (Exception e) {
    
    
                _LOG.error("保存配置失败", e);
                AlertUtil.showErrorAlert("保存配置失败");
            }
        }
    }

    public GeneratorConfig getGeneratorConfigFromUI() {
    
    
        GeneratorConfig generatorConfig = new GeneratorConfig();
        generatorConfig.setProjectFolder(projectFolderField.getText());
        generatorConfig.setModelPackage(modelTargetPackage.getText());
        generatorConfig.setServicePackage(serviceTargetPackage.getText());
        generatorConfig.setServiceImplPackage(serviceImplTargetPackage.getText());
        generatorConfig.setControllerPackage(controllerTargetPackage.getText());
        generatorConfig.setGenerateKeys(generateKeysField.getText());
        generatorConfig.setModelPackageTargetFolder(modelTargetProject.getText());
        generatorConfig.setServicePackageTargetFolder(serviceTargetProject.getText());
        generatorConfig.setServiceImplPackageTargetFolder(serviceImplTargetProject.getText());
        generatorConfig.setControllerPackageTargetFolder(controllerTargetProject.getText());
        generatorConfig.setDaoPackage(daoTargetPackage.getText());
        generatorConfig.setDaoTargetFolder(daoTargetProject.getText());
        generatorConfig.setMapperName(mapperName.getText());
        generatorConfig.setMappingXMLPackage(mapperTargetPackage.getText());
        generatorConfig.setMappingXMLTargetFolder(mappingTargetProject.getText());
        generatorConfig.setTableName(tableNameField.getText());
        generatorConfig.setDomainObjectName(domainObjectNameField.getText());
        generatorConfig.setOffsetLimit(offsetLimitCheckBox.isSelected());
        generatorConfig.setComment(commentCheckBox.isSelected());
        generatorConfig.setOverrideXML(overrideXML.isSelected());
        generatorConfig.setNeedToStringHashcodeEquals(needToStringHashcodeEquals.isSelected());
        generatorConfig.setUseLombokPlugin(useLombokPlugin.isSelected());
        generatorConfig.setUseTableNameAlias(useTableNameAliasCheckbox.isSelected());
        generatorConfig.setNeedForUpdate(forUpdateCheckBox.isSelected());
        generatorConfig.setAnnotationDAO(annotationDAOCheckBox.isSelected());
        generatorConfig.setAnnotationMapperDAO(annotationMapperDAOCheckBox.isSelected());
        generatorConfig.setAnnotation(annotationCheckBox.isSelected());
        generatorConfig.setUseActualColumnNames(useActualColumnNamesCheckbox.isSelected());
        generatorConfig.setEncoding(encodingChoice.getValue());
        generatorConfig.setUseExample(useExample.isSelected());
        generatorConfig.setUseDAOExtendStyle(useDAOExtendStyle.isSelected());
        generatorConfig.setUseSchemaPrefix(useSchemaPrefix.isSelected());
        generatorConfig.setJsr310Support(jsr310Support.isSelected());
        return generatorConfig;
    }

    public void setGeneratorConfigIntoUI(GeneratorConfig generatorConfig) {
    
    
        projectFolderField.setText(generatorConfig.getProjectFolder());
        generateKeysField.setText(generatorConfig.getGenerateKeys());
        modelTargetPackage.setText(generatorConfig.getModelPackage());
        modelTargetProject.setText(generatorConfig.getModelPackageTargetFolder());
        serviceTargetPackage.setText(generatorConfig.getServicePackage());
        serviceTargetProject.setText(generatorConfig.getServicePackageTargetFolder());
        serviceImplTargetPackage.setText(generatorConfig.getServiceImplPackage());
        serviceImplTargetProject.setText(generatorConfig.getServiceImplPackageTargetFolder());
        controllerTargetPackage.setText(generatorConfig.getControllerPackage());
        controllerTargetProject.setText(generatorConfig.getControllerPackageTargetFolder());
        daoTargetPackage.setText(generatorConfig.getDaoPackage());
		daoTargetProject.setText(generatorConfig.getDaoTargetFolder());
		mapperTargetPackage.setText(generatorConfig.getMappingXMLPackage());
        mappingTargetProject.setText(generatorConfig.getMappingXMLTargetFolder());
        if (StringUtils.isBlank(tableNameField.getText())) {
    
    
            tableNameField.setText(generatorConfig.getTableName());
            mapperName.setText(generatorConfig.getMapperName());
            domainObjectNameField.setText(generatorConfig.getDomainObjectName());
        }
        offsetLimitCheckBox.setSelected(generatorConfig.isOffsetLimit());
        commentCheckBox.setSelected(generatorConfig.isComment());
        overrideXML.setSelected(generatorConfig.isOverrideXML());
        needToStringHashcodeEquals.setSelected(generatorConfig.isNeedToStringHashcodeEquals());
        useLombokPlugin.setSelected(generatorConfig.isUseLombokPlugin());
        useTableNameAliasCheckbox.setSelected(generatorConfig.getUseTableNameAlias());
        forUpdateCheckBox.setSelected(generatorConfig.isNeedForUpdate());
        annotationDAOCheckBox.setSelected(generatorConfig.isAnnotationDAO());
        annotationCheckBox.setSelected(generatorConfig.isAnnotation());
        useActualColumnNamesCheckbox.setSelected(generatorConfig.isUseActualColumnNames());
        encodingChoice.setValue(generatorConfig.getEncoding());
        useExample.setSelected(generatorConfig.isUseExample());
        useDAOExtendStyle.setSelected(generatorConfig.isUseDAOExtendStyle());
        useSchemaPrefix.setSelected(generatorConfig.isUseSchemaPrefix());
        jsr310Support.setSelected(generatorConfig.isJsr310Support());
    }

    @FXML
    public void openTableColumnCustomizationPage() {
    
    
        if (tableName == null) {
    
    
            AlertUtil.showWarnAlert("请先在左侧选择数据库表");
            return;
        }
        SelectTableColumnController controller = (SelectTableColumnController) loadFXMLPage("定制列", FXMLPage.SELECT_TABLE_COLUMN, true);
        controller.setMainUIController(this);
        try {
    
    
            // If select same schema and another table, update table data
            if (!tableName.equals(controller.getTableName())) {
    
    
                List<UITableColumnVO> tableColumns = DbUtil.getTableColumns(selectedDatabaseConfig, tableName);
                controller.setColumnList(FXCollections.observableList(tableColumns));
                controller.setTableName(tableName);
            }
            controller.showDialogStage();
        } catch (Exception e) {
    
    
            _LOG.error(e.getMessage(), e);
            AlertUtil.showErrorAlert(e.getMessage());
        }
    }

    public void setIgnoredColumns(List<IgnoredColumn> ignoredColumns) {
    
    
        this.ignoredColumns = ignoredColumns;
    }

    public void setColumnOverrides(List<ColumnOverride> columnOverrides) {
    
    
        this.columnOverrides = columnOverrides;
    }

    /**
     * 检查并创建不存在的文件夹
     *
     * @return
     */
    private boolean checkDirs(GeneratorConfig config) {
    
    
		List<String> dirs = new ArrayList<>();
		dirs.add(config.getProjectFolder());
		dirs.add(config.getProjectFolder().concat("/").concat(config.getModelPackageTargetFolder()));
		dirs.add(config.getProjectFolder().concat("/").concat(config.getDaoTargetFolder()));
		dirs.add(config.getProjectFolder().concat("/").concat(config.getMappingXMLTargetFolder()));
		boolean haveNotExistFolder = false;
		for (String dir : dirs) {
    
    
			File file = new File(dir);
			if (!file.exists()) {
    
    
				haveNotExistFolder = true;
			}
		}
		if (haveNotExistFolder) {
    
    
			Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
			alert.setContentText(FOLDER_NO_EXIST);
			Optional<ButtonType> optional = alert.showAndWait();
			if (optional.isPresent()) {
    
    
				if (ButtonType.OK == optional.get()) {
    
    
					try {
    
    
						for (String dir : dirs) {
    
    
							FileUtils.forceMkdir(new File(dir));
						}
						return true;
					} catch (Exception e) {
    
    
						AlertUtil.showErrorAlert("创建目录失败,请检查目录是否是文件而非目录");
					}
				} else {
    
    
					return false;
				}
			}
		}
        return true;
    }

    @FXML
    public void openTargetFolder() {
    
    
        GeneratorConfig generatorConfig = getGeneratorConfigFromUI();
        String projectFolder = generatorConfig.getProjectFolder();
        try {
    
    
            Desktop.getDesktop().browse(new File(projectFolder).toURI());
        }catch (Exception e) {
    
    
            AlertUtil.showErrorAlert("打开目录失败,请检查目录是否填写正确" + e.getMessage());
        }

    }
}



4. Add GeneratorConfig function


package com.zzg.mybatis.generator.model;


public class GeneratorConfig {
    
    

	/**
	 * 本配置的名称
	 */
	private String name;

	private String connectorJarPath;

	private String projectFolder;

	private String modelPackage;

	private String modelPackageTargetFolder;

	private String servicePackage;

	private String servicePackageTargetFolder;

	private String serviceImplPackage;

	private String serviceImplPackageTargetFolder;

	private String controllerPackage;

	private String controllerPackageTargetFolder;

	private String daoPackage;

	private String daoTargetFolder;

	private String mapperName;

	private String mappingXMLPackage;

	private String mappingXMLTargetFolder;

	private String tableName;

	private String domainObjectName;

	private boolean offsetLimit;

	private boolean comment;

	private boolean overrideXML;

	private boolean needToStringHashcodeEquals;

	private boolean useLombokPlugin;

	private boolean needForUpdate;

	private boolean annotationDAO;

	private boolean annotationMapperDAO;

	private boolean annotation;

	private boolean useActualColumnNames;

	private boolean useExample;

	private String generateKeys;

	private String encoding;

	private boolean useTableNameAlias;

	private boolean useDAOExtendStyle;

    private boolean useSchemaPrefix;

    private boolean jsr310Support;

    public boolean isJsr310Support() {
    
    
        return jsr310Support;
    }

    public void setJsr310Support(boolean jsr310Support) {
    
    
        this.jsr310Support = jsr310Support;
    }

    public boolean isUseSchemaPrefix() {
    
    
        return useSchemaPrefix;
    }

    public void setUseSchemaPrefix(boolean useSchemaPrefix) {
    
    
        this.useSchemaPrefix = useSchemaPrefix;
    }

	public boolean isUseExample() {
    
    
		return useExample;
	}

	public void setUseExample(boolean useExample) {
    
    
		this.useExample = useExample;
	}

	public String getName() {
    
    
		return name;
	}

	public void setName(String name) {
    
    
		this.name = name;
	}

	public String getTableName() {
    
    
		return tableName;
	}

	public void setTableName(String tableName) {
    
    
		this.tableName = tableName;
	}

	public String getDomainObjectName() {
    
    
		return domainObjectName;
	}

	public void setDomainObjectName(String domainObjectName) {
    
    
		this.domainObjectName = domainObjectName;
	}

	public String getConnectorJarPath() {
    
    
		return connectorJarPath;
	}

	public void setConnectorJarPath(String connectorJarPath) {
    
    
		this.connectorJarPath = connectorJarPath;
	}

	public String getProjectFolder() {
    
    
		return projectFolder;
	}

	public void setProjectFolder(String projectFolder) {
    
    
		this.projectFolder = projectFolder;
	}

	public String getModelPackage() {
    
    
		return modelPackage;
	}

	public void setModelPackage(String modelPackage) {
    
    
		this.modelPackage = modelPackage;
	}

	public String getModelPackageTargetFolder() {
    
    
		return modelPackageTargetFolder;
	}

	public void setModelPackageTargetFolder(String modelPackageTargetFolder) {
    
    
		this.modelPackageTargetFolder = modelPackageTargetFolder;
	}

	public String getServicePackage() {
    
    
		return servicePackage;
	}

	public void setServicePackage(String servicePackage) {
    
    
		this.servicePackage = servicePackage;
	}

	public String getServicePackageTargetFolder() {
    
    
		return servicePackageTargetFolder;
	}

	public void setServicePackageTargetFolder(String servicePackageTargetFolder) {
    
    
		this.servicePackageTargetFolder = servicePackageTargetFolder;
	}

	public String getServiceImplPackage() {
    
    
		return serviceImplPackage;
	}

	public void setServiceImplPackage(String serviceImplPackage) {
    
    
		this.serviceImplPackage = serviceImplPackage;
	}

	public String getServiceImplPackageTargetFolder() {
    
    
		return serviceImplPackageTargetFolder;
	}

	public void setServiceImplPackageTargetFolder(String serviceImplPackageTargetFolder) {
    
    
		this.serviceImplPackageTargetFolder = serviceImplPackageTargetFolder;
	}

	public String getControllerPackage() {
    
    
		return controllerPackage;
	}

	public void setControllerPackage(String controllerPackage) {
    
    
		this.controllerPackage = controllerPackage;
	}

	public String getControllerPackageTargetFolder() {
    
    
		return controllerPackageTargetFolder;
	}

	public void setControllerPackageTargetFolder(String controllerPackageTargetFolder) {
    
    
		this.controllerPackageTargetFolder = controllerPackageTargetFolder;
	}

	public String getDaoPackage() {
    
    
		return daoPackage;
	}

	public void setDaoPackage(String daoPackage) {
    
    
		this.daoPackage = daoPackage;
	}

	public String getDaoTargetFolder() {
    
    
		return daoTargetFolder;
	}

	public void setDaoTargetFolder(String daoTargetFolder) {
    
    
		this.daoTargetFolder = daoTargetFolder;
	}

	public String getMappingXMLPackage() {
    
    
		return mappingXMLPackage;
	}

	public void setMappingXMLPackage(String mappingXMLPackage) {
    
    
		this.mappingXMLPackage = mappingXMLPackage;
	}

	public String getMappingXMLTargetFolder() {
    
    
		return mappingXMLTargetFolder;
	}

	public void setMappingXMLTargetFolder(String mappingXMLTargetFolder) {
    
    
		this.mappingXMLTargetFolder = mappingXMLTargetFolder;
	}

	public boolean isOffsetLimit() {
    
    
		return offsetLimit;
	}

	public void setOffsetLimit(boolean offsetLimit) {
    
    
		this.offsetLimit = offsetLimit;
	}

	public boolean isComment() {
    
    
		return comment;
	}

	public void setComment(boolean comment) {
    
    
		this.comment = comment;
	}

    public boolean isNeedToStringHashcodeEquals() {
    
    
        return needToStringHashcodeEquals;
    }

    public void setNeedToStringHashcodeEquals(boolean needToStringHashcodeEquals) {
    
    
        this.needToStringHashcodeEquals = needToStringHashcodeEquals;
    }

	public boolean isUseLombokPlugin() {
    
    
		return useLombokPlugin;
	}

	public void setUseLombokPlugin(boolean useLombokPlugin) {
    
    
		this.useLombokPlugin = useLombokPlugin;
	}

	public boolean isNeedForUpdate() {
    
    
		return needForUpdate;
	}

	public void setNeedForUpdate(boolean needForUpdate) {
    
    
		this.needForUpdate = needForUpdate;
	}

	public boolean isAnnotationDAO() {
    
    
		return annotationDAO;
	}

	public void setAnnotationDAO(boolean annotationDAO) {
    
    
		this.annotationDAO = annotationDAO;
	}

	public boolean isAnnotationMapperDAO() {
    
    
		return annotationMapperDAO;
	}

	public void setAnnotationMapperDAO(boolean annotationMapperDAO) {
    
    
		this.annotationMapperDAO = annotationMapperDAO;
	}

	public boolean isAnnotation() {
    
    
		return annotation;
	}

	public void setAnnotation(boolean annotation) {
    
    
		this.annotation = annotation;
	}

	public boolean isUseActualColumnNames() {
    
    
		return useActualColumnNames;
	}

	public void setUseActualColumnNames(boolean useActualColumnNames) {
    
    
		this.useActualColumnNames = useActualColumnNames;
	}

	public String getMapperName() {
    
    
		return mapperName;
	}

	public void setMapperName(String mapperName) {
    
    
		this.mapperName = mapperName;
	}

	public String getGenerateKeys() {
    
    
		return generateKeys;
	}

	public void setGenerateKeys(String generateKeys) {
    
    
		this.generateKeys = generateKeys;
	}

    public String getEncoding() {
    
    
        return encoding;
    }

    public void setEncoding(String encoding) {
    
    
        this.encoding = encoding;
    }

	public boolean getUseTableNameAlias() {
    
    
		return useTableNameAlias;
	}

	public void setUseTableNameAlias(boolean useTableNameAlias) {
    
    
		this.useTableNameAlias = useTableNameAlias;
	}

	public boolean isUseTableNameAlias() {
    
    
		return useTableNameAlias;
	}

	public boolean isOverrideXML() {
    
    
		return overrideXML;
	}

	public void setOverrideXML(boolean overrideXML) {
    
    
		this.overrideXML = overrideXML;
	}

	public void setUseDAOExtendStyle(boolean useDAOExtendStyle) {
    
    
		this.useDAOExtendStyle = useDAOExtendStyle;
	}

	public boolean isUseDAOExtendStyle() {
    
    
		return useDAOExtendStyle;
	}
}



5. Add PluginConfiguration configuration.

Insert image description here

package com.zzg.mybatis.generator.bridge;

import com.jcraft.jsch.Session;
import com.zzg.mybatis.generator.controller.PictureProcessStateController;
import com.zzg.mybatis.generator.model.DatabaseConfig;
import com.zzg.mybatis.generator.model.DbType;
import com.zzg.mybatis.generator.model.GeneratorConfig;
import com.zzg.mybatis.generator.plugins.DbRemarksCommentGenerator;
import com.zzg.mybatis.generator.plugins.ServiceAndControllerGeneratorPlugin;
import com.zzg.mybatis.generator.util.ConfigHelper;
import com.zzg.mybatis.generator.util.DbUtil;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.api.ProgressCallback;
import org.mybatis.generator.api.ShellCallback;
import org.mybatis.generator.config.*;
import org.mybatis.generator.internal.DefaultShellCallback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


public class MybatisGeneratorBridge {
    
    

	private static final Logger _LOG = LoggerFactory.getLogger(MybatisGeneratorBridge.class);

    private GeneratorConfig generatorConfig;

    private DatabaseConfig selectedDatabaseConfig;

    private ProgressCallback progressCallback;

    private List<IgnoredColumn> ignoredColumns;

    private List<ColumnOverride> columnOverrides;

    public MybatisGeneratorBridge() {
    
    
    }

    public void setGeneratorConfig(GeneratorConfig generatorConfig) {
    
    
        this.generatorConfig = generatorConfig;
    }

    public void setDatabaseConfig(DatabaseConfig databaseConfig) {
    
    
        this.selectedDatabaseConfig = databaseConfig;
    }

    public void generate() throws Exception {
    
    
        Configuration configuration = new Configuration();
        Context context = new Context(ModelType.CONDITIONAL);
        configuration.addContext(context);
		
        context.addProperty("javaFileEncoding", "UTF-8");
        
		String dbType = selectedDatabaseConfig.getDbType();
		String connectorLibPath = ConfigHelper.findConnectorLibPath(dbType);
	    _LOG.info("connectorLibPath: {}", connectorLibPath);
	    configuration.addClasspathEntry(connectorLibPath);
        // Table configuration
        TableConfiguration tableConfig = new TableConfiguration(context);
        tableConfig.setTableName(generatorConfig.getTableName());
        tableConfig.setDomainObjectName(generatorConfig.getDomainObjectName());
        if(!generatorConfig.isUseExample()) {
    
    
            tableConfig.setUpdateByExampleStatementEnabled(false);
            tableConfig.setCountByExampleStatementEnabled(false);
            tableConfig.setDeleteByExampleStatementEnabled(false);
            tableConfig.setSelectByExampleStatementEnabled(false);
        }

		context.addProperty("autoDelimitKeywords", "true");
		if (DbType.MySQL.name().equals(dbType) || DbType.MySQL_8.name().equals(dbType)) {
    
    
			tableConfig.setSchema(selectedDatabaseConfig.getSchema());
			// 由于beginningDelimiter和endingDelimiter的默认值为双引号("),在Mysql中不能这么写,所以还要将这两个默认值改为`
			context.addProperty("beginningDelimiter", "`");
			context.addProperty("endingDelimiter", "`");
		} else {
    
    
            tableConfig.setCatalog(selectedDatabaseConfig.getSchema());
	    }
        if (generatorConfig.isUseSchemaPrefix()) {
    
    
            if (DbType.MySQL.name().equals(dbType) || DbType.MySQL_8.name().equals(dbType)) {
    
    
                tableConfig.setSchema(selectedDatabaseConfig.getSchema());
            } else if (DbType.Oracle.name().equals(dbType)) {
    
    
                //Oracle的schema为用户名,如果连接用户拥有dba等高级权限,若不设schema,会导致把其他用户下同名的表也生成一遍导致中代码重复
                tableConfig.setSchema(selectedDatabaseConfig.getUsername());
            } else {
    
    
                tableConfig.setCatalog(selectedDatabaseConfig.getSchema());
            }
        }
        // 针对 postgresql 单独配置
		if (DbType.PostgreSQL.name().equals(dbType)) {
    
    
            tableConfig.setDelimitIdentifiers(true);
        }

        //添加GeneratedKey主键生成
		if (StringUtils.isNotEmpty(generatorConfig.getGenerateKeys())) {
    
    
            String dbType2 = dbType;
            if (DbType.MySQL.name().equals(dbType2) || DbType.MySQL_8.name().equals(dbType)) {
    
    
                dbType2 = "JDBC";
                //dbType为JDBC,且配置中开启useGeneratedKeys时,Mybatis会使用Jdbc3KeyGenerator,
                //使用该KeyGenerator的好处就是直接在一次INSERT 语句内,通过resultSet获取得到 生成的主键值,
                //并很好的支持设置了读写分离代理的数据库
                //例如阿里云RDS + 读写分离代理
                //无需指定主库
                //当使用SelectKey时,Mybatis会使用SelectKeyGenerator,INSERT之后,多发送一次查询语句,获得主键值
                //在上述读写分离被代理的情况下,会得不到正确的主键
            }
			tableConfig.setGeneratedKey(new GeneratedKey(generatorConfig.getGenerateKeys(), dbType2, true, null));
		}

        if (generatorConfig.getMapperName() != null) {
    
    
            tableConfig.setMapperName(generatorConfig.getMapperName());
        }
        // add ignore columns
        if (ignoredColumns != null) {
    
    
            ignoredColumns.forEach(tableConfig::addIgnoredColumn);
        }
        if (columnOverrides != null) {
    
    
            columnOverrides.forEach(tableConfig::addColumnOverride);
        }
        if (generatorConfig.isUseActualColumnNames()) {
    
    
			tableConfig.addProperty("useActualColumnNames", "true");
        }

		if(generatorConfig.isUseTableNameAlias()){
    
    
            tableConfig.setAlias(generatorConfig.getTableName());
        }

        JDBCConnectionConfiguration jdbcConfig = new JDBCConnectionConfiguration();
        if (DbType.MySQL.name().equals(dbType) || DbType.MySQL_8.name().equals(dbType)) {
    
    
	        jdbcConfig.addProperty("nullCatalogMeansCurrent", "true");
	        // useInformationSchema可以拿到表注释,从而生成类注释可以使用表的注释
	        jdbcConfig.addProperty("useInformationSchema", "true");
        }
        jdbcConfig.setDriverClass(DbType.valueOf(dbType).getDriverClass());
        jdbcConfig.setConnectionURL(DbUtil.getConnectionUrlWithSchema(selectedDatabaseConfig));
        jdbcConfig.setUserId(selectedDatabaseConfig.getUsername());
        jdbcConfig.setPassword(selectedDatabaseConfig.getPassword());
        if(DbType.Oracle.name().equals(dbType)){
    
    
            jdbcConfig.getProperties().setProperty("remarksReporting", "true");
        }

        // java model
        JavaModelGeneratorConfiguration modelConfig = new JavaModelGeneratorConfiguration();
        modelConfig.setTargetPackage(generatorConfig.getModelPackage());
        modelConfig.setTargetProject(generatorConfig.getProjectFolder() + "/" + generatorConfig.getModelPackageTargetFolder());
        // Mapper configuration
        SqlMapGeneratorConfiguration mapperConfig = new SqlMapGeneratorConfiguration();
        mapperConfig.setTargetPackage(generatorConfig.getMappingXMLPackage());
        mapperConfig.setTargetProject(generatorConfig.getProjectFolder() + "/" + generatorConfig.getMappingXMLTargetFolder());
        // DAO
        JavaClientGeneratorConfiguration daoConfig = new JavaClientGeneratorConfiguration();
        daoConfig.setConfigurationType("XMLMAPPER");
        daoConfig.setTargetPackage(generatorConfig.getDaoPackage());
        daoConfig.setTargetProject(generatorConfig.getProjectFolder() + "/" + generatorConfig.getDaoTargetFolder());


        // java service、service impl 、controller
        PluginConfiguration serviceAndControllerConfig = new PluginConfiguration();
        serviceAndControllerConfig.addProperty("type", "com.zzg.mybatis.generator.plugins.ServiceAndControllerGeneratorPlugin");
        //serviceAndControllerConfig.addProperty("targetProject", generatorConfig.getProjectFolder()+"/src/main/java");
        serviceAndControllerConfig.addProperty("serviceTargetProject", generatorConfig.getProjectFolder() + "/" + generatorConfig.getServicePackageTargetFolder());
        serviceAndControllerConfig.addProperty("serviceImplTargetProject", generatorConfig.getProjectFolder() + "/" + generatorConfig.getServiceImplPackageTargetFolder());
        serviceAndControllerConfig.addProperty("controllerTargetProject", generatorConfig.getProjectFolder() + "/" + generatorConfig.getControllerPackageTargetFolder());
        serviceAndControllerConfig.addProperty("servicePackage", "com.example.service");
        serviceAndControllerConfig.addProperty("serviceImplPackage", "com.example.service.impl");
        serviceAndControllerConfig.addProperty("controllerPackage", "com.example.controller");
        serviceAndControllerConfig.addProperty("serviceSuffix", "Service");
        serviceAndControllerConfig.addProperty("superServiceInterface", "org.aurochsframework.boot.commons.service.GeneralService");
        serviceAndControllerConfig.addProperty("superServiceImpl", "org.aurochsframework.boot.commons.service.AbstractGeneralService");
        serviceAndControllerConfig.addProperty("superController", "org.aurochsframework.boot.commons.controller.GeneralCrudController");
        serviceAndControllerConfig.setConfigurationType("com.zzg.mybatis.generator.plugins.ServiceAndControllerGeneratorPlugin");
        context.addPluginConfiguration(serviceAndControllerConfig);


        context.setId("myid");
        context.addTableConfiguration(tableConfig);
        context.setJdbcConnectionConfiguration(jdbcConfig);
        context.setJavaModelGeneratorConfiguration(modelConfig);
        context.setSqlMapGeneratorConfiguration(mapperConfig);
        context.setJavaClientGeneratorConfiguration(daoConfig);

        // Comment
        CommentGeneratorConfiguration commentConfig = new CommentGeneratorConfiguration();
        commentConfig.setConfigurationType(DbRemarksCommentGenerator.class.getName());
        if (generatorConfig.isComment()) {
    
    
            commentConfig.addProperty("columnRemarks", "true");
        }
        if (generatorConfig.isAnnotation()) {
    
    
            commentConfig.addProperty("annotations", "true");
        }
        context.setCommentGeneratorConfiguration(commentConfig);
        // set java file encoding
        context.addProperty(PropertyRegistry.CONTEXT_JAVA_FILE_ENCODING, generatorConfig.getEncoding());

        //实体添加序列化
        PluginConfiguration serializablePluginConfiguration = new PluginConfiguration();
        serializablePluginConfiguration.addProperty("type", "org.mybatis.generator.plugins.SerializablePlugin");
        serializablePluginConfiguration.setConfigurationType("org.mybatis.generator.plugins.SerializablePlugin");
        context.addPluginConfiguration(serializablePluginConfiguration);

        // Lombok 插件
        if (generatorConfig.isUseLombokPlugin()) {
    
    
            PluginConfiguration pluginConfiguration = new PluginConfiguration();
            pluginConfiguration.addProperty("type", "com.softwareloop.mybatis.generator.plugins.LombokPlugin");
            pluginConfiguration.setConfigurationType("com.softwareloop.mybatis.generator.plugins.LombokPlugin");
            context.addPluginConfiguration(pluginConfiguration);
        }
        // toString, hashCode, equals插件
        else if (generatorConfig.isNeedToStringHashcodeEquals()) {
    
    
            PluginConfiguration pluginConfiguration1 = new PluginConfiguration();
            pluginConfiguration1.addProperty("type", "org.mybatis.generator.plugins.EqualsHashCodePlugin");
            pluginConfiguration1.setConfigurationType("org.mybatis.generator.plugins.EqualsHashCodePlugin");
            context.addPluginConfiguration(pluginConfiguration1);
            PluginConfiguration pluginConfiguration2 = new PluginConfiguration();
            pluginConfiguration2.addProperty("type", "org.mybatis.generator.plugins.ToStringPlugin");
            pluginConfiguration2.setConfigurationType("org.mybatis.generator.plugins.ToStringPlugin");
            context.addPluginConfiguration(pluginConfiguration2);
        }
        // limit/offset插件
        if (generatorConfig.isOffsetLimit()) {
    
    
            if (DbType.MySQL.name().equals(dbType) || DbType.MySQL_8.name().equals(dbType)
		            || DbType.PostgreSQL.name().equals(dbType)) {
    
    
                PluginConfiguration pluginConfiguration = new PluginConfiguration();
                pluginConfiguration.addProperty("type", "com.zzg.mybatis.generator.plugins.MySQLLimitPlugin");
                pluginConfiguration.setConfigurationType("com.zzg.mybatis.generator.plugins.MySQLLimitPlugin");
                context.addPluginConfiguration(pluginConfiguration);
            }
        }
        //for JSR310
        if (generatorConfig.isJsr310Support()) {
    
    
            JavaTypeResolverConfiguration javaTypeResolverConfiguration = new JavaTypeResolverConfiguration();
            javaTypeResolverConfiguration.setConfigurationType("com.zzg.mybatis.generator.plugins.JavaTypeResolverJsr310Impl");
            context.setJavaTypeResolverConfiguration(javaTypeResolverConfiguration);
        }
        //forUpdate 插件
        if(generatorConfig.isNeedForUpdate()) {
    
    
            if (DbType.MySQL.name().equals(dbType)
                    || DbType.PostgreSQL.name().equals(dbType) || DbType.Oracle.name().equals(dbType)) {
    
    
                PluginConfiguration pluginConfiguration = new PluginConfiguration();
                pluginConfiguration.addProperty("type", "com.zzg.mybatis.generator.plugins.MySQLForUpdatePlugin");
                pluginConfiguration.setConfigurationType("com.zzg.mybatis.generator.plugins.MySQLForUpdatePlugin");
                context.addPluginConfiguration(pluginConfiguration);
            }
        }
        //repository 插件
        if(generatorConfig.isAnnotationDAO()) {
    
    
            if (DbType.MySQL.name().equals(dbType) || DbType.MySQL_8.name().equals(dbType)
                    || DbType.PostgreSQL.name().equals(dbType) || DbType.Oracle.name().equals(dbType)) {
    
    
                PluginConfiguration pluginConfiguration = new PluginConfiguration();
                pluginConfiguration.addProperty("type", "com.zzg.mybatis.generator.plugins.RepositoryPlugin");
                pluginConfiguration.setConfigurationType("com.zzg.mybatis.generator.plugins.RepositoryPlugin");
                context.addPluginConfiguration(pluginConfiguration);
            }
        }
        //mapper 插件
        if(generatorConfig.isAnnotationMapperDAO()) {
    
    
            if (DbType.MySQL.name().equals(dbType) || DbType.MySQL_8.name().equals(dbType)
                    || DbType.PostgreSQL.name().equals(dbType) || DbType.Oracle.name().equals(dbType)) {
    
    
                PluginConfiguration pluginConfiguration = new PluginConfiguration();
                pluginConfiguration.addProperty("type", "com.zzg.mybatis.generator.plugins.MapperPlugin");
                pluginConfiguration.setConfigurationType("com.zzg.mybatis.generator.plugins.MapperPlugin");
                context.addPluginConfiguration(pluginConfiguration);
            }
        }

        if (generatorConfig.isUseDAOExtendStyle()) {
    
    
            if (DbType.MySQL.name().equals(dbType) || DbType.MySQL_8.name().equals(dbType)
                    || DbType.PostgreSQL.name().equals(dbType) || DbType.Oracle.name().equals(dbType)) {
    
    
                PluginConfiguration pluginConfiguration = new PluginConfiguration();
				pluginConfiguration.addProperty("useExample", String.valueOf(generatorConfig.isUseExample()));
				pluginConfiguration.addProperty("type", "com.zzg.mybatis.generator.plugins.CommonDAOInterfacePlugin");
                pluginConfiguration.setConfigurationType("com.zzg.mybatis.generator.plugins.CommonDAOInterfacePlugin");
                context.addPluginConfiguration(pluginConfiguration);
            }
        }

        context.setTargetRuntime("MyBatis3");

        List<String> warnings = new ArrayList<>();
        Set<String> fullyqualifiedTables = new HashSet<>();
        Set<String> contexts = new HashSet<>();
        ShellCallback shellCallback = new DefaultShellCallback(true); // override=true
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(configuration, shellCallback, warnings);
        // if overrideXML selected, delete oldXML ang generate new one
		if (generatorConfig.isOverrideXML()) {
    
    
			String mappingXMLFilePath = getMappingXMLFilePath(generatorConfig);
			File mappingXMLFile = new File(mappingXMLFilePath);
			if (mappingXMLFile.exists()) {
    
    
				mappingXMLFile.delete();
			}
		}
        myBatisGenerator.generate(progressCallback, contexts, fullyqualifiedTables);
    }

    private String getMappingXMLFilePath(GeneratorConfig generatorConfig) {
    
    
		StringBuilder sb = new StringBuilder();
		sb.append(generatorConfig.getProjectFolder()).append("/");
		sb.append(generatorConfig.getMappingXMLTargetFolder()).append("/");
		String mappingXMLPackage = generatorConfig.getMappingXMLPackage();
		if (StringUtils.isNotEmpty(mappingXMLPackage)) {
    
    
			sb.append(mappingXMLPackage.replace(".", "/")).append("/");
		}
		if (StringUtils.isNotEmpty(generatorConfig.getMapperName())) {
    
    
			sb.append(generatorConfig.getMapperName()).append(".xml");
		} else {
    
    
			sb.append(generatorConfig.getDomainObjectName()).append("Mapper.xml");
		}

		return sb.toString();
	}

	public void setProgressCallback(ProgressCallback progressCallback) {
    
    
        this.progressCallback = progressCallback;
    }

    public void setIgnoredColumns(List<IgnoredColumn> ignoredColumns) {
    
    
        this.ignoredColumns = ignoredColumns;
    }

    public void setColumnOverrides(List<ColumnOverride> columnOverrides) {
    
    
        this.columnOverrides = columnOverrides;
    }
}

6. Operation and test results

Insert image description here
Insert image description here

The whole text is finished everywhere

Guess you like

Origin blog.csdn.net/GoodburghCottage/article/details/133345298