MyBatis Generator 代码自动生成器

news2024/12/26 22:41:41

一、什么是逆向工程

Mybatis的逆向工程就是由代码生成器生成我们需要的代码和映射文件。我们在编写Mybatis程序时,基本都是围绕着pojo类,Mapper接口,Mapper.xml文件等文件来进行的。如果实际开发中数据库的表特别多,那么我们需要手动去写每一张表的pojo类,Mapper接口,Mapper.xml文件,这显然需要花费巨大的精力,而且可能由于表字段太多,哪里写错了都难以排除。所以我们在实际开发中,一般使用逆向工程方式来自动生成所需的文件,这也是企业中一种非常常见的方法。

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

在这里插入图片描述

1、MGB简介

官方文档 : http://mybatis.org/generator/
逆向工程包的下载地址: https://github.com/mybatis/generator/releases/tag/mybatis-generator-1.3.2

(1)MyBatis Generator:即MBG

(2)MBG是一个专门为MyBatis框架使用者定制的代码生成器

(3)MBG可以快速的根据表生成对应的映射文件、接口、以及bean类

(4)只可以生成单表CRUD,但是表连接、存储过程等这些复杂sql的定义需要我们手工编写

2、编写MBG的配置文件mbg.xml(重要几处配置)

相应的配置文件在官方文档中,可以找到

在这里插入图片描述

向下滑动

在这里插入图片描述在这里插入图片描述
上述配置文件是官方给出的示例配置文件,之后将其中相关部分改为和自己模块匹配的内容

3、运行程序(代码生成器)

在这里插入图片描述

二、逆向工程生成代码

①、首先创建maven项目

1、项目整体目录:

在这里插入图片描述

2、导入maven依赖:


<!-- 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>

②、创建日志文件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

③、创建generatorConfig.xml配置文件


<?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; 这里传上来页面自动给转成了 &。

在这里插入图片描述
还有就是不同的数据库中不能含有相同的表,例如数据库A有t_user表,数据库B也有t_user表,那么到时候代码不知道生成哪个,而我恰好生成的是我们不需要的那个。啊?你说上面不是指定了数据库吗,怎么会到读取到其它数据库的表,不好意思,我试了不下十遍,最后我把其它数据库同名的表删除才成功的。如果你没有这种情况那更好咯。

④、创建逆向工程核心生成代码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();
        }
    }
 
}

⑤、运行逆向工程核心生成代码

运行上面的程序,如果控制台打印了如下日志,说明生成代码成功了。

在这里插入图片描述
然后我们再看项目就会发现生成了如下文件:

在这里插入图片描述

三、逆向工程举例

首先我们将上面生成的文件复制到目标项目中。在使用逆向工程举例之前,先来介绍生成的文件有哪些东西:

(1)、TUserMapper接口生成的方法介绍:

在这里插入图片描述在这里插入图片描述

  1. long countByExample(TUserExample example):按条件计数
  2. int deleteByExample(TUserExample example):按条件删除
  3. int deleteByPrimaryKey(Integer id):按主键删除
  4. int insert(TUser record):插入数据(返回值为ID)
  5. int insertSelective(TUser record):插入数据,只插入值不为null的字段,内部动态sql判断
  6. List selectByExample(TUserExample example):按条件查询,传入null表示查询所有
  7. TUser selectByPrimaryKey(Integer id):按主键查询
  8. int updateByExampleSelective(@Param(“record”) TUser record, @Param(“example”) TUserExample example):按条件更新值不为null的字段
  9. int updateByExample(@Param(“record”) TUser record, @Param(“example”) TUserExample example):按条件更新
  10. int updateByPrimaryKeySelective(TUser record):按主键更新值不为null的字段
  11. int updateByPrimaryKey(TUser record):按主键更新

测试不带条件的方法:


//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)、TUserExample条件扩展类介绍:

上面的测试方法是不带条件的操作,那么接下来学习一下按条件如何进行增删改查操作,我们在逆向工程中已经生成了这个类TUserExample,这个类就是一个条件扩展类,里面定义了一系列方法用来做条件,比如:排序、去重、大于、小于、等于、模糊查询、数据在某某之间等等。

我们在TUserExample类中可以看到定义了一个内部类GeneratedCriteria,这个内部类就定义了一系列条件的方法,这些条件最后都会拼接在SQL中,但是我们一般不用它,都用它的子类Criteria来进行操作,Criteria继承了内部类GeneratedCriteria。

在这里插入图片描述
简单举例:


//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?"删除成功":"删除失败");
    }
}

至此Mybatis的逆向工程就全部介绍完成了,说难也不是特别难,只要一步步自己去实现,去理解一遍,是非常简单的,可能复杂一点的是那个XxxExample类,但如果自己多举几个例子也不难。

四、逆向工程代码扩展

问:MyBatis Generator 为什么不生成 service 层和 controller 层 ?
答:mybatis 是持久层框架。

①、自定义注释生成器

1、创建自定义注释生成器 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、添加 generatorConfig.xml 配置

<?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>

②、自定义Controller和Service插件

1、自定义生成Controller和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、添加 generatorConfig.xml 配置


<?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是基于mybatis generator开发的一款界面工具,该工具可以使你非常容易及快速生成Mybatis的Java POJO文件及数据库Mapping文件。官方提供的xml配置非常灵活,对于熟悉的同学可能更加喜欢,这个工具对于新手来说可以更加容易上手。

① 、核心特性

1、按照界面步骤轻松生成代码,省去XML繁琐的学习与配置过程

2、保存数据库连接与Generator配置,每次代码生成轻松搞定

3、内置常用插件,比如offset分页 、可选的去除掉对版本管理不友好的注释,这样新增或删除字段重新生成的文件比较过来清楚

4、目前已经支持Mysql、Oracle与PostgreSQL

下载地址: https://github.com 搜索 mybatis-generator-gui 随便下载一个就可以了
也可以上 gitee 、 gitcode 下载

② 、下载代码并编译


# 下载代码
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

③ 、界面效果

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

④ 、项目整体目录:

在这里插入图片描述
在这里插入图片描述

⑤ 、MyBatis Generator 逆向工程代码扩展

这里我们主要讲的还是 关于第四章 MyBatis Generator 的逆向工程代码扩展,在MyBatis Generator gui 要怎么写,因为这里没有 generatorConfig.xml 配置 了
至于 其他的知识,比如Java FX 怎么写 请自行 先学习相关内容

②、自定义Controller和Service插件

1、自定义生成Controller和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、添加 MainUI.fxml 功能


<?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、添加 MainUIController 功能


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、添加 GeneratorConfig功能


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、添加 PluginConfiguration 配置。

在这里插入图片描述

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、运行与测试结果

在这里插入图片描述
在这里插入图片描述

全文到处便完结了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1045432.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

超全超详细的Redis笔记-数据类型及其使用、主从复制、哨兵模式、缓存穿透、击穿、雪崩

文章目录 狂神聊Redis1、Nosql概述1.1、为什么要用Nosql1.2、什么是NoSQL1.3、NoSQL的四大分类 2、Redis 入门2.1、概述2.2、Windows 安装2.3、Linux安装2.4、测试性能2.5、Redis基础知识 3、五大基本数据类型3.1、Redis-Key3.2、String3.3、List3.4、Set3.5、Hash&#xff08;…

基于SSM的实习管理系统

基于SSM的实习管理系统、前后端分离 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringSpringMVCMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 管理员界面 教师 学生 研究背景 基于SSM的实习管理系统是一个基于Spring、Spring…

【计算机网络】网络层和数据链路层

文章目录 IP协议网段划分分类划分法CIDR 方案路由NAT网络地址转换技术IP报文的另外三个参数mac帧ARP协议交换机ICMP代理服务器 IP协议 TCP有将数据 可靠、高效 发给对方的 策略&#xff0c;而IP具有发送的能力&#xff0c;即将数据从A主机送到B主机的 能力 。 用户要的是100%…

GeoPandas和Matplotlib地图高亮显示——与中国建交的国家(不全)

GeoPandas和Matplotlib地图高亮显示——与中国建交的国家&#xff08;不全&#xff09; 一、概要二、整体架构流程三、完整代码 一、概要 这段代码是使用GeoPandas和Matplotlib库在Python中绘制世界地图的一个例子&#xff0c;它突出了与中国建交的国家&#xff08;部分&#x…

​数据库查询进阶--多表查询

目录 目录 1. 概述 2. 内连接&#xff08;Inner Join&#xff09; 2.1 语法 2.2 示例 3. 左连接&#xff08;Left Join&#xff09; 3.1 语法 3.2 示例 4. 右连接&#xff08;Right Join&#xff09; 4.1 语法 4.2 示例 5. 全外连接&#xff08;Full Outer Join&am…

vue实现进度条+背景定位

最近在做一个数字孪生项目&#xff0c;用于展示地铁车辆的进场动画及部件&#xff0c;使用的vueunity&#xff0c;但是 unity模型在加载完成之前会有个加载进度条&#xff0c;页面背景色是黑色&#xff0c;中间只有个一进度条框 可以看到很单调很丑&#xff0c;并且客户也不满…

2023软件测试八股文,涵盖所有面试题

Part1 1、你的测试职业发展是什么&#xff1f; 测试经验越多&#xff0c;测试能力越高。所以我的职业发展是需要时间积累的&#xff0c;一步步向着高级测试工程师奔去。而且我也有初步的职业规划&#xff0c;前3年积累测试经验&#xff0c;按如何做好测试工程师的要点去要求自…

如何优化前端性能?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 优化前端性能1. 减少HTTP请求2. 压缩资源3. 使用浏览器缓存4. 使用CDN5. 延迟加载6. 使用响应式设计7. 减少重绘和回流8. 代码优化9. 使用现代Web技术 ⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前…

vue event bus 事件总线

vue event bus 事件总线 创建 工程&#xff1a; H:\java_work\java_springboot\vue_study ctrl按住不放 右键 悬着 powershell H:\java_work\java_springboot\js_study\Vue2_3入门到实战-配套资料\01-随堂代码素材\day04\准备代码\08-事件总线-扩展 vue --version vue crea…

免杀对抗-内存加载-shellcode转换-UUID+MAC+IPV4

内存加载-UUID地址-ShellCode转换 介绍&#xff1a;通用唯一识别码(UUID),是用于计算机体系中以识别信息数目的一个128位标识符&#xff0c;根据标准方法生成&#xff0c;不依赖中央机构的注册和分配&#xff0c;UUID具有唯一性。 演示语言&#xff1a;c 1.使用以下代码将c语言…

如何使用 API 接口获取商品数据,从申请 API 接口、使用 API 接口到实际应用,一一讲解

在当今的数字化时代&#xff0c;应用程序接口&#xff08;API&#xff09;已经成为数据获取的重要通道。API 接口使得不同的应用程序能够方便地进行数据交换&#xff0c;从而促进了信息的广泛传播和利用。在众多的数据源中&#xff0c;商品数据是一个非常重要的领域&#xff0c…

leetcode面试题0808有重复字符串的排列组合

描述 输入一个长度为 n 字符串&#xff0c;打印出该字符串中字符的所有排列&#xff0c;你可以以任意顺序返回这个字符串数组。 例如输入字符串ABC,则输出由字符A,B,C所能排列出来的所有字符串ABC,ACB,BAC,BCA,CBA和CAB。 数据范围&#xff1a;n<10 要求&#xff1a;空间复…

Mysql高级语句(视图表 、存储过程、条件语句、循环语句)

Mysql高级语句&#xff08;视图表 、存储过程、条件语句、循环语句&#xff09; 一、 CREATE VIEW&#xff08;视图&#xff09;1.1、 视图表概述1.2、 视图表能否修改&#xff1f;&#xff08;面试题&#xff09;1.3、 基本语法1.3.1、 创建1.3.2、 查看1.3.3 、删除 1.4、 通…

基于微信小程序的场地预约系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统主要功能&#xff1a;具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…

react create-react-app v5 从零搭建项目

前言&#xff1a; 好久没用 create-react-app做项目了&#xff0c;这次为了个h5项目&#xff0c;就几个页面&#xff0c;决定自己搭建一个&#xff08;ps:mmp 好久没用&#xff0c;搭建的时候遇到一堆问题&#xff09;。 我之前都是使用 umi 。后台管理系统的项目 使用 antd-…

你听说过推挽电路吗?避免交越失真

推挽电路就是用两个三级管或者场效应管构成的放大电路&#xff0c;这个电路的特点就是输出电阻小&#xff0c;能够驱动大的负载&#xff0c;从而能够使得单片机管脚直接驱动发光二极管、蜂鸣器。上面的三极管是N型三极管&#xff0c;下面的三极管是P型三极管&#xff0c; 当输入…

【深度学习实验】卷积神经网络(五):深度卷积神经网络经典模型——VGG网络(卷积层、池化层、全连接层)

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入必要的工具包 1. conv_layer&#xff08;创建卷积块&#xff09; 2. vgg_conv_block&#xff08;卷积模块&#xff1a;卷积层*n、池化层&#xff09; 3. vgg_fc_layer&#xff08;…

华为云云耀云服务器L实例评测|华为云云耀云服务器docker部署srs,可使用HLS协议

华为云云耀云服务器L实例评测&#xff5c;华为云云耀云服务器docker部署srs&#xff0c;可使用HLS协议 什么是华为云云耀云L实例 云耀云服务器L实例&#xff0c;面向初创企业和开发者打造的全新轻量应用云服务器。提供丰富严选的应用镜像&#xff0c;实现应用一键部署&#x…

信创办公–基于WPS的EXCEL最佳实践系列 (获取外部数据)

信创办公–基于WPS的EXCEL最佳实践系列 &#xff08;获取外部数据&#xff09; 目录 应用背景操作步骤1、导入数据2、刷新数据 应用背景 通常企业的数据会存储在数据库或不同的系统中&#xff0c;而我们想要在自己用的工作WPS的excel表格里使用这些数据&#xff0c;我们可以使…

QT入门10个小demo——MP4视频播放器

&#x1f64c;秋名山码民的主页 &#x1f602;oi退役选手&#xff0c;Java、大数据、单片机、IoT均有所涉猎&#xff0c;热爱技术&#xff0c;技术无罪 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; 获取源码&#xff0c;添加WX 目录 一、前…