[
  {
    "path": ".gitignore",
    "content": "/target/\n/config/\n.idea\n.settings\nlogs\n*.iml\n.project\n.classpath\n/src/main/resources/sqlite3.db\n/config/\n"
  },
  {
    "path": "README.md",
    "content": "mybatis-generator-gui\n==============\n\nmybatis-generator-gui是基于 [mybatis generator](http://www.mybatis.org/generator/index.html) 开发一款界面工具, 本工具可以使你非常容易及快速生成Mybatis的Java POJO文件及数据库Mapping文件。\n\n![image](https://user-images.githubusercontent.com/3505708/49334784-1a42c980-f619-11e8-914d-9ea85db9cec3.png)\n\n\n![basic](https://user-images.githubusercontent.com/3505708/51911610-45754980-240d-11e9-85ad-643e55cafab2.png)\n\n\n![overSSH](https://user-images.githubusercontent.com/3505708/51911646-5920b000-240d-11e9-9048-738306a56d14.png)\n\n![SearchSupport](https://user-images.githubusercontent.com/8142133/115959972-881d2200-a541-11eb-8ad4-052f379b91f1.png)\n\n\n### 核心特性\n* 按照界面步骤轻松生成代码，省去XML繁琐的学习与配置过程\n* 保存数据库连接与Generator配置，每次代码生成轻松搞定\n* 内置常用插件，比如分页插件\n* 支持OverSSH 方式，通过SSH隧道连接至公司内网访问数据库\n* 把数据库中表列的注释生成为Java实体的注释，生成的实体清晰明了\n* 可选的去除掉对版本管理不友好的注释，这样新增或删除字段重新生成的文件比较过来清楚\n* 目前已经支持Mysql、Mysql8、Oracle、PostgreSQL与SQL Server，暂不对其他非主流数据库提供支持。(MySQL支持的比较好，其他数据库有什么问题可以在issue中反馈)\n\n### 运行要求（重要！！！）\n本工具仅支持Java的2个最新的LTS版本，jdk8和jdk11\n* jdk1.8要求版本在<strong>1.8.0.60</strong>以上版本\n* Java 11无版本要求\n\n### 直接运行（非必须）\n推荐使用IDE直接运行，如果需要二进制安装包，可以关注公众号获取二进制安装版，目前支持Windows和MacOS，注意你的JDK是不是1.8，并且版本大于1.8.0.60\n\n\n### 启动本软件\n\n* 方法一：关注微信公众号“搬砖头也要有态度”，回复“GUI”获取下载链接\n    \n  ![image](https://user-images.githubusercontent.com/3505708/61360019-2893dc00-a8b0-11e9-8dc9-a020e997ab87.png)\n\n* 方法二: 自助构建\n\n  ```bash\n  git clone https://github.com/zouzg/mybatis-generator-gui\n  cd mybatis-generator-gui\n  mvn jfx:jar\n  cd target/jfx/app/\n  java -jar mybatis-generator-gui.jar\n  ```\n\n* 方法三: IDE中运行\n\n  Eclipse or IntelliJ IDEA中启动, 找到`com.zzg.mybatis.generator.MainUI`类并运行就可以了（主要你的IED运行的jdk版本是否符合要求）\n\n* 方法四：打包为本地原生应用，双击快捷方式即可启动，方便快捷\n\n  如果不想打包后的安装包logo为Java的灰色的茶杯，需要在pom文件里将对应操作系统平台的图标注释放开\n\n  ```bash\n  #<icon>${project.basedir}/package/windows/mybatis-generator-gui.ico</icon>为windows\n  #<icon>${project.basedir}/package/macosx/mybatis-generator-gui.icns</icon>为mac\n  mvn jfx:native\n  ```\n\n  另外需要注意，windows系统打包成exe的话需要安装WiXToolset3+的环境；由于打包后会把jre打入安装包，两个平台均100M左右，体积较大请自行打包；打包后的安装包在target/jfx/native目录下\n\n### 注意事项\n* 本自动生成代码工具只适合生成单表的增删改查，对于需要做数据库联合查询的，请自行写新的XML与Mapper；\n* 部分系统在中文输入方法时输入框中无法输入文字，请切换成英文输入法；\n* 如果不明白对应字段或选项是什么意思的时候，把光标放在对应字段或Label上停留一会然后如果有解释会出现解释；\n\n\n### 文档\n更多详细文档请参考本库的Wiki\n* [Usage](https://github.com/astarring/mybatis-generator-gui/wiki/Usage-Guide)\n\n\n### 贡献\n目前本工具只是本人项目人使用到了并且觉得非常有用所以把它开源，如果你觉得有用并且想改进本软件，你可以：\n* 对于你认为有用的功能，你可以在Issue提，我可以开发的尽量满足\n* 对于有Bug的地方，请按如下方式在Issue中提bug\n    * 如何重现你的bug，包括你使用的系统，JDK版本，数据库类型及版本\n    * 如果有任何的错误截图会更好\n    * 如果你是一些常见的数据库连接、软件启动不了等问题，请先仔细阅读上面的文档，再解决不了在下面的QQ群中问（问问题的时候尽量把各种信息都提供好，否则只是几行文字是没有人愿意为你解答的）。\n    \n### QQ群\n鉴于有的同学可能有一些特殊情况不能使用，我建了一个钉钉群供大家交流，钉钉群号：35412531 （原QQ群已不再提供，QQ不方便打开）\n\n- - -\nLicensed under the Apache 2.0 License\n\nCopyright 2017 by Owen Zou\n"
  },
  {
    "path": "_config.yml",
    "content": "theme: jekyll-theme-cayman"
  },
  {
    "path": "pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.zzg</groupId>\n    <artifactId>mybatis-generator-gui</artifactId>\n    <version>0.8.9-SNAPSHOT</version>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>\n        <!-- Java 11请修改此处为11 -->\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.mybatis.generator</groupId>\n            <artifactId>mybatis-generator-core</artifactId>\n            <version>1.3.6</version>\n        </dependency>\n        <dependency>\n            <groupId>ch.qos.logback</groupId>\n            <artifactId>logback-classic</artifactId>\n            <version>1.2.0</version>\n        </dependency>\n        <dependency>\n            <groupId>ch.qos.logback</groupId>\n            <artifactId>logback-core</artifactId>\n            <version>1.2.0</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.4</version>\n        </dependency>\n        <dependency>\n            <groupId>commons-io</groupId>\n            <artifactId>commons-io</artifactId>\n            <version>[2.7,)</version>\n        </dependency>\n        <dependency>\n            <groupId>org.xerial</groupId>\n            <artifactId>sqlite-jdbc</artifactId>\n            <version>3.8.11.2</version>\n        </dependency>\n        <dependency>\n            <groupId>commons-beanutils</groupId>\n            <artifactId>commons-beanutils</artifactId>\n            <version>1.9.2</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.76</version>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.13.1</version>\n        </dependency>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-api</artifactId>\n            <version>1.7.25</version>\n        </dependency>\n        <dependency>\n            <groupId>com.jcraft</groupId>\n            <artifactId>jsch</artifactId>\n            <version>0.1.54</version>\n        </dependency>\n        <dependency>\n            <groupId>com.softwareloop</groupId>\n            <artifactId>mybatis-generator-lombok-plugin</artifactId>\n            <version>1.0</version>\n        </dependency>\n        <!-- Java 11请关闭下面注释 -->\n        <!--\n        <dependency>\n            <groupId>org.openjfx</groupId>\n            <artifactId>javafx-controls</artifactId>\n            <version>11</version>\n        </dependency>\n        <dependency>\n            <groupId>org.openjfx</groupId>\n            <artifactId>javafx-fxml</artifactId>\n            <version>11</version>\n        </dependency>\n        -->\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.1</version>\n                <configuration>\n                    <!-- Java 11请修改此处为11 -->\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>com.zenjava</groupId>\n                <artifactId>javafx-maven-plugin</artifactId>\n                <version>8.8.3</version>\n                <configuration>\n                    <bundleArguments>\n                        <!-- windows打包开启-->\n                        <icon>${project.basedir}/package/windows/mybatis-generator-gui.ico</icon>\n                        <!-- mac打包开启-->\n                        <icon>${project.basedir}/package/macosx/mybatis-generator-gui.icns</icon>\n                    </bundleArguments>\n                    <mainClass>com.zzg.mybatis.generator.MainUI</mainClass>\n                    <vendor>Owen Zou</vendor>\n                    <verbose>false</verbose>\n                    <jfxMainAppJarName>mybatis-generator-gui.jar</jfxMainAppJarName>\n                    <needShortcut>true</needShortcut>\n                    <needMenu>true</needMenu>\n                    <copyAdditionalAppResourcesToJar>true</copyAdditionalAppResourcesToJar>\n                    <additionalAppResources>${project.basedir}/src/main/resources</additionalAppResources>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/Main.java",
    "content": "package com.zzg.mybatis.generator;\n\nimport javafx.application.Application;\n\n/**\n * @author 欧闻\n * @version $Id: Main, v 0.1 2021/4/20 欧闻 Exp $$\n */\npublic class Main {\n\n    public static void main(String[] args) {\n        Application.launch(MainUI.class);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/MainUI.java",
    "content": "package com.zzg.mybatis.generator;\n\nimport com.zzg.mybatis.generator.controller.MainUIController;\nimport com.zzg.mybatis.generator.util.ConfigHelper;\nimport javafx.application.Application;\nimport javafx.fxml.FXMLLoader;\nimport javafx.scene.Parent;\nimport javafx.scene.Scene;\nimport javafx.scene.image.Image;\nimport javafx.stage.Stage;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport javax.swing.*;\nimport java.net.URL;\n\n/**\n * 这是本软件的主入口,要运行本软件请直接运行本类就可以了,不用传入任何参数\n * 本软件要求jkd版本大于1.8.0.40\n */\npublic class MainUI extends Application {\n\n\tprivate static final Logger _LOG = LoggerFactory.getLogger(MainUI.class);\n\n\t@Override\n\tpublic void start(Stage primaryStage) throws Exception {\n\t\tConfigHelper.createEmptyFiles();\n\t\tURL url = Thread.currentThread().getContextClassLoader().getResource(\"fxml/MainUI.fxml\");\n\t\tFXMLLoader fxmlLoader = new FXMLLoader(url);\n\t\tParent root = fxmlLoader.load();\n\t\tprimaryStage.setResizable(true);\n\t\tprimaryStage.setScene(new Scene(root));\n\t\tprimaryStage.setTitle(\"Mybatis Generator GUI\");\n\t\tImage imageIcon = new Image(\"icons/mybatis-logo.png\");\n\t\tprimaryStage.getIcons().add(imageIcon);\n\t\tprimaryStage.show();\n\n\t\tMainUIController controller = fxmlLoader.getController();\n\t\tcontroller.setPrimaryStage(primaryStage);\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tlaunch(args);\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/bridge/MybatisGeneratorBridge.java",
    "content": "package com.zzg.mybatis.generator.bridge;\n\nimport com.jcraft.jsch.Session;\nimport com.zzg.mybatis.generator.controller.PictureProcessStateController;\nimport com.zzg.mybatis.generator.model.DatabaseConfig;\nimport com.zzg.mybatis.generator.model.DbType;\nimport com.zzg.mybatis.generator.model.GeneratorConfig;\nimport com.zzg.mybatis.generator.plugins.DbRemarksCommentGenerator;\nimport com.zzg.mybatis.generator.util.ConfigHelper;\nimport com.zzg.mybatis.generator.util.DbUtil;\nimport org.apache.commons.lang3.StringUtils;\nimport org.mybatis.generator.api.MyBatisGenerator;\nimport org.mybatis.generator.api.ProgressCallback;\nimport org.mybatis.generator.api.ShellCallback;\nimport org.mybatis.generator.config.*;\nimport org.mybatis.generator.internal.DefaultShellCallback;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * The bridge between GUI and the mybatis generator. All the operation to  mybatis generator should proceed through this\n * class\n * <p>\n * Created by Owen on 6/30/16.\n */\npublic class MybatisGeneratorBridge {\n\n\tprivate static final Logger _LOG = LoggerFactory.getLogger(MybatisGeneratorBridge.class);\n\n    private GeneratorConfig generatorConfig;\n\n    private DatabaseConfig selectedDatabaseConfig;\n\n    private ProgressCallback progressCallback;\n\n    private List<IgnoredColumn> ignoredColumns;\n\n    private List<ColumnOverride> columnOverrides;\n\n    public MybatisGeneratorBridge() {\n    }\n\n    public void setGeneratorConfig(GeneratorConfig generatorConfig) {\n        this.generatorConfig = generatorConfig;\n    }\n\n    public void setDatabaseConfig(DatabaseConfig databaseConfig) {\n        this.selectedDatabaseConfig = databaseConfig;\n    }\n\n    public void generate() throws Exception {\n        Configuration configuration = new Configuration();\n        Context context = new Context(ModelType.CONDITIONAL);\n        configuration.addContext(context);\n\t\t\n        context.addProperty(\"javaFileEncoding\", \"UTF-8\");\n        \n\t\tString dbType = selectedDatabaseConfig.getDbType();\n\t\tString connectorLibPath = ConfigHelper.findConnectorLibPath(dbType);\n\t    _LOG.info(\"connectorLibPath: {}\", connectorLibPath);\n\t    configuration.addClasspathEntry(connectorLibPath);\n        // Table configuration\n        TableConfiguration tableConfig = new TableConfiguration(context);\n        tableConfig.setTableName(generatorConfig.getTableName());\n        tableConfig.setDomainObjectName(generatorConfig.getDomainObjectName());\n        if(!generatorConfig.isUseExample()) {\n            tableConfig.setUpdateByExampleStatementEnabled(false);\n            tableConfig.setCountByExampleStatementEnabled(false);\n            tableConfig.setDeleteByExampleStatementEnabled(false);\n            tableConfig.setSelectByExampleStatementEnabled(false);\n        }\n\n\t\tcontext.addProperty(\"autoDelimitKeywords\", \"true\");\n\t\tif (DbType.MySQL.name().equals(dbType) || DbType.MySQL_8.name().equals(dbType)) {\n\t\t\ttableConfig.setSchema(selectedDatabaseConfig.getSchema());\n\t\t\t// 由于beginningDelimiter和endingDelimiter的默认值为双引号(\")，在Mysql中不能这么写，所以还要将这两个默认值改为`\n\t\t\tcontext.addProperty(\"beginningDelimiter\", \"`\");\n\t\t\tcontext.addProperty(\"endingDelimiter\", \"`\");\n\t\t} else {\n            tableConfig.setCatalog(selectedDatabaseConfig.getSchema());\n\t    }\n        if (generatorConfig.isUseSchemaPrefix()) {\n            if (DbType.MySQL.name().equals(dbType) || DbType.MySQL_8.name().equals(dbType)) {\n                tableConfig.setSchema(selectedDatabaseConfig.getSchema());\n            } else if (DbType.Oracle.name().equals(dbType)) {\n                //Oracle的schema为用户名，如果连接用户拥有dba等高级权限，若不设schema，会导致把其他用户下同名的表也生成一遍导致mapper中代码重复\n                tableConfig.setSchema(selectedDatabaseConfig.getUsername());\n            } else {\n                tableConfig.setCatalog(selectedDatabaseConfig.getSchema());\n            }\n        }\n        // 针对 postgresql 单独配置\n\t\tif (DbType.PostgreSQL.name().equals(dbType)) {\n            tableConfig.setDelimitIdentifiers(true);\n        }\n\n        //添加GeneratedKey主键生成\n\t\tif (StringUtils.isNotEmpty(generatorConfig.getGenerateKeys())) {\n            String dbType2 = dbType;\n            if (DbType.MySQL.name().equals(dbType2) || DbType.MySQL_8.name().equals(dbType)) {\n                dbType2 = \"JDBC\";\n                //dbType为JDBC，且配置中开启useGeneratedKeys时，Mybatis会使用Jdbc3KeyGenerator,\n                //使用该KeyGenerator的好处就是直接在一次INSERT 语句内，通过resultSet获取得到 生成的主键值，\n                //并很好的支持设置了读写分离代理的数据库\n                //例如阿里云RDS + 读写分离代理\n                //无需指定主库\n                //当使用SelectKey时，Mybatis会使用SelectKeyGenerator，INSERT之后，多发送一次查询语句，获得主键值\n                //在上述读写分离被代理的情况下，会得不到正确的主键\n            }\n\t\t\ttableConfig.setGeneratedKey(new GeneratedKey(generatorConfig.getGenerateKeys(), dbType2, true, null));\n\t\t}\n\n        if (generatorConfig.getMapperName() != null) {\n            tableConfig.setMapperName(generatorConfig.getMapperName());\n        }\n        // add ignore columns\n        if (ignoredColumns != null) {\n            ignoredColumns.forEach(tableConfig::addIgnoredColumn);\n        }\n        if (columnOverrides != null) {\n            columnOverrides.forEach(tableConfig::addColumnOverride);\n        }\n        if (generatorConfig.isUseActualColumnNames()) {\n\t\t\ttableConfig.addProperty(\"useActualColumnNames\", \"true\");\n        }\n\n\t\tif(generatorConfig.isUseTableNameAlias()){\n            tableConfig.setAlias(generatorConfig.getTableName());\n        }\n\n        JDBCConnectionConfiguration jdbcConfig = new JDBCConnectionConfiguration();\n        if (DbType.MySQL.name().equals(dbType) || DbType.MySQL_8.name().equals(dbType)) {\n\t        jdbcConfig.addProperty(\"nullCatalogMeansCurrent\", \"true\");\n\t        // useInformationSchema可以拿到表注释，从而生成类注释可以使用表的注释\n\t        jdbcConfig.addProperty(\"useInformationSchema\", \"true\");\n        }\n        jdbcConfig.setDriverClass(DbType.valueOf(dbType).getDriverClass());\n        jdbcConfig.setConnectionURL(DbUtil.getConnectionUrlWithSchema(selectedDatabaseConfig));\n        jdbcConfig.setUserId(selectedDatabaseConfig.getUsername());\n        jdbcConfig.setPassword(selectedDatabaseConfig.getPassword());\n        if(DbType.Oracle.name().equals(dbType)){\n            jdbcConfig.getProperties().setProperty(\"remarksReporting\", \"true\");\n        }\n        // java model\n        JavaModelGeneratorConfiguration modelConfig = new JavaModelGeneratorConfiguration();\n        modelConfig.setTargetPackage(generatorConfig.getModelPackage());\n        modelConfig.setTargetProject(generatorConfig.getProjectFolder() + \"/\" + generatorConfig.getModelPackageTargetFolder());\n        // Mapper configuration\n        SqlMapGeneratorConfiguration mapperConfig = new SqlMapGeneratorConfiguration();\n        mapperConfig.setTargetPackage(generatorConfig.getMappingXMLPackage());\n        mapperConfig.setTargetProject(generatorConfig.getProjectFolder() + \"/\" + generatorConfig.getMappingXMLTargetFolder());\n        // DAO\n        JavaClientGeneratorConfiguration daoConfig = new JavaClientGeneratorConfiguration();\n        daoConfig.setConfigurationType(\"XMLMAPPER\");\n        daoConfig.setTargetPackage(generatorConfig.getDaoPackage());\n        daoConfig.setTargetProject(generatorConfig.getProjectFolder() + \"/\" + generatorConfig.getDaoTargetFolder());\n\n\n        context.setId(\"myid\");\n        context.addTableConfiguration(tableConfig);\n        context.setJdbcConnectionConfiguration(jdbcConfig);\n        context.setJavaModelGeneratorConfiguration(modelConfig);\n        context.setSqlMapGeneratorConfiguration(mapperConfig);\n        context.setJavaClientGeneratorConfiguration(daoConfig);\n        // Comment\n        CommentGeneratorConfiguration commentConfig = new CommentGeneratorConfiguration();\n        commentConfig.setConfigurationType(DbRemarksCommentGenerator.class.getName());\n        if (generatorConfig.isComment()) {\n            commentConfig.addProperty(\"columnRemarks\", \"true\");\n        }\n        if (generatorConfig.isAnnotation()) {\n            commentConfig.addProperty(\"annotations\", \"true\");\n        }\n        context.setCommentGeneratorConfiguration(commentConfig);\n        // set java file encoding\n        context.addProperty(PropertyRegistry.CONTEXT_JAVA_FILE_ENCODING, generatorConfig.getEncoding());\n\n        //实体添加序列化\n        PluginConfiguration serializablePluginConfiguration = new PluginConfiguration();\n        serializablePluginConfiguration.addProperty(\"type\", \"org.mybatis.generator.plugins.SerializablePlugin\");\n        serializablePluginConfiguration.setConfigurationType(\"org.mybatis.generator.plugins.SerializablePlugin\");\n        context.addPluginConfiguration(serializablePluginConfiguration);\n\n        // Lombok 插件\n        if (generatorConfig.isUseLombokPlugin()) {\n            PluginConfiguration pluginConfiguration = new PluginConfiguration();\n            pluginConfiguration.addProperty(\"type\", \"com.softwareloop.mybatis.generator.plugins.LombokPlugin\");\n            pluginConfiguration.setConfigurationType(\"com.softwareloop.mybatis.generator.plugins.LombokPlugin\");\n            context.addPluginConfiguration(pluginConfiguration);\n        }\n        // toString, hashCode, equals插件\n        else if (generatorConfig.isNeedToStringHashcodeEquals()) {\n            PluginConfiguration pluginConfiguration1 = new PluginConfiguration();\n            pluginConfiguration1.addProperty(\"type\", \"org.mybatis.generator.plugins.EqualsHashCodePlugin\");\n            pluginConfiguration1.setConfigurationType(\"org.mybatis.generator.plugins.EqualsHashCodePlugin\");\n            context.addPluginConfiguration(pluginConfiguration1);\n            PluginConfiguration pluginConfiguration2 = new PluginConfiguration();\n            pluginConfiguration2.addProperty(\"type\", \"org.mybatis.generator.plugins.ToStringPlugin\");\n            pluginConfiguration2.setConfigurationType(\"org.mybatis.generator.plugins.ToStringPlugin\");\n            context.addPluginConfiguration(pluginConfiguration2);\n        }\n        // limit/offset插件\n        if (generatorConfig.isOffsetLimit()) {\n            if (DbType.MySQL.name().equals(dbType) || DbType.MySQL_8.name().equals(dbType)\n\t\t            || DbType.PostgreSQL.name().equals(dbType)) {\n                PluginConfiguration pluginConfiguration = new PluginConfiguration();\n                pluginConfiguration.addProperty(\"type\", \"com.zzg.mybatis.generator.plugins.MySQLLimitPlugin\");\n                pluginConfiguration.setConfigurationType(\"com.zzg.mybatis.generator.plugins.MySQLLimitPlugin\");\n                context.addPluginConfiguration(pluginConfiguration);\n            }\n        }\n        //for JSR310\n        if (generatorConfig.isJsr310Support()) {\n            JavaTypeResolverConfiguration javaTypeResolverConfiguration = new JavaTypeResolverConfiguration();\n            javaTypeResolverConfiguration.setConfigurationType(\"com.zzg.mybatis.generator.plugins.JavaTypeResolverJsr310Impl\");\n            context.setJavaTypeResolverConfiguration(javaTypeResolverConfiguration);\n        }\n        //forUpdate 插件\n        if(generatorConfig.isNeedForUpdate()) {\n            if (DbType.MySQL.name().equals(dbType)\n                    || DbType.PostgreSQL.name().equals(dbType)) {\n                PluginConfiguration pluginConfiguration = new PluginConfiguration();\n                pluginConfiguration.addProperty(\"type\", \"com.zzg.mybatis.generator.plugins.MySQLForUpdatePlugin\");\n                pluginConfiguration.setConfigurationType(\"com.zzg.mybatis.generator.plugins.MySQLForUpdatePlugin\");\n                context.addPluginConfiguration(pluginConfiguration);\n            }\n        }\n        //repository 插件\n        if(generatorConfig.isAnnotationDAO()) {\n            if (DbType.MySQL.name().equals(dbType) || DbType.MySQL_8.name().equals(dbType)\n                    || DbType.PostgreSQL.name().equals(dbType)) {\n                PluginConfiguration pluginConfiguration = new PluginConfiguration();\n                pluginConfiguration.addProperty(\"type\", \"com.zzg.mybatis.generator.plugins.RepositoryPlugin\");\n                pluginConfiguration.setConfigurationType(\"com.zzg.mybatis.generator.plugins.RepositoryPlugin\");\n                context.addPluginConfiguration(pluginConfiguration);\n            }\n        }\n        if (generatorConfig.isUseDAOExtendStyle()) {\n            if (DbType.MySQL.name().equals(dbType) || DbType.MySQL_8.name().equals(dbType)\n                    || DbType.PostgreSQL.name().equals(dbType)) {\n                PluginConfiguration pluginConfiguration = new PluginConfiguration();\n\t\t\t\tpluginConfiguration.addProperty(\"useExample\", String.valueOf(generatorConfig.isUseExample()));\n\t\t\t\tpluginConfiguration.addProperty(\"type\", \"com.zzg.mybatis.generator.plugins.CommonDAOInterfacePlugin\");\n                pluginConfiguration.setConfigurationType(\"com.zzg.mybatis.generator.plugins.CommonDAOInterfacePlugin\");\n                context.addPluginConfiguration(pluginConfiguration);\n            }\n        }\n\n        context.setTargetRuntime(\"MyBatis3\");\n\n        List<String> warnings = new ArrayList<>();\n        Set<String> fullyqualifiedTables = new HashSet<>();\n        Set<String> contexts = new HashSet<>();\n        ShellCallback shellCallback = new DefaultShellCallback(true); // override=true\n        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(configuration, shellCallback, warnings);\n        // if overrideXML selected, delete oldXML ang generate new one\n\t\tif (generatorConfig.isOverrideXML()) {\n\t\t\tString mappingXMLFilePath = getMappingXMLFilePath(generatorConfig);\n\t\t\tFile mappingXMLFile = new File(mappingXMLFilePath);\n\t\t\tif (mappingXMLFile.exists()) {\n\t\t\t\tmappingXMLFile.delete();\n\t\t\t}\n\t\t}\n        myBatisGenerator.generate(progressCallback, contexts, fullyqualifiedTables);\n    }\n\n    private String getMappingXMLFilePath(GeneratorConfig generatorConfig) {\n\t\tStringBuilder sb = new StringBuilder();\n\t\tsb.append(generatorConfig.getProjectFolder()).append(\"/\");\n\t\tsb.append(generatorConfig.getMappingXMLTargetFolder()).append(\"/\");\n\t\tString mappingXMLPackage = generatorConfig.getMappingXMLPackage();\n\t\tif (StringUtils.isNotEmpty(mappingXMLPackage)) {\n\t\t\tsb.append(mappingXMLPackage.replace(\".\", \"/\")).append(\"/\");\n\t\t}\n\t\tif (StringUtils.isNotEmpty(generatorConfig.getMapperName())) {\n\t\t\tsb.append(generatorConfig.getMapperName()).append(\".xml\");\n\t\t} else {\n\t\t\tsb.append(generatorConfig.getDomainObjectName()).append(\"Mapper.xml\");\n\t\t}\n\n\t\treturn sb.toString();\n\t}\n\n\tpublic void setProgressCallback(ProgressCallback progressCallback) {\n        this.progressCallback = progressCallback;\n    }\n\n    public void setIgnoredColumns(List<IgnoredColumn> ignoredColumns) {\n        this.ignoredColumns = ignoredColumns;\n    }\n\n    public void setColumnOverrides(List<ColumnOverride> columnOverrides) {\n        this.columnOverrides = columnOverrides;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/controller/BaseFXController.java",
    "content": "package com.zzg.mybatis.generator.controller;\r\n\r\nimport com.zzg.mybatis.generator.view.AlertUtil;\r\nimport javafx.fxml.FXMLLoader;\r\nimport javafx.fxml.Initializable;\r\nimport javafx.scene.Parent;\r\nimport javafx.scene.Scene;\r\nimport javafx.stage.Modality;\r\nimport javafx.stage.Stage;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\nimport java.io.IOException;\r\nimport java.lang.ref.SoftReference;\r\nimport java.net.URL;\r\nimport java.util.HashMap;\r\nimport java.util.Map;\r\n\r\npublic abstract class BaseFXController implements Initializable {\r\n    private static final Logger _LOG = LoggerFactory.getLogger(BaseFXController.class);\r\n\r\n    private Stage primaryStage;\r\n    private Stage dialogStage;\r\n\r\n    private static Map<FXMLPage, SoftReference<? extends BaseFXController>> cacheNodeMap = new HashMap<>();\r\n\r\n    public BaseFXController loadFXMLPage(String title, FXMLPage fxmlPage, boolean cache) {\r\n        SoftReference<? extends BaseFXController> parentNodeRef = cacheNodeMap.get(fxmlPage);\r\n        if (cache && parentNodeRef != null) {\r\n            return parentNodeRef.get();\r\n        }\r\n        URL skeletonResource = Thread.currentThread().getContextClassLoader().getResource(fxmlPage.getFxml());\r\n        FXMLLoader loader = new FXMLLoader(skeletonResource);\r\n        Parent loginNode;\r\n        try {\r\n            loginNode = loader.load();\r\n            BaseFXController controller     = loader.getController();\r\n            // fix bug: 嵌套弹出时会发生dialogStage被覆盖的情况\r\n            Stage            tmpDialogStage = new Stage();\r\n            tmpDialogStage.setTitle(title);\r\n            tmpDialogStage.initModality(Modality.APPLICATION_MODAL);\r\n            tmpDialogStage.initOwner(getPrimaryStage());\r\n            tmpDialogStage.setScene(new Scene(loginNode));\r\n            tmpDialogStage.setMaximized(false);\r\n            tmpDialogStage.setResizable(false);\r\n            tmpDialogStage.show();\r\n            controller.setDialogStage(tmpDialogStage);\r\n            // put into cache map\r\n            SoftReference<BaseFXController> softReference = new SoftReference<>(controller);\r\n            cacheNodeMap.put(fxmlPage, softReference);\r\n\r\n            return controller;\r\n        } catch (IOException e) {\r\n            _LOG.error(e.getMessage(), e);\r\n            AlertUtil.showErrorAlert(e.getMessage());\r\n        }\r\n        return null;\r\n    }\r\n\r\n    public Stage getPrimaryStage() {\r\n        return primaryStage;\r\n    }\r\n\r\n    public void setPrimaryStage(Stage primaryStage) {\r\n        this.primaryStage = primaryStage;\r\n    }\r\n\r\n    public Stage getDialogStage() {\r\n        return dialogStage;\r\n    }\r\n\r\n    public void setDialogStage(Stage dialogStage) {\r\n        this.dialogStage = dialogStage;\r\n    }\r\n\r\n    public void showDialogStage() {\r\n        if (dialogStage != null) {\r\n            dialogStage.show();\r\n        }\r\n    }\r\n\r\n    public void closeDialogStage() {\r\n        if (dialogStage != null) {\r\n            dialogStage.close();\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/controller/DbConnectionController.java",
    "content": "package com.zzg.mybatis.generator.controller;\n\nimport com.zzg.mybatis.generator.model.DatabaseConfig;\nimport com.zzg.mybatis.generator.util.ConfigHelper;\nimport com.zzg.mybatis.generator.view.AlertUtil;\nimport javafx.fxml.FXML;\nimport javafx.scene.control.ChoiceBox;\nimport javafx.scene.control.TextField;\nimport org.apache.commons.lang3.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.net.URL;\nimport java.util.ResourceBundle;\n\npublic class DbConnectionController extends BaseFXController {\n\n    private static final Logger _LOG = LoggerFactory.getLogger(DbConnectionController.class);\n\n    @FXML\n    protected TextField nameField;\n    @FXML\n    protected TextField hostField;\n    @FXML\n    protected TextField portField;\n    @FXML\n    protected TextField userNameField;\n    @FXML\n    protected TextField passwordField;\n    @FXML\n    protected TextField schemaField;\n    @FXML\n    protected ChoiceBox<String> encodingChoice;\n    @FXML\n    protected ChoiceBox<String> dbTypeChoice;\n    protected MainUIController mainUIController;\n    protected TabPaneController tabPaneController;\n    protected boolean isUpdate = false;\n    protected Integer primayKey;\n\n    @Override\n    public void initialize(URL location, ResourceBundle resources) {\n    }\n\n    final void saveConnection() {\n        DatabaseConfig config = extractConfigForUI();\n        if (config == null) {\n            return;\n        }\n        try {\n            ConfigHelper.saveDatabaseConfig(this.isUpdate, primayKey, config);\n            this.tabPaneController.getDialogStage().close();\n            mainUIController.loadLeftDBTree();\n        } catch (Exception e) {\n            _LOG.error(e.getMessage(), e);\n            AlertUtil.showErrorAlert(e.getMessage());\n        }\n    }\n\n    void setMainUIController(MainUIController controller) {\n        this.mainUIController = controller;\n        super.setDialogStage(mainUIController.getDialogStage());\n    }\n\n    public void setTabPaneController(TabPaneController tabPaneController) {\n        this.tabPaneController = tabPaneController;\n    }\n\n    public DatabaseConfig extractConfigForUI() {\n        String name = nameField.getText();\n        String host = hostField.getText();\n        String port = portField.getText();\n        String userName = userNameField.getText();\n        String password = passwordField.getText();\n        String encoding = encodingChoice.getValue();\n        String dbType = dbTypeChoice.getValue();\n        String schema = schemaField.getText();\n        DatabaseConfig config = new DatabaseConfig();\n        config.setName(name);\n        config.setDbType(dbType);\n        config.setHost(host);\n        config.setPort(port);\n        config.setUsername(userName);\n        config.setPassword(password);\n        config.setSchema(schema);\n        config.setEncoding(encoding);\n        if (StringUtils.isAnyEmpty(name, host, port, userName, encoding, dbType, schema)) {\n            AlertUtil.showWarnAlert(\"密码以外其他字段必填\");\n            return null;\n        }\n        return config;\n    }\n\n    public void setConfig(DatabaseConfig config) {\n        isUpdate = true;\n        primayKey = config.getId(); // save id for update config\n        nameField.setText(config.getName());\n        hostField.setText(config.getHost());\n        portField.setText(config.getPort());\n        userNameField.setText(config.getUsername());\n        passwordField.setText(config.getPassword());\n        encodingChoice.setValue(config.getEncoding());\n        dbTypeChoice.setValue(config.getDbType());\n        schemaField.setText(config.getSchema());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/controller/FXMLPage.java",
    "content": "package com.zzg.mybatis.generator.controller;\n\n/**\n * FXML User Interface enum\n * <p>\n * Created by Owen on 6/20/16.\n */\npublic enum FXMLPage {\n\n    NEW_CONNECTION(\"fxml/newConnection.fxml\"),\n    SELECT_TABLE_COLUMN(\"fxml/selectTableColumn.fxml\"),\n    TABLE_COLUMN_CONFIG(\"fxml/tableColumnConfigs.fxml\"),\n    GENERATOR_CONFIG(\"fxml/generatorConfigs.fxml\"),\n    ;\n\n    private String fxml;\n\n    FXMLPage(String fxml) {\n        this.fxml = fxml;\n    }\n\n    public String getFxml() {\n        return this.fxml;\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/controller/GeneratorConfigController.java",
    "content": "package com.zzg.mybatis.generator.controller;\n\nimport com.zzg.mybatis.generator.model.GeneratorConfig;\nimport com.zzg.mybatis.generator.util.ConfigHelper;\nimport com.zzg.mybatis.generator.view.AlertUtil;\nimport javafx.collections.FXCollections;\nimport javafx.fxml.FXML;\nimport javafx.scene.control.Button;\nimport javafx.scene.control.TableCell;\nimport javafx.scene.control.TableColumn;\nimport javafx.scene.control.TableView;\nimport javafx.scene.control.cell.PropertyValueFactory;\nimport javafx.scene.layout.HBox;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.net.URL;\nimport java.util.List;\nimport java.util.ResourceBundle;\n\n/**\n * 管理GeneratorConfig的Controller\n *\n * Created by Owen on 8/21/16.\n */\npublic class GeneratorConfigController extends BaseFXController {\n\n    private static final Logger _LOG = LoggerFactory.getLogger(GeneratorConfigController.class);\n\n    @FXML\n    private TableView<GeneratorConfig> configTable;\n    @FXML\n    private TableColumn nameColumn;\n    @FXML\n    private TableColumn opsColumn;\n\n    private MainUIController mainUIController;\n\n    private GeneratorConfigController controller;\n\n    @Override\n    public void initialize(URL location, ResourceBundle resources) {\n        controller = this;\n        nameColumn.setCellValueFactory(new PropertyValueFactory<>(\"name\"));\n        // 自定义操作列\n        opsColumn.setCellValueFactory(new PropertyValueFactory<>(\"name\"));\n        opsColumn.setCellFactory(cell -> {\n            return new TableCell() {\n                @Override\n                protected void updateItem(Object item, boolean empty) {\n                    super.updateItem(item, empty);\n                    if (item == null || empty) {\n                        setText(null);\n                        setGraphic(null);\n                    } else {\n                        Button btn1 = new Button(\"应用\");\n                        Button btn2 = new Button(\"删除\");\n                        HBox hBox = new HBox();\n                        hBox.setSpacing(10);\n                        hBox.getChildren().add(btn1);\n                        hBox.getChildren().add(btn2);\n                        btn1.setOnAction(event -> {\n                            try {\n                                // 应用配置\n                                GeneratorConfig generatorConfig = ConfigHelper.loadGeneratorConfig(item.toString());\n                                mainUIController.setGeneratorConfigIntoUI(generatorConfig);\n                                controller.closeDialogStage();\n                            } catch (Exception e) {\n                                AlertUtil.showErrorAlert(e.getMessage());\n                            }\n                        });\n                        btn2.setOnAction(event -> {\n                            try {\n                                // 删除配置\n                                _LOG.debug(\"item: {}\", item);\n                                ConfigHelper.deleteGeneratorConfig(item.toString());\n                                refreshTableView();\n                            } catch (Exception e) {\n                                AlertUtil.showErrorAlert(e.getMessage());\n                            }\n                        });\n                        setGraphic(hBox);\n                    }\n                }\n            };\n        });\n        refreshTableView();\n    }\n\n    public void refreshTableView() {\n        try {\n            List<GeneratorConfig> configs = ConfigHelper.loadGeneratorConfigs();\n            configTable.setItems(FXCollections.observableList(configs));\n        } catch (Exception e) {\n            AlertUtil.showErrorAlert(e.getMessage());\n        }\n    }\n\n    void setMainUIController(MainUIController mainUIController) {\n        this.mainUIController = mainUIController;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/controller/MainUIController.java",
    "content": "package com.zzg.mybatis.generator.controller;\n\nimport com.jcraft.jsch.Session;\nimport com.zzg.mybatis.generator.bridge.MybatisGeneratorBridge;\nimport com.zzg.mybatis.generator.model.DatabaseConfig;\nimport com.zzg.mybatis.generator.model.GeneratorConfig;\nimport com.zzg.mybatis.generator.model.UITableColumnVO;\nimport com.zzg.mybatis.generator.util.ConfigHelper;\nimport com.zzg.mybatis.generator.util.DbUtil;\nimport com.zzg.mybatis.generator.util.MyStringUtils;\nimport com.zzg.mybatis.generator.view.AlertUtil;\nimport com.zzg.mybatis.generator.view.UIProgressCallback;\nimport javafx.collections.FXCollections;\nimport javafx.collections.ObservableList;\nimport javafx.concurrent.Task;\nimport javafx.fxml.FXML;\nimport javafx.scene.control.*;\nimport javafx.scene.control.Label;\nimport javafx.scene.control.MenuItem;\nimport javafx.scene.control.TextField;\nimport javafx.scene.control.cell.TextFieldTreeCell;\nimport javafx.scene.image.ImageView;\nimport javafx.scene.input.KeyCode;\nimport javafx.scene.input.MouseEvent;\nimport javafx.scene.input.KeyEvent;\nimport javafx.stage.DirectoryChooser;\nimport javafx.util.Callback;\nimport org.apache.commons.io.FileUtils;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.commons.lang3.exception.ExceptionUtils;\nimport org.mybatis.generator.config.ColumnOverride;\nimport org.mybatis.generator.config.IgnoredColumn;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.awt.*;\nimport java.io.File;\nimport java.net.URL;\nimport java.sql.SQLRecoverableException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.ResourceBundle;\n\npublic class MainUIController extends BaseFXController {\n\n    private static final Logger _LOG = LoggerFactory.getLogger(MainUIController.class);\n    private static final String FOLDER_NO_EXIST = \"部分目录不存在，是否创建\";\n    // tool bar buttons\n    @FXML\n    private Label connectionLabel;\n    @FXML\n    private Label configsLabel;\n    @FXML\n    private TextField modelTargetPackage;\n    @FXML\n    private TextField mapperTargetPackage;\n    @FXML\n    private TextField daoTargetPackage;\n    @FXML\n    private TextField tableNameField;\n    @FXML\n    private TextField domainObjectNameField;\n    @FXML\n    private TextField generateKeysField;\t//主键ID\n    @FXML\n    private TextField modelTargetProject;\n    @FXML\n    private TextField mappingTargetProject;\n    @FXML\n    private TextField daoTargetProject;\n    @FXML\n    private TextField mapperName;\n    @FXML\n    private TextField projectFolderField;\n    @FXML\n    private CheckBox offsetLimitCheckBox;\n    @FXML\n    private CheckBox commentCheckBox;\n    @FXML\n\tprivate CheckBox overrideXML;\n    @FXML\n    private CheckBox needToStringHashcodeEquals;\n    @FXML\n    private CheckBox useLombokPlugin;\n    @FXML\n    private CheckBox forUpdateCheckBox;\n    @FXML\n    private CheckBox annotationDAOCheckBox;\n    @FXML\n    private CheckBox useTableNameAliasCheckbox;\n    @FXML\n    private CheckBox annotationCheckBox;\n    @FXML\n    private CheckBox useActualColumnNamesCheckbox;\n    @FXML\n    private CheckBox useExample;\n    @FXML\n    private CheckBox useDAOExtendStyle;\n    @FXML\n    private CheckBox useSchemaPrefix;\n    @FXML\n    private CheckBox jsr310Support;\n    @FXML\n    private TreeView<String> leftDBTree;\n    @FXML\n    public TextField filterTreeBox;\n    // Current selected databaseConfig\n    private DatabaseConfig selectedDatabaseConfig;\n    // Current selected tableName\n    private String tableName;\n\n    private List<IgnoredColumn> ignoredColumns;\n\n    private List<ColumnOverride> columnOverrides;\n\n    @FXML\n    private ChoiceBox<String> encodingChoice;\n\n    @Override\n    public void initialize(URL location, ResourceBundle resources) {\n        ImageView dbImage = new ImageView(\"icons/computer.png\");\n        dbImage.setFitHeight(40);\n        dbImage.setFitWidth(40);\n        connectionLabel.setGraphic(dbImage);\n        connectionLabel.setOnMouseClicked(event -> {\n            TabPaneController controller = (TabPaneController) loadFXMLPage(\"新建数据库连接\", FXMLPage.NEW_CONNECTION, false);\n            controller.setMainUIController(this);\n            controller.showDialogStage();\n        });\n        ImageView configImage = new ImageView(\"icons/config-list.png\");\n        configImage.setFitHeight(40);\n        configImage.setFitWidth(40);\n        configsLabel.setGraphic(configImage);\n        configsLabel.setOnMouseClicked(event -> {\n            GeneratorConfigController controller = (GeneratorConfigController) loadFXMLPage(\"配置\", FXMLPage.GENERATOR_CONFIG, false);\n            controller.setMainUIController(this);\n            controller.showDialogStage();\n        });\n\t\tuseExample.setOnMouseClicked(event -> {\n\t\t\tif (useExample.isSelected()) {\n\t\t\t\toffsetLimitCheckBox.setDisable(false);\n\t\t\t} else {\n\t\t\t\toffsetLimitCheckBox.setDisable(true);\n\t\t\t}\n\t\t});\n\t\t// selectedProperty().addListener 解决应用配置的时候未触发Clicked事件\n        useLombokPlugin.selectedProperty().addListener((observable, oldValue, newValue) -> {\n            needToStringHashcodeEquals.setDisable(newValue);\n        });\n\n        leftDBTree.setShowRoot(false);\n        leftDBTree.setRoot(new TreeItem<>());\n        Callback<TreeView<String>, TreeCell<String>> defaultCellFactory = TextFieldTreeCell.forTreeView();\n        filterTreeBox.addEventHandler(KeyEvent.KEY_PRESSED, ev -> {\n            if (ev.getCode() == KeyCode.ENTER) {\n                ObservableList<TreeItem<String>> schemas = leftDBTree.getRoot().getChildren();\n                schemas.filtered(TreeItem::isExpanded).forEach(this::displayTables);\n                ev.consume();\n            }\n        });\n        leftDBTree.setCellFactory((TreeView<String> tv) -> {\n            TreeCell<String> cell = defaultCellFactory.call(tv);\n\n            cell.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {\n                int level = leftDBTree.getTreeItemLevel(cell.getTreeItem());\n                TreeCell<String> treeCell = (TreeCell<String>) event.getSource();\n                TreeItem<String> treeItem = treeCell.getTreeItem();\n                if (level == 1) {\n                    final ContextMenu contextMenu = new ContextMenu();\n                    MenuItem item1 = new MenuItem(\"关闭连接\");\n                    item1.setOnAction(event1 -> treeItem.getChildren().clear());\n\t                MenuItem item2 = new MenuItem(\"编辑连接\");\n\t                item2.setOnAction(event1 -> {\n\t\t                DatabaseConfig selectedConfig = (DatabaseConfig) treeItem.getGraphic().getUserData();\n                        TabPaneController controller = (TabPaneController) loadFXMLPage(\"编辑数据库连接\", FXMLPage.NEW_CONNECTION, false);\n\t\t                controller.setMainUIController(this);\n\t\t                controller.setConfig(selectedConfig);\n\t\t                controller.showDialogStage();\n\t                });\n                    MenuItem item3 = new MenuItem(\"删除连接\");\n                    item3.setOnAction(event1 -> {\n                        DatabaseConfig selectedConfig = (DatabaseConfig) treeItem.getGraphic().getUserData();\n                        try {\n                            ConfigHelper.deleteDatabaseConfig(selectedConfig);\n                            this.loadLeftDBTree();\n                        } catch (Exception e) {\n                            AlertUtil.showErrorAlert(\"Delete connection failed! Reason: \" + e.getMessage());\n                        }\n                    });\n                    contextMenu.getItems().addAll(item1, item2, item3);\n                    cell.setContextMenu(contextMenu);\n                }\n                if (event.getClickCount() == 2) {\n                    if(treeItem == null) {\n                        return ;\n                    }\n                    treeItem.setExpanded(true);\n                    if (level == 1) {\n                        displayTables(treeItem);\n                    } else if (level == 2) { // left DB tree level3\n                        String tableName = treeCell.getTreeItem().getValue();\n                        selectedDatabaseConfig = (DatabaseConfig) treeItem.getParent().getGraphic().getUserData();\n                        this.tableName = tableName;\n                        tableNameField.setText(tableName);\n                        domainObjectNameField.setText(MyStringUtils.dbStringToCamelStyle(tableName));\n                        mapperName.setText(domainObjectNameField.getText().concat(\"DAO\"));\n                    }\n                }\n            });\n            return cell;\n        });\n        loadLeftDBTree();\n\t\tsetTooltip();\n\t\t//默认选中第一个，否则如果忘记选择，没有对应错误提示\n        encodingChoice.getSelectionModel().selectFirst();\n\t}\n\n\tprivate void displayTables(TreeItem<String> treeItem) {\n        if(treeItem == null) {\n            return ;\n        }\n        if (!treeItem.isExpanded()) {\n            return;\n        }\n        DatabaseConfig selectedConfig = (DatabaseConfig) treeItem.getGraphic().getUserData();\n        try {\n            String filter = filterTreeBox.getText();\n            List<String> tables = DbUtil.getTableNames(selectedConfig, filter);\n            if (tables.size() > 0) {\n                ObservableList<TreeItem<String>> children = treeItem.getChildren();\n                children.clear();\n                for (String tableName : tables) {\n                    TreeItem<String> newTreeItem = new TreeItem<>();\n                    ImageView imageView = new ImageView(\"icons/table.png\");\n                    imageView.setFitHeight(16);\n                    imageView.setFitWidth(16);\n                    newTreeItem.setGraphic(imageView);\n                    newTreeItem.setValue(tableName);\n                    children.add(newTreeItem);\n                }\n            }else if (StringUtils.isNotBlank(filter)){\n                treeItem.getChildren().clear();\n            }\n            if (StringUtils.isNotBlank(filter)) {\n                ImageView imageView = new ImageView(\"icons/filter.png\");\n                imageView.setFitHeight(16);\n                imageView.setFitWidth(16);\n                imageView.setUserData(treeItem.getGraphic().getUserData());\n                treeItem.setGraphic(imageView);\n            }else {\n                ImageView dbImage = new ImageView(\"icons/computer.png\");\n                dbImage.setFitHeight(16);\n                dbImage.setFitWidth(16);\n                dbImage.setUserData(treeItem.getGraphic().getUserData());\n                treeItem.setGraphic(dbImage);\n            }\n        } catch (SQLRecoverableException e) {\n            _LOG.error(e.getMessage(), e);\n            AlertUtil.showErrorAlert(\"连接超时\");\n        } catch (Exception e) {\n            _LOG.error(e.getMessage(), e);\n            AlertUtil.showErrorAlert(e.getMessage());\n        }\n    }\n\n\tprivate void setTooltip() {\n\t\tencodingChoice.setTooltip(new Tooltip(\"生成文件的编码，必选\"));\n\t\tgenerateKeysField.setTooltip(new Tooltip(\"insert时可以返回主键ID\"));\n\t\toffsetLimitCheckBox.setTooltip(new Tooltip(\"是否要生成分页查询代码\"));\n\t\tcommentCheckBox.setTooltip(new Tooltip(\"使用数据库的列注释作为实体类字段名的Java注释 \"));\n\t\tuseActualColumnNamesCheckbox.setTooltip(new Tooltip(\"是否使用数据库实际的列名作为实体类域的名称\"));\n\t\tuseTableNameAliasCheckbox.setTooltip(new Tooltip(\"在Mapper XML文件中表名使用别名，并且列全部使用as查询\"));\n\t\toverrideXML.setTooltip(new Tooltip(\"重新生成时把原XML文件覆盖，否则是追加\"));\n        useDAOExtendStyle.setTooltip(new Tooltip(\"将通用接口方法放在公共接口中，DAO接口留空\"));\n        forUpdateCheckBox.setTooltip(new Tooltip(\"在Select语句中增加for update后缀\"));\n        useLombokPlugin.setTooltip(new Tooltip(\"实体类使用Lombok @Data简化代码\"));\n\t}\n\n    void loadLeftDBTree() {\n        TreeItem rootTreeItem = leftDBTree.getRoot();\n        rootTreeItem.getChildren().clear();\n        try {\n            List<DatabaseConfig> dbConfigs = ConfigHelper.loadDatabaseConfig();\n            for (DatabaseConfig dbConfig : dbConfigs) {\n                TreeItem<String> treeItem = new TreeItem<>();\n                treeItem.setValue(dbConfig.getName());\n                ImageView dbImage = new ImageView(\"icons/computer.png\");\n                dbImage.setFitHeight(16);\n                dbImage.setFitWidth(16);\n                dbImage.setUserData(dbConfig);\n                treeItem.setGraphic(dbImage);\n                rootTreeItem.getChildren().add(treeItem);\n            }\n        } catch (Exception e) {\n            _LOG.error(\"connect db failed, reason\", e);\n            AlertUtil.showErrorAlert(e.getMessage() + \"\\n\" + ExceptionUtils.getStackTrace(e));\n        }\n    }\n\n    @FXML\n    public void chooseProjectFolder() {\n        DirectoryChooser directoryChooser = new DirectoryChooser();\n        File selectedFolder = directoryChooser.showDialog(getPrimaryStage());\n        if (selectedFolder != null) {\n            projectFolderField.setText(selectedFolder.getAbsolutePath());\n        }\n    }\n\n    @FXML\n    public void generateCode() {\n        if (tableName == null) {\n            AlertUtil.showWarnAlert(\"请先在左侧选择数据库表\");\n            return;\n        }\n        String result = validateConfig();\n\t\tif (result != null) {\n\t\t\tAlertUtil.showErrorAlert(result);\n\t\t\treturn;\n\t\t}\n        GeneratorConfig generatorConfig = getGeneratorConfigFromUI();\n        if (!checkDirs(generatorConfig)) {\n            return;\n        }\n\n        MybatisGeneratorBridge bridge = new MybatisGeneratorBridge();\n        bridge.setGeneratorConfig(generatorConfig);\n        bridge.setDatabaseConfig(selectedDatabaseConfig);\n        bridge.setIgnoredColumns(ignoredColumns);\n        bridge.setColumnOverrides(columnOverrides);\n        UIProgressCallback alert = new UIProgressCallback(Alert.AlertType.INFORMATION);\n        bridge.setProgressCallback(alert);\n        alert.show();\n        PictureProcessStateController pictureProcessStateController = null;\n        try {\n            //Engage PortForwarding\n            Session sshSession = DbUtil.getSSHSession(selectedDatabaseConfig);\n            DbUtil.engagePortForwarding(sshSession, selectedDatabaseConfig);\n\n            if (sshSession != null) {\n                pictureProcessStateController = new PictureProcessStateController();\n                pictureProcessStateController.setDialogStage(getDialogStage());\n                pictureProcessStateController.startPlay();\n            }\n\n            bridge.generate();\n\n            if (pictureProcessStateController != null) {\n                Task task = new Task<Void>() {\n                    @Override\n                    protected Void call() throws Exception {\n                        Thread.sleep(3000);\n                        return null;\n                    }\n                };\n                PictureProcessStateController finalPictureProcessStateController = pictureProcessStateController;\n                task.setOnSucceeded(event -> {\n                    finalPictureProcessStateController.close();\n                });\n                task.setOnFailed(event -> {\n                    finalPictureProcessStateController.close();\n                });\n                new Thread(task).start();\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            AlertUtil.showErrorAlert(e.getMessage());\n            if (pictureProcessStateController != null) {\n                pictureProcessStateController.close();\n                pictureProcessStateController.playFailState(e.getMessage(), true);\n            }\n        }\n    }\n\n\tprivate String validateConfig() {\n\t\tString projectFolder = projectFolderField.getText();\n\t\tif (StringUtils.isEmpty(projectFolder))  {\n\t\t\treturn \"项目目录不能为空\";\n\t\t}\n\t\tif (StringUtils.isEmpty(domainObjectNameField.getText()))  {\n\t\t\treturn \"类名不能为空\";\n\t\t}\n\t\tif (StringUtils.isAnyEmpty(modelTargetPackage.getText(), mapperTargetPackage.getText(), daoTargetPackage.getText())) {\n\t\t\treturn \"包名不能为空\";\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t@FXML\n    public void saveGeneratorConfig() {\n        TextInputDialog dialog = new TextInputDialog(\"\");\n        dialog.setTitle(\"保存当前配置\");\n        dialog.setContentText(\"请输入配置名称\");\n        Optional<String> result = dialog.showAndWait();\n        if (result.isPresent()) {\n            String name = result.get();\n            if (StringUtils.isEmpty(name)) {\n                AlertUtil.showErrorAlert(\"名称不能为空\");\n                return;\n            }\n            _LOG.info(\"user choose name: {}\", name);\n            try {\n                GeneratorConfig generatorConfig = getGeneratorConfigFromUI();\n                generatorConfig.setName(name);\n                ConfigHelper.deleteGeneratorConfig(name);\n                ConfigHelper.saveGeneratorConfig(generatorConfig);\n            } catch (Exception e) {\n                _LOG.error(\"保存配置失败\", e);\n                AlertUtil.showErrorAlert(\"保存配置失败\");\n            }\n        }\n    }\n\n    public GeneratorConfig getGeneratorConfigFromUI() {\n        GeneratorConfig generatorConfig = new GeneratorConfig();\n        generatorConfig.setProjectFolder(projectFolderField.getText());\n        generatorConfig.setModelPackage(modelTargetPackage.getText());\n        generatorConfig.setGenerateKeys(generateKeysField.getText());\n        generatorConfig.setModelPackageTargetFolder(modelTargetProject.getText());\n        generatorConfig.setDaoPackage(daoTargetPackage.getText());\n        generatorConfig.setDaoTargetFolder(daoTargetProject.getText());\n        generatorConfig.setMapperName(mapperName.getText());\n        generatorConfig.setMappingXMLPackage(mapperTargetPackage.getText());\n        generatorConfig.setMappingXMLTargetFolder(mappingTargetProject.getText());\n        generatorConfig.setTableName(tableNameField.getText());\n        generatorConfig.setDomainObjectName(domainObjectNameField.getText());\n        generatorConfig.setOffsetLimit(offsetLimitCheckBox.isSelected());\n        generatorConfig.setComment(commentCheckBox.isSelected());\n        generatorConfig.setOverrideXML(overrideXML.isSelected());\n        generatorConfig.setNeedToStringHashcodeEquals(needToStringHashcodeEquals.isSelected());\n        generatorConfig.setUseLombokPlugin(useLombokPlugin.isSelected());\n        generatorConfig.setUseTableNameAlias(useTableNameAliasCheckbox.isSelected());\n        generatorConfig.setNeedForUpdate(forUpdateCheckBox.isSelected());\n        generatorConfig.setAnnotationDAO(annotationDAOCheckBox.isSelected());\n        generatorConfig.setAnnotation(annotationCheckBox.isSelected());\n        generatorConfig.setUseActualColumnNames(useActualColumnNamesCheckbox.isSelected());\n        generatorConfig.setEncoding(encodingChoice.getValue());\n        generatorConfig.setUseExample(useExample.isSelected());\n        generatorConfig.setUseDAOExtendStyle(useDAOExtendStyle.isSelected());\n        generatorConfig.setUseSchemaPrefix(useSchemaPrefix.isSelected());\n        generatorConfig.setJsr310Support(jsr310Support.isSelected());\n        return generatorConfig;\n    }\n\n    public void setGeneratorConfigIntoUI(GeneratorConfig generatorConfig) {\n        projectFolderField.setText(generatorConfig.getProjectFolder());\n        modelTargetPackage.setText(generatorConfig.getModelPackage());\n        generateKeysField.setText(generatorConfig.getGenerateKeys());\n        modelTargetProject.setText(generatorConfig.getModelPackageTargetFolder());\n        daoTargetPackage.setText(generatorConfig.getDaoPackage());\n\t\tdaoTargetProject.setText(generatorConfig.getDaoTargetFolder());\n\t\tmapperTargetPackage.setText(generatorConfig.getMappingXMLPackage());\n        mappingTargetProject.setText(generatorConfig.getMappingXMLTargetFolder());\n        if (StringUtils.isBlank(tableNameField.getText())) {\n            tableNameField.setText(generatorConfig.getTableName());\n            mapperName.setText(generatorConfig.getMapperName());\n            domainObjectNameField.setText(generatorConfig.getDomainObjectName());\n        }\n        offsetLimitCheckBox.setSelected(generatorConfig.isOffsetLimit());\n        commentCheckBox.setSelected(generatorConfig.isComment());\n        overrideXML.setSelected(generatorConfig.isOverrideXML());\n        needToStringHashcodeEquals.setSelected(generatorConfig.isNeedToStringHashcodeEquals());\n        useLombokPlugin.setSelected(generatorConfig.isUseLombokPlugin());\n        useTableNameAliasCheckbox.setSelected(generatorConfig.getUseTableNameAlias());\n        forUpdateCheckBox.setSelected(generatorConfig.isNeedForUpdate());\n        annotationDAOCheckBox.setSelected(generatorConfig.isAnnotationDAO());\n        annotationCheckBox.setSelected(generatorConfig.isAnnotation());\n        useActualColumnNamesCheckbox.setSelected(generatorConfig.isUseActualColumnNames());\n        encodingChoice.setValue(generatorConfig.getEncoding());\n        useExample.setSelected(generatorConfig.isUseExample());\n        useDAOExtendStyle.setSelected(generatorConfig.isUseDAOExtendStyle());\n        useSchemaPrefix.setSelected(generatorConfig.isUseSchemaPrefix());\n        jsr310Support.setSelected(generatorConfig.isJsr310Support());\n    }\n\n    @FXML\n    public void openTableColumnCustomizationPage() {\n        if (tableName == null) {\n            AlertUtil.showWarnAlert(\"请先在左侧选择数据库表\");\n            return;\n        }\n        SelectTableColumnController controller = (SelectTableColumnController) loadFXMLPage(\"定制列\", FXMLPage.SELECT_TABLE_COLUMN, true);\n        controller.setMainUIController(this);\n        try {\n            // If select same schema and another table, update table data\n            if (!tableName.equals(controller.getTableName())) {\n                List<UITableColumnVO> tableColumns = DbUtil.getTableColumns(selectedDatabaseConfig, tableName);\n                controller.setColumnList(FXCollections.observableList(tableColumns));\n                controller.setTableName(tableName);\n            }\n            controller.showDialogStage();\n        } catch (Exception e) {\n            _LOG.error(e.getMessage(), e);\n            AlertUtil.showErrorAlert(e.getMessage());\n        }\n    }\n\n    public void setIgnoredColumns(List<IgnoredColumn> ignoredColumns) {\n        this.ignoredColumns = ignoredColumns;\n    }\n\n    public void setColumnOverrides(List<ColumnOverride> columnOverrides) {\n        this.columnOverrides = columnOverrides;\n    }\n\n    /**\n     * 检查并创建不存在的文件夹\n     *\n     * @return\n     */\n    private boolean checkDirs(GeneratorConfig config) {\n\t\tList<String> dirs = new ArrayList<>();\n\t\tdirs.add(config.getProjectFolder());\n\t\tdirs.add(config.getProjectFolder().concat(\"/\").concat(config.getModelPackageTargetFolder()));\n\t\tdirs.add(config.getProjectFolder().concat(\"/\").concat(config.getDaoTargetFolder()));\n\t\tdirs.add(config.getProjectFolder().concat(\"/\").concat(config.getMappingXMLTargetFolder()));\n\t\tboolean haveNotExistFolder = false;\n\t\tfor (String dir : dirs) {\n\t\t\tFile file = new File(dir);\n\t\t\tif (!file.exists()) {\n\t\t\t\thaveNotExistFolder = true;\n\t\t\t}\n\t\t}\n\t\tif (haveNotExistFolder) {\n\t\t\tAlert alert = new Alert(Alert.AlertType.CONFIRMATION);\n\t\t\talert.setContentText(FOLDER_NO_EXIST);\n\t\t\tOptional<ButtonType> optional = alert.showAndWait();\n\t\t\tif (optional.isPresent()) {\n\t\t\t\tif (ButtonType.OK == optional.get()) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfor (String dir : dirs) {\n\t\t\t\t\t\t\tFileUtils.forceMkdir(new File(dir));\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tAlertUtil.showErrorAlert(\"创建目录失败，请检查目录是否是文件而非目录\");\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n        return true;\n    }\n\n    @FXML\n    public void openTargetFolder() {\n        GeneratorConfig generatorConfig = getGeneratorConfigFromUI();\n        String projectFolder = generatorConfig.getProjectFolder();\n        try {\n            Desktop.getDesktop().browse(new File(projectFolder).toURI());\n        }catch (Exception e) {\n            AlertUtil.showErrorAlert(\"打开目录失败，请检查目录是否填写正确\" + e.getMessage());\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/controller/OverSshController.java",
    "content": "package com.zzg.mybatis.generator.controller;\n\nimport com.jcraft.jsch.JSchException;\nimport com.jcraft.jsch.Session;\nimport com.zzg.mybatis.generator.model.DatabaseConfig;\nimport com.zzg.mybatis.generator.util.ConfigHelper;\nimport com.zzg.mybatis.generator.util.DbUtil;\nimport com.zzg.mybatis.generator.view.AlertUtil;\nimport javafx.event.ActionEvent;\nimport javafx.fxml.FXML;\nimport javafx.scene.control.ChoiceBox;\nimport javafx.scene.control.Label;\nimport javafx.scene.control.PasswordField;\nimport javafx.scene.control.TextField;\nimport javafx.scene.layout.HBox;\nimport javafx.scene.paint.Paint;\nimport javafx.stage.FileChooser;\nimport org.apache.commons.lang3.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.File;\nimport java.net.URL;\nimport java.util.ResourceBundle;\nimport java.util.concurrent.*;\n\n/**\n * Project: mybatis-generator-gui\n *\n * @author slankka on 2018/12/30.\n */\npublic class OverSshController extends DbConnectionController {\n\n    private Logger logger = LoggerFactory.getLogger(OverSshController.class);\n\n    @FXML\n    public HBox pubkeyBox;\n    @FXML\n    public Label lPortLabel;\n    @FXML\n    public TextField sshUserField;\n    @FXML\n    public ChoiceBox<String> authTypeChoice;\n    @FXML\n    public Label sshPasswordLabel;\n    @FXML\n    public PasswordField sshPasswordField;\n    @FXML\n    private TextField sshHostField;\n    @FXML\n    private TextField sshdPortField;\n    @FXML\n    private TextField lportField;\n    @FXML\n    private TextField rportField;\n    @FXML\n    private Label note;\n    @FXML\n    private Label pubkeyBoxLabel;\n    @FXML\n    private TextField sshPubKeyField;\n    @FXML\n    public PasswordField sshPubkeyPasswordField;\n    @FXML\n    public Label sshPubkeyPasswordLabel;\n    @FXML\n    public Label sshPubkeyPasswordNote;\n\n    private FileChooser fileChooser = new FileChooser();\n\n    private File privateKey;\n    @Override\n    public void initialize(URL location, ResourceBundle resources) {\n        fileChooser.setTitle(\"选择SSH秘钥文件\");\n        fileChooser.setInitialDirectory(new File(System.getProperty(\"user.home\")));\n        authTypeChoice.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {\n            if (\"PubKey\".equals(newValue)) {\n                //公钥认证\n                sshPasswordField.setVisible(false);\n                sshPasswordLabel.setVisible(false);\n                pubkeyBox.setVisible(true);\n                pubkeyBoxLabel.setVisible(true);\n                sshPubkeyPasswordField.setVisible(true);\n                sshPubkeyPasswordLabel.setVisible(true);\n                sshPubkeyPasswordNote.setVisible(true);\n            }else {\n                //密码认证\n                pubkeyBox.setVisible(false);\n                pubkeyBoxLabel.setVisible(false);\n                sshPubkeyPasswordField.setVisible(false);\n                sshPubkeyPasswordLabel.setVisible(false);\n                sshPubkeyPasswordNote.setVisible(false);\n                sshPasswordLabel.setVisible(true);\n                sshPasswordField.setVisible(true);\n            }\n        });\n    }\n\n    public void setDbConnectionConfig(DatabaseConfig databaseConfig) {\n        if (databaseConfig == null) {\n            return;\n        }\n        isUpdate = true;\n        super.setConfig(databaseConfig);\n        this.sshdPortField.setText(databaseConfig.getSshPort());\n        this.sshHostField.setText(databaseConfig.getSshHost());\n        this.lportField.setText(databaseConfig.getLport());\n        this.rportField.setText(databaseConfig.getRport());\n        this.sshUserField.setText(databaseConfig.getSshUser());\n        this.sshPasswordField.setText(databaseConfig.getSshPassword());\n        //例如：默认从本机的 3306 -> 转发到 3306\n        if (StringUtils.isBlank(this.lportField.getText())) {\n            this.lportField.setText(databaseConfig.getPort());\n        }\n        if (StringUtils.isBlank(this.rportField.getText())) {\n            this.rportField.setText(databaseConfig.getPort());\n        }\n        if (StringUtils.isNotBlank(databaseConfig.getPrivateKey())) {\n            this.sshPubKeyField.setText(databaseConfig.getPrivateKey());\n            this.sshPubkeyPasswordField.setText(databaseConfig.getPrivateKeyPassword());\n            authTypeChoice.getSelectionModel().select(\"PubKey\");\n        }\n        checkInput();\n    }\n\n    @FXML\n    public void checkInput() {\n        DatabaseConfig databaseConfig = extractConfigFromUi();\n        if (authTypeChoice.getValue().equals(\"Password\") && (\n            StringUtils.isBlank(databaseConfig.getSshHost())\n                || StringUtils.isBlank(databaseConfig.getSshPort())\n                || StringUtils.isBlank(databaseConfig.getSshUser())\n                || StringUtils.isBlank(databaseConfig.getSshPassword())\n        )\n            || authTypeChoice.getValue().equals(\"PubKey\") && (\n            StringUtils.isBlank(databaseConfig.getSshHost())\n                || StringUtils.isBlank(databaseConfig.getSshPort())\n                || StringUtils.isBlank(databaseConfig.getSshUser())\n                || StringUtils.isBlank(databaseConfig.getPrivateKey())\n        )\n        ) {\n            note.setText(\"当前SSH配置输入不完整，OVER SSH不生效\");\n            note.setTextFill(Paint.valueOf(\"#ff666f\"));\n        } else {\n            note.setText(\"当前SSH配置生效\");\n            note.setTextFill(Paint.valueOf(\"#5da355\"));\n        }\n    }\n\n    public void setLPortLabelText(String text) {\n        lPortLabel.setText(text);\n    }\n\n    public void recoverNotice() {\n        this.lPortLabel.setText(\"注意不要填写被其他程序占用的端口\");\n    }\n\n    public DatabaseConfig extractConfigFromUi() {\n        String name = nameField.getText();\n        String host = hostField.getText();\n        String port = portField.getText();\n        String userName = userNameField.getText();\n        String password = passwordField.getText();\n        String encoding = encodingChoice.getValue();\n        String dbType = dbTypeChoice.getValue();\n        String schema = schemaField.getText();\n        String authType = authTypeChoice.getValue();\n        DatabaseConfig config = new DatabaseConfig();\n        config.setName(name);\n        config.setDbType(dbType);\n        config.setHost(host);\n        config.setPort(port);\n        config.setUsername(userName);\n        config.setPassword(password);\n        config.setSchema(schema);\n        config.setEncoding(encoding);\n        config.setSshHost(this.sshHostField.getText());\n        config.setSshPort(this.sshdPortField.getText());\n        config.setLport(this.lportField.getText());\n        config.setRport(this.rportField.getText());\n        config.setSshUser(this.sshUserField.getText());\n        config.setSshPassword(this.sshPasswordField.getText());\n        if (\"PubKey\".equals(authType)) {\n            config.setPrivateKey(this.privateKey.getAbsolutePath());\n            config.setPrivateKeyPassword(this.sshPubkeyPasswordField.getText());\n        }\n        return config;\n    }\n\n    public void saveConfig() {\n        DatabaseConfig databaseConfig = extractConfigFromUi();\n        if (StringUtils.isAnyEmpty(\n                databaseConfig.getName(),\n                databaseConfig.getHost(),\n                databaseConfig.getPort(),\n                databaseConfig.getUsername(),\n                databaseConfig.getEncoding(),\n                databaseConfig.getDbType(),\n                databaseConfig.getSchema())) {\n            AlertUtil.showWarnAlert(\"密码以外其他字段必填\");\n            return;\n        }\n        try {\n            ConfigHelper.saveDatabaseConfig(this.isUpdate, primayKey, databaseConfig);\n            this.tabPaneController.getDialogStage().close();\n            mainUIController.loadLeftDBTree();\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n            AlertUtil.showErrorAlert(e.getMessage());\n        }\n    }\n\n    @FXML\n    public void testSSH() {\n        Session session = DbUtil.getSSHSession(extractConfigFromUi());\n        if (session == null) {\n            AlertUtil.showErrorAlert(\"请检查主机，端口，用户名，以及密码/秘钥是否填写正确\");\n            return;\n        }\n        ExecutorService executorService = Executors.newSingleThreadExecutor();\n        Future<?> result = executorService.submit(() -> {\n            try {\n                session.connect();\n            } catch (JSchException e) {\n                logger.error(\"Connect Over SSH failed\", e);\n                throw new RuntimeException(e.getMessage());\n            }\n        });\n        executorService.shutdown();\n        try {\n            boolean b = executorService.awaitTermination(5, TimeUnit.SECONDS);\n            if (!b) {\n                throw new TimeoutException(\"连接超时\");\n            }\n            result.get();\n            AlertUtil.showInfoAlert(\"连接SSH服务器成功，恭喜你可以使用OverSSH功能\");\n            recoverNotice();\n        } catch (Exception e) {\n            AlertUtil.showErrorAlert(\"请检查主机，端口，用户名，以及密码/秘钥是否填写正确: \" + e.getMessage());\n        } finally {\n            DbUtil.shutdownPortForwarding(session);\n        }\n    }\n\n    @FXML\n    public void reset(ActionEvent actionEvent) {\n        this.sshUserField.clear();\n        this.sshPasswordField.clear();\n        this.sshdPortField.clear();\n        this.sshHostField.clear();\n        this.lportField.clear();\n        this.rportField.clear();\n        this.sshPubKeyField.clear();\n        recoverNotice();\n    }\n\n    public void choosePubKey(ActionEvent actionEvent) {\n        this.privateKey = fileChooser.showOpenDialog(getDialogStage());\n        sshPubKeyField.setText(this.privateKey.getAbsolutePath());\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/controller/PictureProcessStateController.java",
    "content": "package com.zzg.mybatis.generator.controller;\n\nimport javafx.animation.RotateTransition;\nimport javafx.animation.Timeline;\nimport javafx.geometry.Insets;\nimport javafx.geometry.Pos;\nimport javafx.scene.Group;\nimport javafx.scene.Scene;\nimport javafx.scene.control.Button;\nimport javafx.scene.image.Image;\nimport javafx.scene.image.ImageView;\nimport javafx.scene.layout.HBox;\nimport javafx.scene.layout.VBox;\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Rectangle;\nimport javafx.scene.text.Font;\nimport javafx.scene.text.Text;\nimport javafx.stage.Modality;\nimport javafx.stage.Stage;\nimport javafx.stage.StageStyle;\nimport javafx.util.Duration;\n\n\nimport static javafx.scene.paint.Color.DARKSEAGREEN;\n\npublic class PictureProcessStateController {\n    private ImageView dbImage = new ImageView(\"icons/SSH_tunnel.png\");\n    private final Rectangle rect = new Rectangle(20, 20, 30, 30);\n    private final RotateTransition rotateTransition = new RotateTransition();\n    private final Text text = new Text(\"\");\n    private final Stage dialogStage = new Stage(StageStyle.TRANSPARENT);\n    private double initX;\n    private double initY;\n    private Stage parentStage;\n    private final Button button = new Button(\"\");\n    public void setDialogStage(Stage stage) {\n        this.parentStage = stage;\n    }\n\n    public void startPlay() {\n        dbImage.setFitHeight(192);\n        dbImage.setFitWidth(798);\n        Group rootGroup = new Group();\n        Scene scene = new Scene(rootGroup, 800, 212, Color.TRANSPARENT);\n        dialogStage.initModality(Modality.APPLICATION_MODAL);\n        dialogStage.setScene(scene);\n        dialogStage.initOwner(parentStage);\n        dialogStage.centerOnScreen();\n        dialogStage.setTitle(\"OverSSH\");\n\n        rect.setArcHeight(10);\n        rect.setArcWidth(10);\n        rect.setFill(DARKSEAGREEN);\n\n        rotateTransition.setNode(rect);\n        rotateTransition.setDuration(Duration.seconds(0.8d));\n        rotateTransition.setFromAngle(0);\n        rotateTransition.setToAngle(720);\n        rotateTransition.setCycleCount(Timeline.INDEFINITE);\n        rotateTransition.setAutoReverse(true);\n        VBox vBoxRect = new VBox();\n        vBoxRect.setAlignment(Pos.TOP_CENTER);\n        vBoxRect.getChildren().add(rect);\n        VBox.setMargin(rect, new Insets(125, 0, 0, 350));\n        rotateTransition.play();\n\n\n        text.setFont(Font.font(12));\n        VBox vBoxLabel = new VBox();\n        vBoxLabel.getChildren().add(text);\n        VBox.setMargin(text, new Insets(175, 0, 15, 40));\n\n\n        button.setPrefSize(90, 40);\n        HBox hBoxButton = new HBox();\n        hBoxButton.setPrefSize(505, 170);\n        hBoxButton.getChildren().add(button);\n        hBoxButton.setAlignment(Pos.BOTTOM_RIGHT);\n        hBoxButton.getStylesheets().add(Thread.currentThread().getContextClassLoader().getResource(\"style.css\").toExternalForm());\n        HBox.setMargin(button, new Insets(0, 15, 5, 0));\n        button.setStyle(\"-fx-border-width: 0px;\");\n        button.setStyle(\"-fx-border-color: transparent;\");\n        button.setStyle(\"-fx-background-color: transparent;\");\n        rootGroup.getChildren().addAll(dbImage, vBoxRect, vBoxLabel, hBoxButton);\n        dialogStage.show();\n\n        button.setOnMouseClicked((event) -> dialogStage.close());\n\n        rootGroup.setOnMousePressed((me) -> {\n                initX = me.getScreenX() - dialogStage.getX();\n                initY = me.getScreenY() - dialogStage.getY();\n        });\n        rootGroup.setOnMouseDragged((me) -> {\n            dialogStage.setX(me.getScreenX() - initX);\n            dialogStage.setY(me.getScreenY() - initY);\n        });\n    }\n\n    public void playFailState(String message, boolean showButton) {\n        rect.setFill(Color.ORANGERED);\n        rotateTransition.stop();\n        dbImage.setImage(new Image(\"icons/SSH_tunnel_disconnected.png\"));\n        rotateTransition.setDuration(Duration.seconds(3));\n        rotateTransition.play();\n        text.setText(message);\n        if (showButton) {\n            showCloseButton();\n        }\n        if (!dialogStage.isShowing()) {\n            dialogStage.show();\n        }\n    }\n\n    private void showCloseButton() {\n        button.getStyleClass().add(\"btn\");\n        button.getStyleClass().add(\"btn-default\");\n        button.setStyle(\"-fx-border-width: 1px;\");\n        button.setStyle(\"-fx-background-color: #fff;\");\n        button.setText(\"我知道了\");\n    }\n\n    public void playSuccessState(String message, boolean showButton) {\n        rect.setFill(DARKSEAGREEN);\n        rotateTransition.stop();\n        dbImage.setImage(new Image(\"icons/SSH_tunnel.png\"));\n        rotateTransition.setDuration(Duration.seconds(0.8));\n        rotateTransition.play();\n        text.setText(message);\n        if (showButton) {\n            showCloseButton();\n        }\n    }\n\n    public void close() {\n        dialogStage.close();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/controller/SelectTableColumnController.java",
    "content": "package com.zzg.mybatis.generator.controller;\n\nimport com.zzg.mybatis.generator.model.UITableColumnVO;\nimport javafx.collections.ObservableList;\nimport javafx.fxml.FXML;\nimport javafx.scene.control.TableColumn;\nimport javafx.scene.control.TableView;\nimport javafx.scene.control.cell.CheckBoxTableCell;\nimport javafx.scene.control.cell.PropertyValueFactory;\nimport javafx.scene.control.cell.TextFieldTableCell;\nimport org.mybatis.generator.config.ColumnOverride;\nimport org.mybatis.generator.config.IgnoredColumn;\n\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.ResourceBundle;\n\n/**\n * Created by Owen on 6/20/16.\n */\npublic class SelectTableColumnController extends BaseFXController {\n\n    @FXML\n    private TableView<UITableColumnVO> columnListView;\n    @FXML\n    private TableColumn<UITableColumnVO, Boolean> checkedColumn;\n    @FXML\n    private TableColumn<UITableColumnVO, String> columnNameColumn;\n    @FXML\n    private TableColumn<UITableColumnVO, String> jdbcTypeColumn;\n    @FXML\n    private TableColumn<UITableColumnVO, String> javaTypeColumn;\n    @FXML\n    private TableColumn<UITableColumnVO, String> propertyNameColumn;\n    @FXML\n    private TableColumn<UITableColumnVO, String> typeHandlerColumn;\n\n    private MainUIController mainUIController;\n\n    private String tableName;\n\n    @Override\n    public void initialize(URL location, ResourceBundle resources) {\n        // cellvaluefactory\n        checkedColumn.setCellValueFactory(new PropertyValueFactory<>(\"checked\"));\n        columnNameColumn.setCellValueFactory(new PropertyValueFactory<>(\"columnName\"));\n        jdbcTypeColumn.setCellValueFactory(new PropertyValueFactory<>(\"jdbcType\"));\n        propertyNameColumn.setCellValueFactory(new PropertyValueFactory<>(\"propertyName\"));\n        typeHandlerColumn.setCellValueFactory(new PropertyValueFactory<>(\"typeHandler\"));\n        // Cell Factory that customize how the cell should render\n        checkedColumn.setCellFactory(CheckBoxTableCell.forTableColumn(checkedColumn));\n        jdbcTypeColumn.setCellFactory(TextFieldTableCell.forTableColumn());\n        // handle commit event to save the user input data\n        jdbcTypeColumn.setOnEditCommit(event -> {\n            event.getTableView().getItems().get(event.getTablePosition().getRow()).setJdbcType(event.getNewValue());\n        });\n        javaTypeColumn.setCellFactory(TextFieldTableCell.forTableColumn());\n        // handle commit event to save the user input data\n        javaTypeColumn.setOnEditCommit(event -> {\n            event.getTableView().getItems().get(event.getTablePosition().getRow()).setJavaType(event.getNewValue());\n        });\n        propertyNameColumn.setCellFactory(TextFieldTableCell.forTableColumn());\n        propertyNameColumn.setOnEditCommit(event -> {\n            event.getTableView().getItems().get(event.getTablePosition().getRow()).setPropertyName(event.getNewValue());\n        });\n        typeHandlerColumn.setCellFactory(TextFieldTableCell.forTableColumn());\n        typeHandlerColumn.setOnEditCommit(event -> {\n            event.getTableView().getItems().get(event.getTablePosition().getRow()).setTypeHandle(event.getNewValue());\n        });\n    }\n\n    @FXML\n    public void ok() {\n        ObservableList<UITableColumnVO> items = columnListView.getItems();\n        if (items != null && items.size() > 0) {\n            List<IgnoredColumn> ignoredColumns = new ArrayList<>();\n            List<ColumnOverride> columnOverrides = new ArrayList<>();\n            items.stream().forEach(item -> {\n                if (!item.getChecked()) {\n                    IgnoredColumn ignoredColumn = new IgnoredColumn(item.getColumnName());\n                    ignoredColumns.add(ignoredColumn);\n                } else if (item.getTypeHandle() != null || item.getJavaType() != null || item.getPropertyName() != null) { // unchecked and have typeHandler value\n                    ColumnOverride columnOverride = new ColumnOverride(item.getColumnName());\n                    columnOverride.setTypeHandler(item.getTypeHandle());\n                    columnOverride.setJdbcType(item.getJdbcType());\n                    columnOverride.setJavaProperty(item.getPropertyName());\n                    columnOverride.setJavaType(item.getJavaType());\n                    columnOverrides.add(columnOverride);\n                }\n            });\n            mainUIController.setIgnoredColumns(ignoredColumns);\n            mainUIController.setColumnOverrides(columnOverrides);\n        }\n        getDialogStage().close();\n    }\n\n    @FXML\n    public void cancel() {\n        getDialogStage().close();\n    }\n\n    @FXML\n    public void configAction() {\n        TableColumnConfigsController controller = (TableColumnConfigsController) loadFXMLPage(\"定制列配置\", FXMLPage.TABLE_COLUMN_CONFIG,true);\n        controller.setColumnListView(this.columnListView);\n        controller.setTableName(this.tableName);\n        controller.showDialogStage();\n    }\n\n    public void setColumnList(ObservableList<UITableColumnVO> columns) {\n        columnListView.setItems(columns);\n    }\n\n    public void setMainUIController(MainUIController mainUIController) {\n        this.mainUIController = mainUIController;\n    }\n\n    public String getTableName() {\n        return tableName;\n    }\n\n    public void setTableName(String tableName) {\n        this.tableName = tableName;\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/controller/TabPaneController.java",
    "content": "package com.zzg.mybatis.generator.controller;\n\nimport com.jcraft.jsch.Session;\nimport com.zzg.mybatis.generator.model.DatabaseConfig;\nimport com.zzg.mybatis.generator.util.DbUtil;\nimport com.zzg.mybatis.generator.view.AlertUtil;\nimport javafx.concurrent.Task;\nimport javafx.fxml.FXML;\nimport javafx.scene.control.TabPane;\nimport javafx.scene.layout.AnchorPane;\nimport org.apache.commons.lang3.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.EOFException;\nimport java.net.URL;\nimport java.util.ResourceBundle;\n\n/**\n * Project: mybatis-generator-gui\n *\n * @author github.com/slankka on 2019/1/22.\n */\npublic class TabPaneController extends BaseFXController {\n    private static Logger logger = LoggerFactory.getLogger(TabPaneController.class);\n\n    @FXML\n    private TabPane tabPane;\n\n    @FXML\n    private DbConnectionController tabControlAController;\n\n    @FXML\n    private OverSshController tabControlBController;\n\n    private boolean isOverssh;\n\n    private MainUIController mainUIController;\n\n    @Override\n    public void initialize(URL location, ResourceBundle resources) {\n        tabPane.setPrefHeight(((AnchorPane) tabPane.getSelectionModel().getSelectedItem().getContent()).getPrefHeight());\n        tabPane.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {\n            isOverssh = observable.getValue().getText().equals(\"SSH\");\n            tabPane.prefHeightProperty().bind(((AnchorPane) tabPane.getSelectionModel().getSelectedItem().getContent()).prefHeightProperty());\n            getDialogStage().close();\n            getDialogStage().show();\n        });\n    }\n\n    public void setMainUIController(MainUIController mainUIController) {\n        this.mainUIController = mainUIController;\n        this.tabControlAController.setMainUIController(mainUIController);\n        this.tabControlAController.setTabPaneController(this);\n        this.tabControlBController.setMainUIController(mainUIController);\n        this.tabControlBController.setTabPaneController(this);\n    }\n\n    public void setConfig(DatabaseConfig selectedConfig) {\n        tabControlAController.setConfig(selectedConfig);\n        tabControlBController.setDbConnectionConfig(selectedConfig);\n        if (StringUtils.isNoneBlank(\n                selectedConfig.getSshHost(),\n                selectedConfig.getSshPassword(),\n                selectedConfig.getSshPort(),\n                selectedConfig.getSshUser(),\n                selectedConfig.getLport())) {\n            logger.info(\"Found SSH based Config\");\n            tabPane.getSelectionModel().selectLast();\n        }\n    }\n\n    private DatabaseConfig extractConfigForUI() {\n        if (isOverssh) {\n            return tabControlBController.extractConfigFromUi();\n        } else {\n            return tabControlAController.extractConfigForUI();\n        }\n    }\n\n    @FXML\n    void saveConnection() {\n        if (isOverssh) {\n            tabControlBController.saveConfig();\n        } else {\n            tabControlAController.saveConnection();\n        }\n    }\n\n\n    @FXML\n    void testConnection() {\n        DatabaseConfig config = extractConfigForUI();\n        if (config == null) {\n            return;\n        }\n        if (StringUtils.isAnyEmpty(config.getName(),\n                config.getHost(),\n                config.getPort(),\n                config.getUsername(),\n                config.getEncoding(),\n                config.getDbType(),\n                config.getSchema())) {\n            AlertUtil.showWarnAlert(\"密码以外其他字段必填\");\n            return;\n        }\n        Session sshSession = DbUtil.getSSHSession(config);\n        if (isOverssh && sshSession != null) {\n            PictureProcessStateController pictureProcessState = new PictureProcessStateController();\n            pictureProcessState.setDialogStage(getDialogStage());\n            pictureProcessState.startPlay();\n            //如果不用异步，则视图会等方法返回才会显示\n            Task task = new Task<Void>() {\n                @Override\n                protected Void call() throws Exception {\n                    DbUtil.engagePortForwarding(sshSession, config);\n                    DbUtil.getConnection(config);\n                    return null;\n                }\n            };\n            task.setOnFailed(event -> {\n                Throwable e = task.getException();\n                logger.error(\"task Failed\", e);\n                if (e instanceof RuntimeException) {\n                    if (e.getMessage().equals(\"Address already in use: JVM_Bind\")) {\n                        tabControlBController.setLPortLabelText(config.getLport() + \"已经被占用，请换其他端口\");\n                    }\n                    //端口转发一定不成功，导致数据库连接不上\n                    pictureProcessState.playFailState(\"连接失败:\" + e.getMessage(), true);\n                    return;\n                }\n\n                if (e.getCause() instanceof EOFException) {\n                    pictureProcessState.playFailState(\"连接失败, 请检查数据库的主机名，并且检查端口和目标端口是否一致\", true);\n                    //端口转发已经成功，但是数据库连接不上，故需要释放连接\n                    DbUtil.shutdownPortForwarding(sshSession);\n                    return;\n                }\n                pictureProcessState.playFailState(\"连接失败:\" + e.getMessage(), true);\n                //可能是端口转发已经成功，但是数据库连接不上，故需要释放连接\n                DbUtil.shutdownPortForwarding(sshSession);\n            });\n            task.setOnSucceeded(event -> {\n                try {\n                    pictureProcessState.playSuccessState(\"连接成功\", true);\n                    DbUtil.shutdownPortForwarding(sshSession);\n                    tabControlBController.recoverNotice();\n                } catch (Exception e) {\n                    logger.error(\"\", e);\n                }\n            });\n            new Thread(task).start();\n        } else {\n            try {\n                DbUtil.getConnection(config);\n                AlertUtil.showInfoAlert(\"连接成功\");\n            } catch (RuntimeException e) {\n                logger.error(\"\", e);\n                AlertUtil.showWarnAlert(\"连接失败, \" + e.getMessage());\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n                AlertUtil.showWarnAlert(\"连接失败\");\n            }\n        }\n    }\n\n    @FXML\n    void cancel() {\n        getDialogStage().close();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/controller/TableColumnConfigsController.java",
    "content": "package com.zzg.mybatis.generator.controller;\n\nimport com.zzg.mybatis.generator.model.UITableColumnVO;\nimport com.zzg.mybatis.generator.view.AlertUtil;\nimport javafx.collections.ObservableList;\nimport javafx.fxml.FXML;\nimport javafx.scene.control.Label;\nimport javafx.scene.control.TableView;\nimport javafx.scene.control.TextField;\nimport org.apache.commons.collections.CollectionUtils;\nimport org.apache.commons.lang3.StringUtils;\nimport org.mybatis.generator.internal.util.JavaBeansUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.net.URL;\nimport java.util.ResourceBundle;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * 定制列配置UI Controller\n *\n * @author xueqi\n * @date 2021-06-24\n */\npublic class TableColumnConfigsController extends BaseFXController {\n\n\tprivate static final Logger _LOG                  = LoggerFactory.getLogger(TableColumnConfigsController.class);\n\tprivate static final String COL_NAME_PREFIX_REGEX = \"(?<=%s)[^\\\"]+\";   // pattern regex and split prefix: (?<=aggregate_|f_)[^\"]+  f_ or d_ prefix\n\tprivate static final String OR_REGEX              = \"|\";\n\n\t@FXML\n\tprivate Label     currentTableNameLabel;\n\t@FXML\n\tprivate TextField columnNamePrefixTextLabel;\n\n\tprivate TableView<UITableColumnVO> columnListView;\n\tprivate String                     tableName;\n\n\t@Override\n\tpublic void initialize(URL location, ResourceBundle resources) {\n\t\t// do nothing\n\t}\n\n\t@FXML\n\tpublic void cancel() {\n\t\tthis.closeDialogStage();\n\t}\n\n\t@FXML\n\tpublic void confirm() {\n\t\ttry {\n\t\t\t// 1. generator bean propert name\n\t\t\tthis.genProertyNameByColumnNamePrefix();\n\n\t\t\t// close window\n\t\t\tthis.closeDialogStage();\n\t\t} catch (Exception e) {\n\t\t\t_LOG.error(\"confirm throw exception.\", e);\n\t\t\tAlertUtil.showErrorAlert(e.getMessage());\n\t\t}\n\t}\n\n\tpublic void setColumnListView(TableView<UITableColumnVO> columnListView) {\n\t\tthis.columnListView = columnListView;\n\t}\n\n\tpublic void setTableName(String tableName) {\n\t\tthis.tableName = tableName;\n\t\tcurrentTableNameLabel.setText(tableName);\n\t}\n\n\tprivate void genProertyNameByColumnNamePrefix() {\n\t\tString columnNamePrefix = this.columnNamePrefixTextLabel.getText();\n\t\tif (StringUtils.isNotBlank(columnNamePrefix)) {\n\t\t\tif (StringUtils.endsWith(columnNamePrefix.trim(), OR_REGEX)) {\n\t\t\t\tcolumnNamePrefix = StringUtils.removeEnd(columnNamePrefix.trim(), OR_REGEX);\n\t\t\t}\n\n\t\t\tString regex = String.format(COL_NAME_PREFIX_REGEX, columnNamePrefix);\n\t\t\t_LOG.info(\"table:{}, column_name_prefix:{}, regex:{}\", this.tableName, columnNamePrefix, regex);\n\n\t\t\tPattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);\n\n\t\t\tObservableList<UITableColumnVO> items = columnListView.getItems();\n\t\t\tif (CollectionUtils.isNotEmpty(items)) {\n\t\t\t\titems.stream().forEach(item -> {\n\t\t\t\t\tString  columnName = item.getColumnName();\n\t\t\t\t\tMatcher matcher    = pattern.matcher(columnName);\n\t\t\t\t\tif (matcher.find()) {\n\t\t\t\t\t\t// use first match result\n\t\t\t\t\t\tString regexColumnName = matcher.group();\n\t\t\t\t\t\tif (StringUtils.isNotBlank(regexColumnName)) {\n\t\t\t\t\t\t\tString propertyName = JavaBeansUtil.getCamelCaseString(regexColumnName, false);\n\t\t\t\t\t\t\t_LOG.debug(\"table:{} column_name:{} regex_column_name:{} property_name:{}\", tableName, columnName, regexColumnName, propertyName);\n\n\t\t\t\t\t\t\tif (StringUtils.isNotBlank(propertyName)) item.setPropertyName(propertyName);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t_LOG.warn(\"table:{} column_name:{} regex_column_name is blank\", tableName, columnName);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// if not match, set property name is null\n\t\t\t\t\t\titem.setPropertyName(null);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/exception/DbDriverLoadingException.java",
    "content": "package com.zzg.mybatis.generator.exception;\n\n/**\n * 数据库驱动加载异常\n * @Date 2017/8/15 21:46\n * @Author jy\n */\npublic class DbDriverLoadingException extends RuntimeException{\n\n    public DbDriverLoadingException(String message){\n        super(message);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/model/CachedFXMLLoader.java",
    "content": "package com.zzg.mybatis.generator.model;\n\npublic class CachedFXMLLoader {\n\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/model/DatabaseConfig.java",
    "content": "package com.zzg.mybatis.generator.model;\n\nimport java.util.Objects;\n\n/**\n * Created by Owen on 5/13/16.\n */\npublic class DatabaseConfig {\n\n\t/**\n\t * The primary key in the sqlite db\n\t */\n\tprivate Integer id;\n\n\tprivate String dbType;\n\t/**\n\t * The name of the config\n\t */\n\tprivate String name;\n\n\tprivate String host;\n\n\tprivate String port;\n\n\tprivate String schema;\n\n\tprivate String username;\n\n\tprivate String password;\n\n\tprivate String encoding;\n\n    private String lport;\n\n    private String rport;\n\n    private String sshPort;\n\n    private String sshHost;\n\n    private String sshUser;\n\n    private String sshPassword;\n\n    private String privateKeyPassword;\n\n    private String privateKey;\n\n\tpublic Integer getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(Integer id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getHost() {\n\t\treturn host;\n\t}\n\n\tpublic void setHost(String host) {\n\t\tthis.host = host;\n\t}\n\n\tpublic String getPort() {\n\t\treturn port;\n\t}\n\n\tpublic void setPort(String port) {\n\t\tthis.port = port;\n\t}\n\n\tpublic String getSchema() {\n\t\treturn schema;\n\t}\n\n\tpublic void setSchema(String schema) {\n\t\tthis.schema = schema;\n\t}\n\n\tpublic String getUsername() {\n\t\treturn username;\n\t}\n\n\tpublic void setUsername(String username) {\n\t\tthis.username = username;\n\t}\n\n\tpublic String getPassword() {\n\t\treturn password;\n\t}\n\n\tpublic void setPassword(String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic String getEncoding() {\n\t\treturn encoding;\n\t}\n\n\tpublic void setEncoding(String encoding) {\n\t\tthis.encoding = encoding;\n\t}\n\n\tpublic String getDbType() {\n\t\treturn dbType;\n\t}\n\n\tpublic void setDbType(String dbType) {\n\t\tthis.dbType = dbType;\n\t}\n\n    public String getLport() {\n        return lport;\n    }\n\n    public void setLport(String lport) {\n        this.lport = lport;\n    }\n\n    public String getRport() {\n        return rport;\n    }\n\n    public void setRport(String rport) {\n        this.rport = rport;\n    }\n\n    public String getSshPort() {\n        return sshPort;\n    }\n\n    public void setSshPort(String sshPort) {\n        this.sshPort = sshPort;\n    }\n\n    public String getSshHost() {\n        return sshHost;\n    }\n\n    public void setSshHost(String sshHost) {\n        this.sshHost = sshHost;\n    }\n\n\tpublic String getSshUser() {\n\t\treturn sshUser;\n\t}\n\n\tpublic void setSshUser(String sshUser) {\n\t\tthis.sshUser = sshUser;\n\t}\n\n\tpublic String getSshPassword() {\n\t\treturn sshPassword;\n\t}\n\n\tpublic void setSshPassword(String sshPassword) {\n\t\tthis.sshPassword = sshPassword;\n\t}\n\n\tpublic String getPrivateKeyPassword() {\n\t\treturn privateKeyPassword;\n\t}\n\n\tpublic void setPrivateKeyPassword(String privateKeyPassword) {\n\t\tthis.privateKeyPassword = privateKeyPassword;\n\t}\n\n\tpublic String getPrivateKey() {\n\t\treturn privateKey;\n\t}\n\n\tpublic void setPrivateKey(String privateKey) {\n\t\tthis.privateKey = privateKey;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object o) {\n\t\tif (this == o) return true;\n\t\tif (o == null || getClass() != o.getClass()) return false;\n\t\tDatabaseConfig that = (DatabaseConfig) o;\n\t\treturn Objects.equals(id, that.id) &&\n\t\t\tObjects.equals(dbType, that.dbType) &&\n\t\t\tObjects.equals(name, that.name) &&\n\t\t\tObjects.equals(host, that.host) &&\n\t\t\tObjects.equals(port, that.port) &&\n\t\t\tObjects.equals(schema, that.schema) &&\n\t\t\tObjects.equals(username, that.username) &&\n\t\t\tObjects.equals(password, that.password) &&\n\t\t\tObjects.equals(encoding, that.encoding) &&\n\t\t\tObjects.equals(lport, that.lport) &&\n\t\t\tObjects.equals(rport, that.rport) &&\n\t\t\tObjects.equals(sshPort, that.sshPort) &&\n\t\t\tObjects.equals(sshHost, that.sshHost) &&\n\t\t\tObjects.equals(sshUser, that.sshUser) &&\n\t\t\tObjects.equals(sshPassword, that.sshPassword) &&\n\t\t\tObjects.equals(privateKeyPassword, that.privateKeyPassword) &&\n\t\t\tObjects.equals(privateKey, that.privateKey);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn Objects.hash(id, dbType, name, host, port, schema, username, password, encoding, lport, rport, sshPort, sshHost, sshUser, sshPassword, privateKeyPassword, privateKey);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"DatabaseConfig{\" +\n\t\t\t\t\"id=\" + id +\n\t\t\t\t\", dbType='\" + dbType + '\\'' +\n\t\t\t\t\", name='\" + name + '\\'' +\n\t\t\t\t\", host='\" + host + '\\'' +\n\t\t\t\t\", port='\" + port + '\\'' +\n\t\t\t\t\", schema='\" + schema + '\\'' +\n\t\t\t\t\", username='\" + username + '\\'' +\n\t\t\t\t\", password='\" + password + '\\'' +\n\t\t\t\t\", encoding='\" + encoding + '\\'' +\n\t\t\t\t\", lport='\" + lport + '\\'' +\n\t\t\t\t\", rport='\" + rport + '\\'' +\n\t\t\t\t\", sshPort='\" + sshPort + '\\'' +\n\t\t\t\t\", sshHost='\" + sshHost + '\\'' +\n\t\t\t\t\", sshUser='\" + sshUser + '\\'' +\n\t\t\t\t\", sshPassword='\" + sshPassword + '\\'' +\n\t\t\t\t'}';\n\t}\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/model/DatabaseDTO.java",
    "content": "package com.zzg.mybatis.generator.model;\n\npublic class DatabaseDTO {\n\n\tprivate String name;\n\tprivate int value;\n\tprivate String driverClass;\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic int getValue() {\n\t\treturn value;\n\t}\n\n\tpublic void setValue(int value) {\n\t\tthis.value = value;\n\t}\n\n\tpublic String getDriverClass() {\n\t\treturn driverClass;\n\t}\n\n\tpublic void setDriverClass(String driverClass) {\n\t\tthis.driverClass = driverClass;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn name;\n\t}\n\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/model/DbType.java",
    "content": "package com.zzg.mybatis.generator.model;\n\n/**\n * Created by Owen on 6/14/16.\n */\npublic enum DbType {\n\n    MySQL(\"com.mysql.jdbc.Driver\", \"jdbc:mysql://%s:%s/%s?useUnicode=true&useSSL=false&characterEncoding=%s\", \"mysql-connector-java-5.1.38.jar\"),\n    MySQL_8(\"com.mysql.cj.jdbc.Driver\", \"jdbc:mysql://%s:%s/%s?serverTimezone=UTC&useUnicode=true&useSSL=false&characterEncoding=%s\", \"mysql-connector-java-8.0.11.jar\"),\n    Oracle(\"oracle.jdbc.OracleDriver\", \"jdbc:oracle:thin:@//%s:%s/%s\", \"ojdbc6.jar\"),\n    PostgreSQL(\"org.postgresql.Driver\", \"jdbc:postgresql://%s:%s/%s\", \"postgresql-9.4.1209.jar\"),\n\tSQL_Server(\"com.microsoft.sqlserver.jdbc.SQLServerDriver\", \"jdbc:sqlserver://%s:%s;databaseName=%s\", \"sqljdbc4-4.0.jar\"),\n\tSqlite(\"org.sqlite.JDBC\", \"jdbc:sqlite:%s\", \"sqlite-jdbc-3.19.3.jar\");\n\n    private final String driverClass;\n    private final String connectionUrlPattern;\n    private final String connectorJarFile;\n\n    DbType(String driverClass, String connectionUrlPattern, String connectorJarFile) {\n        this.driverClass = driverClass;\n        this.connectionUrlPattern = connectionUrlPattern;\n        this.connectorJarFile = connectorJarFile;\n    }\n\n    public String getDriverClass() {\n        return driverClass;\n    }\n\n    public String getConnectionUrlPattern() {\n        return connectionUrlPattern;\n    }\n\n    public String getConnectorJarFile() {\n        return connectorJarFile;\n    }\n}"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/model/GeneratorConfig.java",
    "content": "package com.zzg.mybatis.generator.model;\n\n/**\n *\n * GeneratorConfig is the Config of mybatis generator config exclude database\n * config\n *\n * Created by Owen on 6/16/16.\n */\npublic class GeneratorConfig {\n\n\t/**\n\t * 本配置的名称\n\t */\n\tprivate String name;\n\n\tprivate String connectorJarPath;\n\n\tprivate String projectFolder;\n\n\tprivate String modelPackage;\n\n\tprivate String modelPackageTargetFolder;\n\n\tprivate String daoPackage;\n\n\tprivate String daoTargetFolder;\n\n\tprivate String mapperName;\n\n\tprivate String mappingXMLPackage;\n\n\tprivate String mappingXMLTargetFolder;\n\n\tprivate String tableName;\n\n\tprivate String domainObjectName;\n\n\tprivate boolean offsetLimit;\n\n\tprivate boolean comment;\n\n\tprivate boolean overrideXML;\n\n\tprivate boolean needToStringHashcodeEquals;\n\n\tprivate boolean useLombokPlugin;\n\n\tprivate boolean needForUpdate;\n\n\tprivate boolean annotationDAO;\n\n\tprivate boolean annotation;\n\n\tprivate boolean useActualColumnNames;\n\n\tprivate boolean useExample;\n\n\tprivate String generateKeys;\n\n\tprivate String encoding;\n\n\tprivate boolean useTableNameAlias;\n\n\tprivate boolean useDAOExtendStyle;\n\n    private boolean useSchemaPrefix;\n\n    private boolean jsr310Support;\n\n    public boolean isJsr310Support() {\n        return jsr310Support;\n    }\n\n    public void setJsr310Support(boolean jsr310Support) {\n        this.jsr310Support = jsr310Support;\n    }\n\n    public boolean isUseSchemaPrefix() {\n        return useSchemaPrefix;\n    }\n\n    public void setUseSchemaPrefix(boolean useSchemaPrefix) {\n        this.useSchemaPrefix = useSchemaPrefix;\n    }\n\n\tpublic boolean isUseExample() {\n\t\treturn useExample;\n\t}\n\n\tpublic void setUseExample(boolean useExample) {\n\t\tthis.useExample = useExample;\n\t}\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getTableName() {\n\t\treturn tableName;\n\t}\n\n\tpublic void setTableName(String tableName) {\n\t\tthis.tableName = tableName;\n\t}\n\n\tpublic String getDomainObjectName() {\n\t\treturn domainObjectName;\n\t}\n\n\tpublic void setDomainObjectName(String domainObjectName) {\n\t\tthis.domainObjectName = domainObjectName;\n\t}\n\n\tpublic String getConnectorJarPath() {\n\t\treturn connectorJarPath;\n\t}\n\n\tpublic void setConnectorJarPath(String connectorJarPath) {\n\t\tthis.connectorJarPath = connectorJarPath;\n\t}\n\n\tpublic String getProjectFolder() {\n\t\treturn projectFolder;\n\t}\n\n\tpublic void setProjectFolder(String projectFolder) {\n\t\tthis.projectFolder = projectFolder;\n\t}\n\n\tpublic String getModelPackage() {\n\t\treturn modelPackage;\n\t}\n\n\tpublic void setModelPackage(String modelPackage) {\n\t\tthis.modelPackage = modelPackage;\n\t}\n\n\tpublic String getModelPackageTargetFolder() {\n\t\treturn modelPackageTargetFolder;\n\t}\n\n\tpublic void setModelPackageTargetFolder(String modelPackageTargetFolder) {\n\t\tthis.modelPackageTargetFolder = modelPackageTargetFolder;\n\t}\n\n\tpublic String getDaoPackage() {\n\t\treturn daoPackage;\n\t}\n\n\tpublic void setDaoPackage(String daoPackage) {\n\t\tthis.daoPackage = daoPackage;\n\t}\n\n\tpublic String getDaoTargetFolder() {\n\t\treturn daoTargetFolder;\n\t}\n\n\tpublic void setDaoTargetFolder(String daoTargetFolder) {\n\t\tthis.daoTargetFolder = daoTargetFolder;\n\t}\n\n\tpublic String getMappingXMLPackage() {\n\t\treturn mappingXMLPackage;\n\t}\n\n\tpublic void setMappingXMLPackage(String mappingXMLPackage) {\n\t\tthis.mappingXMLPackage = mappingXMLPackage;\n\t}\n\n\tpublic String getMappingXMLTargetFolder() {\n\t\treturn mappingXMLTargetFolder;\n\t}\n\n\tpublic void setMappingXMLTargetFolder(String mappingXMLTargetFolder) {\n\t\tthis.mappingXMLTargetFolder = mappingXMLTargetFolder;\n\t}\n\n\tpublic boolean isOffsetLimit() {\n\t\treturn offsetLimit;\n\t}\n\n\tpublic void setOffsetLimit(boolean offsetLimit) {\n\t\tthis.offsetLimit = offsetLimit;\n\t}\n\n\tpublic boolean isComment() {\n\t\treturn comment;\n\t}\n\n\tpublic void setComment(boolean comment) {\n\t\tthis.comment = comment;\n\t}\n\n    public boolean isNeedToStringHashcodeEquals() {\n        return needToStringHashcodeEquals;\n    }\n\n    public void setNeedToStringHashcodeEquals(boolean needToStringHashcodeEquals) {\n        this.needToStringHashcodeEquals = needToStringHashcodeEquals;\n    }\n\n\tpublic boolean isUseLombokPlugin() {\n\t\treturn useLombokPlugin;\n\t}\n\n\tpublic void setUseLombokPlugin(boolean useLombokPlugin) {\n\t\tthis.useLombokPlugin = useLombokPlugin;\n\t}\n\n\tpublic boolean isNeedForUpdate() {\n\t\treturn needForUpdate;\n\t}\n\n\tpublic void setNeedForUpdate(boolean needForUpdate) {\n\t\tthis.needForUpdate = needForUpdate;\n\t}\n\n\tpublic boolean isAnnotationDAO() {\n\t\treturn annotationDAO;\n\t}\n\n\tpublic void setAnnotationDAO(boolean annotationDAO) {\n\t\tthis.annotationDAO = annotationDAO;\n\t}\n\n\tpublic boolean isAnnotation() {\n\t\treturn annotation;\n\t}\n\n\tpublic void setAnnotation(boolean annotation) {\n\t\tthis.annotation = annotation;\n\t}\n\n\tpublic boolean isUseActualColumnNames() {\n\t\treturn useActualColumnNames;\n\t}\n\n\tpublic void setUseActualColumnNames(boolean useActualColumnNames) {\n\t\tthis.useActualColumnNames = useActualColumnNames;\n\t}\n\n\tpublic String getMapperName() {\n\t\treturn mapperName;\n\t}\n\n\tpublic void setMapperName(String mapperName) {\n\t\tthis.mapperName = mapperName;\n\t}\n\n\tpublic String getGenerateKeys() {\n\t\treturn generateKeys;\n\t}\n\n\tpublic void setGenerateKeys(String generateKeys) {\n\t\tthis.generateKeys = generateKeys;\n\t}\n\n    public String getEncoding() {\n        return encoding;\n    }\n\n    public void setEncoding(String encoding) {\n        this.encoding = encoding;\n    }\n\n\tpublic boolean getUseTableNameAlias() {\n\t\treturn useTableNameAlias;\n\t}\n\n\tpublic void setUseTableNameAlias(boolean useTableNameAlias) {\n\t\tthis.useTableNameAlias = useTableNameAlias;\n\t}\n\n\tpublic boolean isUseTableNameAlias() {\n\t\treturn useTableNameAlias;\n\t}\n\n\tpublic boolean isOverrideXML() {\n\t\treturn overrideXML;\n\t}\n\n\tpublic void setOverrideXML(boolean overrideXML) {\n\t\tthis.overrideXML = overrideXML;\n\t}\n\n\tpublic void setUseDAOExtendStyle(boolean useDAOExtendStyle) {\n\t\tthis.useDAOExtendStyle = useDAOExtendStyle;\n\t}\n\n\tpublic boolean isUseDAOExtendStyle() {\n\t\treturn useDAOExtendStyle;\n\t}\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/model/UITableColumnVO.java",
    "content": "package com.zzg.mybatis.generator.model;\n\nimport javafx.beans.property.BooleanProperty;\nimport javafx.beans.property.SimpleBooleanProperty;\nimport javafx.beans.property.SimpleStringProperty;\nimport javafx.beans.property.StringProperty;\n\n/**\n * Created by Owen on 6/22/16.\n */\npublic class UITableColumnVO {\n\n    private BooleanProperty checked = new SimpleBooleanProperty(true); // Default set to true\n\n    private StringProperty columnName = new SimpleStringProperty();\n\n    private StringProperty javaType = new SimpleStringProperty();\n\n    private StringProperty jdbcType = new SimpleStringProperty();\n\n    private StringProperty propertyName = new SimpleStringProperty();\n\n    private StringProperty typeHandle = new SimpleStringProperty();\n\n    public String getColumnName() {\n        return columnName.get();\n    }\n\n    public void setColumnName(String columnName) {\n        this.columnName.set(columnName);\n    }\n\n    public String getJdbcType() {\n        return jdbcType.get();\n    }\n\n    public void setJdbcType(String jdbcType) {\n        this.jdbcType.set(jdbcType);\n    }\n\n    public String getPropertyName() {\n        return propertyName.get();\n    }\n\n    public void setPropertyName(String propertyName) {\n        this.propertyName.set(propertyName);\n    }\n\n    public BooleanProperty checkedProperty() {\n        return checked;\n    }\n\n    public Boolean getChecked() {\n        return this.checked.get();\n    }\n\n    public void setChecked(Boolean checked) {\n        this.checked.set(checked);\n    }\n\n    public StringProperty typeHandleProperty() {\n        return typeHandle;\n    }\n\n    public String getTypeHandle() {\n        return typeHandle.get();\n    }\n\n    public void setTypeHandle(String typeHandle) {\n        this.typeHandle.set(typeHandle);\n    }\n\n    public StringProperty columnNameProperty() {\n        return columnName;\n    }\n\n    public StringProperty jdbcTypeProperty() {\n        return jdbcType;\n    }\n\n    public StringProperty propertyNameProperty() {\n        return propertyName;\n    }\n\n    public String getJavaType() {\n        return javaType.get();\n    }\n\n    public StringProperty javaTypeProperty() {\n        return javaType;\n    }\n\n    public void setJavaType(String javaType) {\n        this.javaType.set(javaType);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/plugins/CommonDAOInterfacePlugin.java",
    "content": "package com.zzg.mybatis.generator.plugins;\n\nimport org.mybatis.generator.api.*;\nimport org.mybatis.generator.api.dom.java.*;\nimport org.mybatis.generator.exception.ShellException;\nimport org.mybatis.generator.internal.DefaultShellCallback;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport static org.mybatis.generator.internal.util.StringUtility.stringHasValue;\n\n/**\n * Project: mybatis-generator-gui\n *\n * @author slankka on 2018/3/11.\n */\npublic class CommonDAOInterfacePlugin extends PluginAdapter {\n\n    private static final String DEFAULT_DAO_SUPER_CLASS = \".MyBatisBaseDao\";\n    private static final FullyQualifiedJavaType SERIALIZEBLE_TYPE = new FullyQualifiedJavaType(\"java.io.Serializable\");\n\n    private List<Method> methods = new ArrayList<>();\n\n    private ShellCallback shellCallback = null;\n\n    public CommonDAOInterfacePlugin() {\n        shellCallback = new DefaultShellCallback(false);\n    }\n    \n    private boolean isUseExample() {\n    \treturn \"true\".equals(getProperties().getProperty(\"useExample\"));\n\t}\n\n    @Override\n    public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {\n        boolean hasPk = introspectedTable.hasPrimaryKeyColumns();\n        JavaFormatter javaFormatter = context.getJavaFormatter();\n        String daoTargetDir = context.getJavaClientGeneratorConfiguration().getTargetProject();\n        String daoTargetPackage = context.getJavaClientGeneratorConfiguration().getTargetPackage();\n        List<GeneratedJavaFile> mapperJavaFiles = new ArrayList<>();\n        String javaFileEncoding = context.getProperty(\"javaFileEncoding\");\n        Interface mapperInterface = new Interface(daoTargetPackage + DEFAULT_DAO_SUPER_CLASS);\n\n        if (stringHasValue(daoTargetPackage)) {\n            mapperInterface.addImportedType(SERIALIZEBLE_TYPE);\n\n            mapperInterface.setVisibility(JavaVisibility.PUBLIC);\n            mapperInterface.addJavaDocLine(\"/**\");\n            mapperInterface.addJavaDocLine(\" * \" + \"DAO公共基类，由MybatisGenerator自动生成请勿修改\");\n            mapperInterface.addJavaDocLine(\" * \" + \"@param <Model> The Model Class 这里是泛型不是Model类\");\n            mapperInterface.addJavaDocLine(\" * \" + \"@param <PK> The Primary Key Class 如果是无主键，则可以用Model来跳过，如果是多主键则是Key类\");\n\t\t\tif (isUseExample()) {\n\t\t\t\tmapperInterface.addJavaDocLine(\" * \" + \"@param <E> The Example Class\");\n\t\t\t}\n            mapperInterface.addJavaDocLine(\" */\");\n\n            FullyQualifiedJavaType daoBaseInterfaceJavaType = mapperInterface.getType();\n            daoBaseInterfaceJavaType.addTypeArgument(new FullyQualifiedJavaType(\"Model\"));\n            daoBaseInterfaceJavaType.addTypeArgument(new FullyQualifiedJavaType(\"PK extends Serializable\"));\n\t\t\tif (isUseExample()) {\n\t\t\t\tdaoBaseInterfaceJavaType.addTypeArgument(new FullyQualifiedJavaType(\"E\"));\n\t\t\t}\n\n            if (!this.methods.isEmpty()) {\n                for (Method method : methods) {\n                    mapperInterface.addMethod(method);\n                }\n            }\n\n            List<GeneratedJavaFile> generatedJavaFiles = introspectedTable.getGeneratedJavaFiles();\n            for (GeneratedJavaFile generatedJavaFile : generatedJavaFiles) {\n                CompilationUnit compilationUnit = generatedJavaFile.getCompilationUnit();\n                FullyQualifiedJavaType type = compilationUnit.getType();\n                String modelName = type.getShortName();\n                if (modelName.endsWith(\"DAO\")) {\n                }\n            }\n            GeneratedJavaFile mapperJavafile = new GeneratedJavaFile(mapperInterface, daoTargetDir, javaFileEncoding, javaFormatter);\n            try {\n                File mapperDir = shellCallback.getDirectory(daoTargetDir, daoTargetPackage);\n                File mapperFile = new File(mapperDir, mapperJavafile.getFileName());\n                // 文件不存在\n                if (!mapperFile.exists()) {\n                    mapperJavaFiles.add(mapperJavafile);\n                }\n            } catch (ShellException e) {\n                e.printStackTrace();\n            }\n        }\n        return mapperJavaFiles;\n    }\n\n    @Override\n    public boolean clientGenerated(Interface interfaze,\n                                   TopLevelClass topLevelClass,\n                                   IntrospectedTable introspectedTable) {\n        interfaze.addJavaDocLine(\"/**\");\n        interfaze.addJavaDocLine(\" * \" + interfaze.getType().getShortName() + \"继承基类\");\n        interfaze.addJavaDocLine(\" */\");\n\n        String daoSuperClass = interfaze.getType().getPackageName() + DEFAULT_DAO_SUPER_CLASS;\n        FullyQualifiedJavaType daoSuperType = new FullyQualifiedJavaType(daoSuperClass);\n\n        String targetPackage = introspectedTable.getContext().getJavaModelGeneratorConfiguration().getTargetPackage();\n\n        String domainObjectName = introspectedTable.getTableConfiguration().getDomainObjectName();\n        FullyQualifiedJavaType baseModelJavaType = new FullyQualifiedJavaType(targetPackage + \".\" + domainObjectName);\n        daoSuperType.addTypeArgument(baseModelJavaType);\n\n        FullyQualifiedJavaType primaryKeyTypeJavaType = null;\n        if (introspectedTable.getPrimaryKeyColumns().size() > 1) {\n            primaryKeyTypeJavaType = new FullyQualifiedJavaType(targetPackage + \".\" + domainObjectName + \"Key\");\n        }else if(introspectedTable.hasPrimaryKeyColumns()){\n            primaryKeyTypeJavaType = introspectedTable.getPrimaryKeyColumns().get(0).getFullyQualifiedJavaType();\n        }else {\n            primaryKeyTypeJavaType = baseModelJavaType;\n        }\n        daoSuperType.addTypeArgument(primaryKeyTypeJavaType);\n\t\tinterfaze.addImportedType(primaryKeyTypeJavaType);\n\n\t\tif (isUseExample()) {\n\t\t\tString exampleType = introspectedTable.getExampleType();\n\t\t\tFullyQualifiedJavaType exampleTypeJavaType = new FullyQualifiedJavaType(exampleType);\n\t\t\tdaoSuperType.addTypeArgument(exampleTypeJavaType);\n\t\t\tinterfaze.addImportedType(exampleTypeJavaType);\n\t\t}\n        interfaze.addImportedType(baseModelJavaType);\n        interfaze.addImportedType(daoSuperType);\n        interfaze.addSuperInterface(daoSuperType);\n        return true;\n    }\n\n    @Override\n    public boolean validate(List<String> list) {\n        return true;\n    }\n\n    private void interceptExampleParam(Method method) {\n\t\tif (isUseExample()) {\n\t\t\tmethod.getParameters().clear();\n\t\t\tmethod.addParameter(new Parameter(new FullyQualifiedJavaType(\"E\"), \"example\"));\n\t\t\tmethods.add(method);\n\t\t}\n    }\n\n    private void interceptPrimaryKeyParam(Method method) {\n        method.getParameters().clear();\n        method.addParameter(new Parameter(new FullyQualifiedJavaType(\"PK\"), \"id\"));\n        methods.add(method);\n    }\n\n    private void interceptModelParam(Method method) {\n        method.getParameters().clear();\n        method.addParameter(new Parameter(new FullyQualifiedJavaType(\"Model\"), \"record\"));\n        methods.add(method);\n    }\n\n    private void interceptModelAndExampleParam(Method method) {\n\t\tif (isUseExample()) {\n\t\t\tList<Parameter> parameters = method.getParameters();\n\t\t\tif (parameters.size() == 1) {\n\t\t\t\tinterceptExampleParam(method);\n\t\t\t}else{\n\t\t\t\tmethod.getParameters().clear();\n\t\t\t\tParameter parameter1 = new Parameter(new FullyQualifiedJavaType(\"Model\"), \"record\");\n\t\t\t\tparameter1.addAnnotation(\"@Param(\\\"record\\\")\");\n\t\t\t\tmethod.addParameter(parameter1);\n\n\t\t\t\tParameter parameter2 = new Parameter(new FullyQualifiedJavaType(\"E\"), \"example\");\n\t\t\t\tparameter2.addAnnotation(\"@Param(\\\"example\\\")\");\n\t\t\t\tmethod.addParameter(parameter2);\n\t\t\t\tmethods.add(method);\n\t\t\t}\n\t\t}\n    }\n\n    @Override\n    public boolean clientCountByExampleMethodGenerated(Method method,\n                                                       Interface interfaze, IntrospectedTable introspectedTable) {\n//        interface\n\t\tif (isUseExample()) {\n\t\t\tinterceptExampleParam(method);\n\t\t}\n\t\treturn false;\n\t}\n\n\n    @Override\n    public boolean clientDeleteByExampleMethodGenerated(Method method,\n                                                        Interface interfaze, IntrospectedTable introspectedTable) {\n        if (isUseExample()) {\n\t\t\tinterceptExampleParam(method);\n\t\t}\n        return false;\n    }\n\n\n    @Override\n    public boolean clientDeleteByPrimaryKeyMethodGenerated(Method method,\n                                                           Interface interfaze, IntrospectedTable introspectedTable) {\n    \tinterceptPrimaryKeyParam(method);\n        return false;\n    }\n\n    @Override\n    public boolean clientInsertMethodGenerated(Method method, Interface interfaze,\n                                                  IntrospectedTable introspectedTable) {\n        interceptModelParam(method);\n        return false;\n    }\n\n    @Override\n    public boolean clientSelectByExampleWithBLOBsMethodGenerated(Method method,\n                                                                 Interface interfaze, IntrospectedTable introspectedTable) {\n        if (isUseExample()) {\n\t\t\tinterceptExampleParam(method);\n\t\t\tmethod.setReturnType(new FullyQualifiedJavaType(\"List<Model>\"));\n\t\t}\n        return false;\n    }\n\n    @Override\n    public boolean clientSelectByExampleWithoutBLOBsMethodGenerated(Method method,\n                                                                    Interface interfaze, IntrospectedTable introspectedTable) {\n        if (isUseExample()) {\n\t\t\tinterceptExampleParam(method);\n\t\t\tmethod.setReturnType(new FullyQualifiedJavaType(\"List<Model>\"));\n\t\t}\n        return false;\n    }\n\n    @Override\n    public boolean clientSelectByPrimaryKeyMethodGenerated(Method method,\n                                                           Interface interfaze, IntrospectedTable introspectedTable) {\n    \tinterceptPrimaryKeyParam(method);\n        method.setReturnType(new FullyQualifiedJavaType(\"Model\"));\n        return false;\n    }\n\n    @Override\n    public boolean clientUpdateByExampleSelectiveMethodGenerated(Method method,\n                                                                 Interface interfaze, IntrospectedTable introspectedTable) {\n        if (isUseExample()) {\n\t\t\tinterceptModelAndExampleParam(method);\n\t\t}\n        return false;\n    }\n\n    @Override\n    public boolean clientUpdateByExampleWithBLOBsMethodGenerated(Method method,\n                                                                 Interface interfaze, IntrospectedTable introspectedTable) {\n        if (isUseExample()) {\n\t\t\tinterceptModelAndExampleParam(method);\n\t\t}\n        return false;\n    }\n\n    @Override\n    public boolean clientUpdateByExampleWithoutBLOBsMethodGenerated(Method method,\n                                                                    Interface interfaze, IntrospectedTable introspectedTable) {\n        if (isUseExample()) {\n\t\t\tinterceptModelAndExampleParam(method);\n\t\t}\n        return false;\n    }\n\n    @Override\n    public boolean clientUpdateByPrimaryKeySelectiveMethodGenerated(Method method,\n                                                                    Interface interfaze, IntrospectedTable introspectedTable) {\n        interceptModelParam(method);\n        return false;\n    }\n\n    @Override\n    public boolean clientUpdateByExampleWithoutBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {\n        if (isUseExample()) {\n\t\t\tinterceptModelAndExampleParam(method);\n\t\t}\n        return false;\n    }\n\n    @Override\n    public boolean clientUpdateByExampleSelectiveMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {\n        if (isUseExample()) {\n\t\t\tinterceptModelAndExampleParam(method);\n\t\t}\n        return false;\n    }\n\n    @Override\n    public boolean clientUpdateByPrimaryKeyWithBLOBsMethodGenerated(Method method,\n                                                                    Interface interfaze, IntrospectedTable introspectedTable) {\n    \tinterceptModelParam(method);\n        return false;\n    }\n\n    @Override\n    public boolean clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated(\n            Method method, Interface interfaze,\n            IntrospectedTable introspectedTable) {\n        interceptModelParam(method);\n        return false;\n    }\n\n    @Override\n    public boolean clientInsertSelectiveMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {\n        interceptModelParam(method);\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/plugins/DbRemarksCommentGenerator.java",
    "content": "/*\n *  Copyright 2008 The Apache Software Foundation\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.zzg.mybatis.generator.plugins;\n\nimport org.mybatis.generator.api.CommentGenerator;\nimport org.mybatis.generator.api.IntrospectedColumn;\nimport org.mybatis.generator.api.IntrospectedTable;\nimport org.mybatis.generator.api.dom.java.*;\nimport org.mybatis.generator.api.dom.xml.XmlElement;\nimport org.mybatis.generator.internal.util.StringUtility;\n\nimport java.util.Properties;\nimport java.util.Set;\n\nimport static org.mybatis.generator.internal.util.StringUtility.isTrue;\n\n/**\n * 此插件使用数据库表中列的注释来生成Java Model中属性的注释\n *\n * @author Owen Zou\n * \n */\npublic class DbRemarksCommentGenerator implements CommentGenerator {\n\n\n    private Properties properties;\n    private boolean columnRemarks;\n    private boolean isAnnotations;\n\n    public DbRemarksCommentGenerator() {\n        super();\n        properties = new Properties();\n    }\n\n\n    public void addJavaFileComment(CompilationUnit compilationUnit) {\n        // add no file level comments by default\n        if (isAnnotations) {\n            compilationUnit.addImportedType(new FullyQualifiedJavaType(\"javax.persistence.Table\"));\n            compilationUnit.addImportedType(new FullyQualifiedJavaType(\"javax.persistence.Id\"));\n            compilationUnit.addImportedType(new FullyQualifiedJavaType(\"javax.persistence.Column\"));\n            compilationUnit.addImportedType(new FullyQualifiedJavaType(\"javax.persistence.GeneratedValue\"));\n            compilationUnit.addImportedType(new FullyQualifiedJavaType(\"org.hibernate.validator.constraints.NotEmpty\"));\n        }\n    }\n\n    /**\n     * Adds a suitable comment to warn users that the element was generated, and\n     * when it was generated.\n     */\n    public void addComment(XmlElement xmlElement) {\n    }\n\n    public void addRootComment(XmlElement rootElement) {\n        // add no document level comments by default\n        return;\n    }\n\n\t@Override\n\tpublic void addGeneralMethodAnnotation(Method method, IntrospectedTable introspectedTable, Set<FullyQualifiedJavaType> set) {\n\n\n\t}\n\n\t@Override\n\tpublic void addGeneralMethodAnnotation(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn, Set<FullyQualifiedJavaType> set) {\n\n\t}\n\n\t@Override\n\tpublic void addFieldAnnotation(Field field, IntrospectedTable introspectedTable, Set<FullyQualifiedJavaType> set) {\n\n\t}\n\n\t@Override\n\tpublic void addFieldAnnotation(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn, Set<FullyQualifiedJavaType> set) {\n\n\t}\n\n\t@Override\n\tpublic void addClassAnnotation(InnerClass innerClass, IntrospectedTable introspectedTable, Set<FullyQualifiedJavaType> set) {\n\t}\n\n\tpublic void addConfigurationProperties(Properties properties) {\n        this.properties.putAll(properties);\n        columnRemarks = isTrue(properties\n                .getProperty(\"columnRemarks\"));\n        isAnnotations = isTrue(properties\n                .getProperty(\"annotations\"));\n    }\n\n    public void addClassComment(InnerClass innerClass,\n            IntrospectedTable introspectedTable) {\n    }\n\n    public void addModelClassComment(TopLevelClass topLevelClass,\n                                IntrospectedTable introspectedTable) {\n        topLevelClass.addJavaDocLine(\"/**\");\n        topLevelClass.addJavaDocLine(\" * @author \");\n        topLevelClass.addJavaDocLine(\" * \" + introspectedTable.getRemarks());\n        topLevelClass.addJavaDocLine(\" */\");\n        if(isAnnotations) {\n            topLevelClass.addAnnotation(\"@Table(name=\\\"\" + introspectedTable.getFullyQualifiedTableNameAtRuntime() + \"\\\")\");\n        }\n    }\n\n    public void addEnumComment(InnerEnum innerEnum,\n            IntrospectedTable introspectedTable) {\n    }\n\n    public void addFieldComment(Field field,\n            IntrospectedTable introspectedTable,\n            IntrospectedColumn introspectedColumn) {\n        if (StringUtility.stringHasValue(introspectedColumn.getRemarks())) {\n            field.addJavaDocLine(\"/**\");\n            StringBuilder sb = new StringBuilder();\n            sb.append(\" * \");\n            sb.append(introspectedColumn.getRemarks());\n            field.addJavaDocLine(sb.toString());\n            field.addJavaDocLine(\" */\");\n        }\n\n        if (isAnnotations) {\n            boolean isId = false;\n            for (IntrospectedColumn column : introspectedTable.getPrimaryKeyColumns()) {\n                if (introspectedColumn == column) {\n                    isId = true;\n                    field.addAnnotation(\"@Id\");\n                    field.addAnnotation(\"@GeneratedValue\");\n                    break;\n                }\n            }\n            if (!introspectedColumn.isNullable() && !isId){\n                field.addAnnotation(\"@NotEmpty\");\n            }\n            if (introspectedColumn.isIdentity()) {\n                if (introspectedTable.getTableConfiguration().getGeneratedKey().getRuntimeSqlStatement().equals(\"JDBC\")) {\n                    field.addAnnotation(\"@GeneratedValue(generator = \\\"JDBC\\\")\");\n                } else {\n                    field.addAnnotation(\"@GeneratedValue(strategy = GenerationType.IDENTITY)\");\n                }\n            } else if (introspectedColumn.isSequenceColumn()) {\n                field.addAnnotation(\"@SequenceGenerator(name=\\\"\\\",sequenceName=\\\"\" + introspectedTable.getTableConfiguration().getGeneratedKey().getRuntimeSqlStatement() + \"\\\")\");\n            }\n        }\n    }\n\n    public void addFieldComment(Field field, IntrospectedTable introspectedTable) {\n    }\n\n    public void addGeneralMethodComment(Method method,\n            IntrospectedTable introspectedTable) {\n    }\n\n    public void addGetterComment(Method method,\n            IntrospectedTable introspectedTable,\n            IntrospectedColumn introspectedColumn) {\n    }\n\n    public void addSetterComment(Method method,\n            IntrospectedTable introspectedTable,\n            IntrospectedColumn introspectedColumn) {\n    }\n\n    public void addClassComment(InnerClass innerClass,\n            IntrospectedTable introspectedTable, boolean markAsDoNotDelete) {\n        innerClass.addJavaDocLine(\"/**\"); //$NON-NLS-1$\n        innerClass.addJavaDocLine(\" */\"); //$NON-NLS-1$\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/plugins/JavaTypeResolverJsr310Impl.java",
    "content": "package com.zzg.mybatis.generator.plugins;\r\n\r\nimport org.mybatis.generator.api.IntrospectedColumn;\r\nimport org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;\r\nimport org.mybatis.generator.internal.types.JavaTypeResolverDefaultImpl;\r\n\r\nimport java.sql.Types;\r\nimport java.time.LocalDate;\r\nimport java.time.LocalDateTime;\r\nimport java.time.LocalTime;\r\n\r\n/**\r\n * @author hanakei\r\n * @since 2018/4/28\r\n */\r\npublic class JavaTypeResolverJsr310Impl extends JavaTypeResolverDefaultImpl {\r\n\r\n    @Override\r\n    protected FullyQualifiedJavaType overrideDefaultType(IntrospectedColumn column, FullyQualifiedJavaType defaultType) {\r\n        FullyQualifiedJavaType answer = defaultType;\r\n\r\n        switch (column.getJdbcType()) {\r\n            case Types.BIT:\r\n                answer = calculateBitReplacement(column, defaultType);\r\n                break;\r\n            case Types.DECIMAL:\r\n            case Types.NUMERIC:\r\n                answer = calculateBigDecimalReplacement(column, defaultType);\r\n                break;\r\n            case Types.DATE:\r\n                answer = new FullyQualifiedJavaType(LocalDate.class.getName());\r\n                break;\r\n            case Types.TIME:\r\n                answer = new FullyQualifiedJavaType(LocalTime.class.getName());\r\n                break;\r\n            case Types.TIMESTAMP:\r\n                answer = new FullyQualifiedJavaType(LocalDateTime.class.getName());\r\n                break;\r\n            default:\r\n                break;\r\n        }\r\n\r\n        return answer;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/plugins/MySQLForUpdatePlugin.java",
    "content": "package com.zzg.mybatis.generator.plugins;\n\nimport org.mybatis.generator.api.IntrospectedTable;\nimport org.mybatis.generator.api.PluginAdapter;\nimport org.mybatis.generator.api.dom.java.*;\nimport org.mybatis.generator.api.dom.xml.Attribute;\nimport org.mybatis.generator.api.dom.xml.TextElement;\nimport org.mybatis.generator.api.dom.xml.XmlElement;\n\nimport java.util.List;\n\n/**\n * Project: mybatis-generator-gui\n *\n * @author slankka on 2017/11/4.\n */\npublic class MySQLForUpdatePlugin extends PluginAdapter {\n\n    @Override\n    public boolean validate(List<String> warnings) {\n        return true;\n    }\n\n    @Override\n    public boolean modelExampleClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {\n\n        PrimitiveTypeWrapper booleanWrapper = FullyQualifiedJavaType.getBooleanPrimitiveInstance().getPrimitiveTypeWrapper();\n        Field forUpdate = new Field();\n        forUpdate.setName(\"forUpdate\");\n        forUpdate.setVisibility(JavaVisibility.PRIVATE);\n        forUpdate.setType(booleanWrapper);\n        topLevelClass.addField(forUpdate);\n\n        Method setForUpdate = new Method();\n        setForUpdate.setVisibility(JavaVisibility.PUBLIC);\n        setForUpdate.setName(\"setForUpdate\");\n        setForUpdate.addParameter(new Parameter(booleanWrapper, \"forUpdate\"));\n        setForUpdate.addBodyLine(\"this.forUpdate = forUpdate;\");\n        topLevelClass.addMethod(setForUpdate);\n\n        Method getForUpdate = new Method();\n        getForUpdate.setVisibility(JavaVisibility.PUBLIC);\n        getForUpdate.setReturnType(booleanWrapper);\n        getForUpdate.setName(\"getForUpdate\");\n        getForUpdate.addBodyLine(\"return forUpdate;\");\n        topLevelClass.addMethod(getForUpdate);\n\n        return true;\n    }\n\n    private void appendForUpdate(XmlElement element, IntrospectedTable introspectedTable) {\n        XmlElement forUpdateElement = new XmlElement(\"if\");\n        forUpdateElement.addAttribute(new Attribute(\"test\", \"forUpdate != null and forUpdate == true\"));\n        forUpdateElement.addElement(new TextElement(\"for update\"));\n        element.addElement(forUpdateElement);\n    }\n\n\n    @Override\n    public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {\n        appendForUpdate(element, introspectedTable);\n        return true;\n    }\n\n    @Override\n    public boolean sqlMapSelectByExampleWithBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {\n        appendForUpdate(element, introspectedTable);\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/plugins/MySQLLimitPlugin.java",
    "content": "package com.zzg.mybatis.generator.plugins;\n\n/**\n * Created by zouzhigang on 2016/6/14.\n */\n\nimport org.mybatis.generator.api.IntrospectedTable;\nimport org.mybatis.generator.api.PluginAdapter;\nimport org.mybatis.generator.api.dom.java.*;\nimport org.mybatis.generator.api.dom.xml.Attribute;\nimport org.mybatis.generator.api.dom.xml.TextElement;\nimport org.mybatis.generator.api.dom.xml.XmlElement;\n\nimport java.util.List;\n\npublic class MySQLLimitPlugin extends PluginAdapter {\n\n    @Override\n    public boolean validate(List<String> list) {\n        return true;\n    }\n\n    /**\n     * 为每个Example类添加limit和offset属性已经set、get方法\n     */\n    @Override\n    public boolean modelExampleClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {\n\n        PrimitiveTypeWrapper integerWrapper = FullyQualifiedJavaType.getIntInstance().getPrimitiveTypeWrapper();\n        PrimitiveTypeWrapper longWrapper = new FullyQualifiedJavaType(\"long\").getPrimitiveTypeWrapper();\n\n        Field limit = new Field();\n        limit.setName(\"limit\");\n        limit.setVisibility(JavaVisibility.PRIVATE);\n        limit.setType(integerWrapper);\n        topLevelClass.addField(limit);\n\n        Method setLimit = new Method();\n        setLimit.setVisibility(JavaVisibility.PUBLIC);\n        setLimit.setName(\"setLimit\");\n        setLimit.addParameter(new Parameter(integerWrapper, \"limit\"));\n        setLimit.addBodyLine(\"this.limit = limit;\");\n        topLevelClass.addMethod(setLimit);\n\n        Method getLimit = new Method();\n        getLimit.setVisibility(JavaVisibility.PUBLIC);\n        getLimit.setReturnType(integerWrapper);\n        getLimit.setName(\"getLimit\");\n        getLimit.addBodyLine(\"return limit;\");\n        topLevelClass.addMethod(getLimit);\n\n        Field offset = new Field();\n        offset.setName(\"offset\");\n        offset.setVisibility(JavaVisibility.PRIVATE);\n        offset.setType(longWrapper);\n        topLevelClass.addField(offset);\n\n        Method setOffset = new Method();\n        setOffset.setVisibility(JavaVisibility.PUBLIC);\n        setOffset.setName(\"setOffset\");\n        setOffset.addParameter(new Parameter(longWrapper, \"offset\"));\n        setOffset.addBodyLine(\"this.offset = offset;\");\n        topLevelClass.addMethod(setOffset);\n\n        Method getOffset = new Method();\n        getOffset.setVisibility(JavaVisibility.PUBLIC);\n        getOffset.setReturnType(longWrapper);\n        getOffset.setName(\"getOffset\");\n        getOffset.addBodyLine(\"return offset;\");\n        topLevelClass.addMethod(getOffset);\n\n        return true;\n    }\n\n    /**\n     * 为Mapper.xml的selectByExample添加limit\n     */\n    @Override\n    public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element,\n                                                                     IntrospectedTable introspectedTable) {\n\n        XmlElement ifLimitNotNullElement = new XmlElement(\"if\");\n        ifLimitNotNullElement.addAttribute(new Attribute(\"test\", \"limit != null\"));\n\n        XmlElement ifOffsetNotNullElement = new XmlElement(\"if\");\n        ifOffsetNotNullElement.addAttribute(new Attribute(\"test\", \"offset != null\"));\n        ifOffsetNotNullElement.addElement(new TextElement(\"limit ${offset}, ${limit}\"));\n        ifLimitNotNullElement.addElement(ifOffsetNotNullElement);\n\n        XmlElement ifOffsetNullElement = new XmlElement(\"if\");\n        ifOffsetNullElement.addAttribute(new Attribute(\"test\", \"offset == null\"));\n        ifOffsetNullElement.addElement(new TextElement(\"limit ${limit}\"));\n        ifLimitNotNullElement.addElement(ifOffsetNullElement);\n\n        element.addElement(ifLimitNotNullElement);\n\n        return true;\n    }\n\n    /**\n     * 为Mapper.xml的selectByExampleWithBLOBs添加limit\n     */\n    @Override\n    public boolean sqlMapSelectByExampleWithBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {\n        XmlElement ifLimitNotNullElement = new XmlElement(\"if\");\n        ifLimitNotNullElement.addAttribute(new Attribute(\"test\", \"limit != null\"));\n\n        XmlElement ifOffsetNotNullElement = new XmlElement(\"if\");\n        ifOffsetNotNullElement.addAttribute(new Attribute(\"test\", \"offset != null\"));\n        ifOffsetNotNullElement.addElement(new TextElement(\"limit ${offset}, ${limit}\"));\n        ifLimitNotNullElement.addElement(ifOffsetNotNullElement);\n\n        XmlElement ifOffsetNullElement = new XmlElement(\"if\");\n        ifOffsetNullElement.addAttribute(new Attribute(\"test\", \"offset == null\"));\n        ifOffsetNullElement.addElement(new TextElement(\"limit ${limit}\"));\n        ifLimitNotNullElement.addElement(ifOffsetNullElement);\n\n        element.addElement(ifLimitNotNullElement);\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/plugins/RepositoryPlugin.java",
    "content": "package com.zzg.mybatis.generator.plugins;\n\nimport org.mybatis.generator.api.IntrospectedTable;\nimport org.mybatis.generator.api.PluginAdapter;\nimport org.mybatis.generator.api.dom.java.*;\n\nimport java.util.List;\n\n/**\n * Project: mybatis-generator-gui\n *\n * @author slankka on 2017/12/13.\n */\npublic class RepositoryPlugin extends PluginAdapter {\n\n    private FullyQualifiedJavaType annotationRepository;\n    private String annotation = \"@Repository\";\n\n    public RepositoryPlugin () {\n        annotationRepository = new FullyQualifiedJavaType(\"org.springframework.stereotype.Repository\"); //$NON-NLS-1$\n    }\n\n    @Override\n    public boolean validate(List<String> list) {\n        return true;\n    }\n\n    @Override\n    public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {\n        interfaze.addImportedType(annotationRepository);\n        interfaze.addAnnotation(annotation);\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/util/ConfigHelper.java",
    "content": "package com.zzg.mybatis.generator.util;\n\nimport com.alibaba.fastjson.JSON;\nimport com.zzg.mybatis.generator.model.DatabaseConfig;\nimport com.zzg.mybatis.generator.model.DbType;\nimport com.zzg.mybatis.generator.model.GeneratorConfig;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.net.URLDecoder;\nimport java.nio.charset.Charset;\nimport java.sql.Connection;\nimport java.sql.ResultSet;\nimport java.sql.Statement;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * XML based config file help class\n * <p>\n * Created by Owen on 6/16/16.\n */\npublic class ConfigHelper {\n\n\tprivate static final Logger _LOG = LoggerFactory.getLogger(ConfigHelper.class);\n\tprivate static final String BASE_DIR = \"config\";\n\tprivate static final String CONFIG_FILE = \"/sqlite3.db\";\n\n\tpublic static void createEmptyFiles() throws Exception {\n\t\tFile file = new File(BASE_DIR);\n\t\tif (!file.exists()) {\n\t\t\tfile.mkdir();\n\t\t}\n\t\tFile uiConfigFile = new File(BASE_DIR + CONFIG_FILE);\n\t\tif (!uiConfigFile.exists()) {\n\t\t\tcreateEmptyXMLFile(uiConfigFile);\n\t\t}\n\t}\n\n\tstatic void createEmptyXMLFile(File uiConfigFile) throws IOException {\n\t\tInputStream fis = null;\n\t\tFileOutputStream fos = null;\n\t\ttry {\n\t\t\tfis = Thread.currentThread().getContextClassLoader().getResourceAsStream(\"sqlite3.db\");\n\t\t\tfos = new FileOutputStream(uiConfigFile);\n\t\t\tbyte[] buffer = new byte[1024];\n\t\t\tint byteread = 0;\n\t\t\twhile ((byteread = fis.read(buffer)) != -1) {\n\t\t\t\tfos.write(buffer, 0, byteread);\n\t\t\t}\n\t\t} finally {\n\t\t\tif (fis != null) fis.close();\n\t\t\tif (fos != null) fos.close();\n\t\t}\n\n\t}\n\n\tpublic static List<DatabaseConfig> loadDatabaseConfig() throws Exception {\n\t\tConnection conn = null;\n\t\tStatement stat = null;\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\tconn = ConnectionManager.getConnection();\n\t\t\tstat = conn.createStatement();\n\t\t\trs = stat.executeQuery(\"SELECT * FROM dbs\");\n\t\t\tList<DatabaseConfig> configs = new ArrayList<>();\n\t\t\twhile (rs.next()) {\n\t\t\t\tint id = rs.getInt(\"id\");\n\t\t\t\tString value = rs.getString(\"value\");\n\t\t\t\tDatabaseConfig databaseConfig = JSON.parseObject(value, DatabaseConfig.class);\n\t\t\t\tdatabaseConfig.setId(id);\n\t\t\t\tconfigs.add(databaseConfig);\n\t\t\t}\n\n\t\t\treturn configs;\n\t\t} finally {\n\t\t\tif (rs != null) rs.close();\n\t\t\tif (stat != null) stat.close();\n\t\t\tif (conn != null) conn.close();\n\t\t}\n\t}\n\n\tpublic static void saveDatabaseConfig(boolean isUpdate, Integer primaryKey, DatabaseConfig dbConfig) throws Exception {\n\t\tString configName = dbConfig.getName();\n\t\tConnection conn = null;\n\t\tStatement stat = null;\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\tconn = ConnectionManager.getConnection();\n\t\t\tstat = conn.createStatement();\n\t\t\tif (!isUpdate) {\n\t\t\t\tResultSet rs1 = stat.executeQuery(\"SELECT * from dbs where name = '\" + configName + \"'\");\n\t\t\t\tif (rs1.next()) {\n\t\t\t\t\tthrow new RuntimeException(\"配置已经存在, 请使用其它名字\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tString jsonStr = JSON.toJSONString(dbConfig);\n\t\t\tString sql;\n\t\t\tif (isUpdate) {\n\t\t\t\tsql = String.format(\"UPDATE dbs SET name = '%s', value = '%s' where id = %d\", configName, jsonStr, primaryKey);\n\t\t\t} else {\n\t\t\t\tsql = String.format(\"INSERT INTO dbs (name, value) values('%s', '%s')\", configName, jsonStr);\n\t\t\t}\n\t\t\tstat.executeUpdate(sql);\n\t\t} finally {\n\t\t\tif (rs != null) rs.close();\n\t\t\tif (stat != null) stat.close();\n\t\t\tif (conn != null) conn.close();\n\t\t}\n\t}\n\n\tpublic static void deleteDatabaseConfig(DatabaseConfig databaseConfig) throws Exception {\n\t\tConnection conn = null;\n\t\tStatement stat = null;\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\tconn = ConnectionManager.getConnection();\n\t\t\tstat = conn.createStatement();\n\t\t\tString sql = String.format(\"delete from dbs where id=%d\", databaseConfig.getId());\n\t\t\tstat.executeUpdate(sql);\n\t\t} finally {\n\t\t\tif (rs != null) rs.close();\n\t\t\tif (stat != null) stat.close();\n\t\t\tif (conn != null) conn.close();\n\t\t}\n\t}\n\n\tpublic static void saveGeneratorConfig(GeneratorConfig generatorConfig) throws Exception {\n\t\tConnection conn = null;\n\t\tStatement stat = null;\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\tconn = ConnectionManager.getConnection();\n\t\t\tstat = conn.createStatement();\n\t\t\tString jsonStr = JSON.toJSONString(generatorConfig);\n\t\t\tString sql = String.format(\"INSERT INTO generator_config values('%s', '%s')\", generatorConfig.getName(),\n\t\t\t\t\tjsonStr);\n\t\t\tstat.executeUpdate(sql);\n\t\t} finally {\n\t\t\tif (rs != null) rs.close();\n\t\t\tif (stat != null) stat.close();\n\t\t\tif (conn != null) conn.close();\n\t\t}\n\t}\n\n\tpublic static GeneratorConfig loadGeneratorConfig(String name) throws Exception {\n\t\tConnection conn = null;\n\t\tStatement stat = null;\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\tconn = ConnectionManager.getConnection();\n\t\t\tstat = conn.createStatement();\n\t\t\tString sql = String.format(\"SELECT * FROM generator_config where name='%s'\", name);\n\t\t\t_LOG.info(\"sql: {}\", sql);\n\t\t\trs = stat.executeQuery(sql);\n\t\t\tGeneratorConfig generatorConfig = null;\n\t\t\tif (rs.next()) {\n\t\t\t\tString value = rs.getString(\"value\");\n\t\t\t\tgeneratorConfig = JSON.parseObject(value, GeneratorConfig.class);\n\t\t\t}\n\t\t\treturn generatorConfig;\n\t\t} finally {\n\t\t\tif (rs != null) rs.close();\n\t\t\tif (stat != null) stat.close();\n\t\t\tif (conn != null) conn.close();\n\t\t}\n\t}\n\n\tpublic static List<GeneratorConfig> loadGeneratorConfigs() throws Exception {\n\t\tConnection conn = null;\n\t\tStatement stat = null;\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\tconn = ConnectionManager.getConnection();\n\t\t\tstat = conn.createStatement();\n\t\t\tString sql = String.format(\"SELECT * FROM generator_config\");\n\t\t\t_LOG.info(\"sql: {}\", sql);\n\t\t\trs = stat.executeQuery(sql);\n\t\t\tList<GeneratorConfig> configs = new ArrayList<>();\n\t\t\twhile (rs.next()) {\n\t\t\t\tString value = rs.getString(\"value\");\n\t\t\t\tconfigs.add(JSON.parseObject(value, GeneratorConfig.class));\n\t\t\t}\n\t\t\treturn configs;\n\t\t} finally {\n\t\t\tif (rs != null) rs.close();\n\t\t\tif (stat != null) stat.close();\n\t\t\tif (conn != null) conn.close();\n\t\t}\n\t}\n\n\tpublic static int deleteGeneratorConfig(String name) throws Exception {\n\t\tConnection conn = null;\n\t\tStatement stat = null;\n\t\ttry {\n\t\t\tconn = ConnectionManager.getConnection();\n\t\t\tstat = conn.createStatement();\n\t\t\tString sql = String.format(\"DELETE FROM generator_config where name='%s'\", name);\n\t\t\t_LOG.info(\"sql: {}\", sql);\n\t\t\treturn stat.executeUpdate(sql);\n\t\t} finally {\n\t\t\tif (stat != null) stat.close();\n\t\t\tif (conn != null) conn.close();\n\t\t}\n\t}\n\n\tpublic static String findConnectorLibPath(String dbType) {\n\t\tDbType type = DbType.valueOf(dbType);\n\t\tURL resource = Thread.currentThread().getContextClassLoader().getResource(\"logback.xml\");\n\t\t_LOG.info(\"jar resource: {}\", resource);\n\t\tif (resource != null) {\n\t\t\ttry {\n\t\t\t\tFile file = new File(resource.toURI().getRawPath() + \"/../lib/\" + type.getConnectorJarFile());\n\t\t\t\treturn URLDecoder.decode(file.getCanonicalPath(), Charset.forName(\"UTF-8\").displayName());\n\t\t\t} catch (Exception e) {\n\t\t\t\tthrow new RuntimeException(\"找不到驱动文件，请联系开发者\");\n\t\t\t}\n\t\t} else {\n\t\t\tthrow new RuntimeException(\"lib can't find\");\n\t\t}\n\t}\n\n\tpublic static List<String> getAllJDBCDriverJarPaths() {\n\t\tList<String> jarFilePathList = new ArrayList<>();\n\t\tURL url = Thread.currentThread().getContextClassLoader().getResource(\"logback.xml\");\n\t\ttry {\n\t\t\tFile file;\n\t\t\tif (url.getPath().contains(\".jar\")) {\n\t\t\t\tfile = new File(\"lib/\");\n\t\t\t} else {\n\t\t\t\tfile = new File(\"src/main/resources/lib\");\n\t\t\t}\n\t\t\t_LOG.info(\"jar lib path: {}\", file.getCanonicalPath());\n\t\t\tFile[] jarFiles = file.listFiles();\n\t\t\tif (jarFiles != null && jarFiles.length > 0) {\n\t\t\t\tfor (File jarFile : jarFiles) {\n\t\t\t\t\t_LOG.info(\"jar file: {}\", jarFile.getAbsolutePath());\n\t\t\t\t\tif (jarFile.isFile() && jarFile.getAbsolutePath().endsWith(\".jar\")) {\n\t\t\t\t\t\tjarFilePathList.add(jarFile.getAbsolutePath());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(\"找不到驱动文件，请联系开发者\");\n\t\t}\n\t\treturn jarFilePathList;\n\t}\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/util/ConnectionManager.java",
    "content": "package com.zzg.mybatis.generator.util;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.File;\nimport java.sql.Connection;\nimport java.sql.DriverManager;\n\n/**\n * Created by Owen on 8/21/16.\n */\npublic class ConnectionManager {\n    private static final Logger _LOG = LoggerFactory.getLogger(ConnectionManager.class);\n    private static final String DB_URL = \"jdbc:sqlite:./config/sqlite3.db\";\n\n    public static Connection getConnection() throws Exception {\n        Class.forName(\"org.sqlite.JDBC\");\n        File file = new File(DB_URL.substring(\"jdbc:sqlite:\".length())).getAbsoluteFile();\n        _LOG.info(\"database FilePath :{}\", file.getAbsolutePath());\n        Connection conn = DriverManager.getConnection(DB_URL);\n        return conn;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/util/DbUtil.java",
    "content": "package com.zzg.mybatis.generator.util;\n\nimport com.jcraft.jsch.JSch;\nimport com.jcraft.jsch.JSchException;\nimport com.jcraft.jsch.Session;\nimport com.zzg.mybatis.generator.exception.DbDriverLoadingException;\nimport com.zzg.mybatis.generator.model.DatabaseConfig;\nimport com.zzg.mybatis.generator.model.DbType;\nimport com.zzg.mybatis.generator.model.UITableColumnVO;\nimport com.zzg.mybatis.generator.view.AlertUtil;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.commons.lang3.math.NumberUtils;\nimport org.mybatis.generator.internal.util.ClassloaderUtility;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.sql.*;\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * Created by Owen on 6/12/16.\n */\npublic class DbUtil {\n\n    private static final Logger _LOG = LoggerFactory.getLogger(DbUtil.class);\n    private static final int DB_CONNECTION_TIMEOUTS_SECONDS = 1;\n\n    private static Map<DbType, Driver> drivers = new HashMap<>();\n\n\tprivate static ExecutorService executorService = Executors.newSingleThreadExecutor();\n\tprivate static volatile boolean portForwaring = false;\n\tprivate static Map<Integer, Session> portForwardingSession = new ConcurrentHashMap<>();\n\n    public static Session getSSHSession(DatabaseConfig databaseConfig) {\n\t\tif (StringUtils.isBlank(databaseConfig.getSshHost())\n\t\t\t\t|| StringUtils.isBlank(databaseConfig.getSshPort())\n\t\t\t\t|| StringUtils.isBlank(databaseConfig.getSshUser())\n\t\t\t\t|| (StringUtils.isBlank(databaseConfig.getPrivateKey()) && StringUtils.isBlank(databaseConfig.getSshPassword()))\n\t\t) {\n\t\t\treturn null;\n\t\t}\n\n\t\tSession session = null;\n\t\ttry {\n\t\t\t//Set StrictHostKeyChecking property to no to avoid UnknownHostKey issue\n\t\t\tjava.util.Properties config = new java.util.Properties();\n\t\t\tconfig.put(\"StrictHostKeyChecking\", \"no\");\n\t\t\tJSch jsch = new JSch();\n\t\t\tInteger sshPort = NumberUtils.createInteger(databaseConfig.getSshPort());\n\t\t\tint port = sshPort == null ? 22 : sshPort;\n\t\t\tsession = jsch.getSession(databaseConfig.getSshUser(), databaseConfig.getSshHost(), port);\n\t\t\tif (StringUtils.isNotBlank(databaseConfig.getPrivateKey())) {\n\t\t\t\t//使用秘钥方式认证\n\t\t\t\tjsch.addIdentity(databaseConfig.getPrivateKey(), StringUtils.defaultIfBlank(databaseConfig.getPrivateKeyPassword(), null));\n\t\t\t}else {\n\t\t\t\tsession.setPassword(databaseConfig.getSshPassword());\n\t\t\t}\n\t\t\tsession.setConfig(config);\n\t\t}catch (JSchException e) {\n\t\t\t//Ignore\n\t\t}\n\t\treturn session;\n\t}\n\n\tpublic static void engagePortForwarding(Session sshSession, DatabaseConfig config) {\n\t\tif (sshSession != null) {\n\t\t\tAtomicInteger assinged_port = new AtomicInteger();\n\t\t\tFuture<?> result = executorService.submit(() -> {\n\t\t\t\ttry {\n\t\t\t\t\tInteger localPort = NumberUtils.createInteger(config.getLport());\n\t\t\t\t\tInteger RemotePort = NumberUtils.createInteger(config.getRport());\n\t\t\t\t\tint lport = localPort == null ? Integer.parseInt(config.getPort()) : localPort;\n\t\t\t\t\tint rport = RemotePort == null ? Integer.parseInt(config.getPort()) : RemotePort;\n\t\t\t\t\tSession session = portForwardingSession.get(lport);\n\t\t\t\t\tif (session != null && session.isConnected()) {\n\t\t\t\t\t\tString s = session.getPortForwardingL()[0];\n\t\t\t\t\t\tString[] split = StringUtils.split(s, \":\");\n\t\t\t\t\t\tboolean portForwarding = String.format(\"%s:%s\", split[0], split[1]).equals(lport + \":\" + config.getHost());\n\t\t\t\t\t\tif (portForwarding) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tsshSession.connect();\n\t\t\t\t\tassinged_port.set(sshSession.setPortForwardingL(lport, config.getHost(), rport));\n\t\t\t\t\tportForwardingSession.put(lport, sshSession);\n\t\t\t\t\tportForwaring = true;\n\t\t\t\t\t_LOG.info(\"portForwarding Enabled, {}\", assinged_port);\n\t\t\t\t} catch (JSchException e) {\n\t\t\t\t\t_LOG.error(\"Connect Over SSH failed\", e);\n\t\t\t\t\tif (e.getCause() != null && e.getCause().getMessage().equals(\"Address already in use: JVM_Bind\")) {\n\t\t\t\t\t\tthrow new RuntimeException(\"Address already in use: JVM_Bind\");\n\t\t\t\t\t}\n\t\t\t\t\tthrow new RuntimeException(e.getMessage());\n\t\t\t\t}\n\t\t\t});\n\t\t\ttry {\n\t\t\t\tresult.get(5, TimeUnit.SECONDS);\n\t\t\t}catch (Exception e) {\n\t\t\t\tshutdownPortForwarding(sshSession);\n\t\t\t\tif (e.getCause() instanceof RuntimeException) {\n\t\t\t\t\tthrow (RuntimeException)e.getCause();\n\t\t\t\t}\n\t\t\t\tif (e instanceof TimeoutException) {\n\t\t\t\t\tthrow new RuntimeException(\"OverSSH 连接超时：超过5秒\");\n\t\t\t\t}\n\n\t\t\t\t_LOG.info(\"executorService isShutdown:{}\", executorService.isShutdown());\n\t\t\t\tAlertUtil.showErrorAlert(\"OverSSH 失败，请检查连接设置:\" + e.getMessage());\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void shutdownPortForwarding(Session session) {\n\t\tportForwaring = false;\n\t\tif (session != null && session.isConnected()) {\n\t\t\tsession.disconnect();\n\t\t\t_LOG.info(\"portForwarding turn OFF\");\n\t\t}\n//\t\texecutorService.shutdown();\n\t}\n\n    public static Connection getConnection(DatabaseConfig config) throws ClassNotFoundException, SQLException {\n\t\tDbType dbType = DbType.valueOf(config.getDbType());\n\t\tif (drivers.get(dbType) == null){\n\t\t\tloadDbDriver(dbType);\n\t\t}\n\n\t\tString url = getConnectionUrlWithSchema(config);\n\t    Properties props = new Properties();\n\n\t    props.setProperty(\"user\", config.getUsername()); //$NON-NLS-1$\n\t    props.setProperty(\"password\", config.getPassword()); //$NON-NLS-1$\n\n\t\tDriverManager.setLoginTimeout(DB_CONNECTION_TIMEOUTS_SECONDS);\n\t    Connection connection = drivers.get(dbType).connect(url, props);\n        _LOG.info(\"getConnection, connection url: {}\", connection);\n        return connection;\n    }\n\n    public static List<String> getTableNames(DatabaseConfig config, String filter) throws Exception {\n\t\tSession sshSession = getSSHSession(config);\n\t\tengagePortForwarding(sshSession, config);\n\t\ttry (Connection connection = getConnection(config)) {\n\t\t\tList<String> tables = new ArrayList<>();\n\t\t\tDatabaseMetaData md = connection.getMetaData();\n\t\t\tResultSet rs;\n\t\t\tif (DbType.valueOf(config.getDbType()) == DbType.SQL_Server) {\n\t\t\t\tString sql = \"select name from sysobjects  where xtype='u' or xtype='v' order by name\";\n\t\t\t\trs = connection.createStatement().executeQuery(sql);\n\t\t\t\twhile (rs.next()) {\n\t\t\t\t\ttables.add(rs.getString(\"name\"));\n\t\t\t\t}\n\t\t\t} else if (DbType.valueOf(config.getDbType()) == DbType.Oracle) {\n\t\t\t\trs = md.getTables(null, config.getUsername().toUpperCase(), null, new String[]{\"TABLE\", \"VIEW\"});\n\t\t\t} else if (DbType.valueOf(config.getDbType()) == DbType.Sqlite) {\n\t\t\t\tString sql = \"Select name from sqlite_master;\";\n\t\t\t\trs = connection.createStatement().executeQuery(sql);\n\t\t\t\twhile (rs.next()) {\n\t\t\t\t\ttables.add(rs.getString(\"name\"));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// rs = md.getTables(null, config.getUsername().toUpperCase(), null, null);\n\t\t\t\trs = md.getTables(config.getSchema(), null, \"%\", new String[]{\"TABLE\", \"VIEW\"});//针对 postgresql 的左侧数据表显示\n\t\t\t}\n\t\t\twhile (rs.next()) {\n\t\t\t\ttables.add(rs.getString(3));\n\t\t\t}\n\t\t\tif (StringUtils.isNotBlank(filter)) {\n\t\t\t\ttables.removeIf(x -> !x.contains(filter) && !(x.replaceAll(\"_\", \"\").contains(filter)));;\n\t\t\t}\n\t\t\tif (tables.size() > 1) {\n\t\t\t\tCollections.sort(tables);\n\t\t\t}\n\t\t\treturn tables;\n\t\t} finally {\n\t\t\tshutdownPortForwarding(sshSession);\n\t\t}\n\t}\n\n    public static List<UITableColumnVO> getTableColumns(DatabaseConfig dbConfig, String tableName) throws Exception {\n        String url = getConnectionUrlWithSchema(dbConfig);\n        _LOG.info(\"getTableColumns, connection url: {}\", url);\n\t\tSession sshSession = getSSHSession(dbConfig);\n\t\tengagePortForwarding(sshSession, dbConfig);\n\t\tConnection conn = getConnection(dbConfig);\n\t\ttry {\n\t\t\tDatabaseMetaData md = conn.getMetaData();\n\t\t\tResultSet rs = md.getColumns(dbConfig.getSchema(), null, tableName, null);\n\t\t\tList<UITableColumnVO> columns = new ArrayList<>();\n\t\t\twhile (rs.next()) {\n\t\t\t\tUITableColumnVO columnVO = new UITableColumnVO();\n\t\t\t\tString columnName = rs.getString(\"COLUMN_NAME\");\n\t\t\t\tcolumnVO.setColumnName(columnName);\n\t\t\t\tcolumnVO.setJdbcType(rs.getString(\"TYPE_NAME\"));\n\t\t\t\tcolumns.add(columnVO);\n\t\t\t}\n\t\t\treturn columns;\n\t\t} finally {\n\t\t\tconn.close();\n\t\t\tshutdownPortForwarding(sshSession);\n\t\t}\n\t}\n\n    public static String getConnectionUrlWithSchema(DatabaseConfig dbConfig) throws ClassNotFoundException {\n\t\tDbType dbType = DbType.valueOf(dbConfig.getDbType());\n\t\tString connectionUrl = String.format(dbType.getConnectionUrlPattern(),\n\t\t\t\tportForwaring ? \"127.0.0.1\" : dbConfig.getHost(), portForwaring ? dbConfig.getLport() : dbConfig.getPort(), dbConfig.getSchema(), dbConfig.getEncoding());\n        _LOG.info(\"getConnectionUrlWithSchema, connection url: {}\", connectionUrl);\n        return connectionUrl;\n    }\n\n\t/**\n\t * 加载数据库驱动\n\t * @param dbType 数据库类型\n\t */\n\tprivate static void loadDbDriver(DbType dbType){\n\t\tList<String> driverJars = ConfigHelper.getAllJDBCDriverJarPaths();\n\t\tClassLoader classloader = ClassloaderUtility.getCustomClassloader(driverJars);\n\t\ttry {\n\t\t\tClass clazz = Class.forName(dbType.getDriverClass(), true, classloader);\n\t\t\tDriver driver = (Driver) clazz.newInstance();\n\t\t\t_LOG.info(\"load driver class: {}\", driver);\n\t\t\tdrivers.put(dbType, driver);\n\t\t} catch (Exception e) {\n\t\t\t_LOG.error(\"load driver error\", e);\n\t\t\tthrow new DbDriverLoadingException(\"找不到\"+dbType.getConnectorJarFile()+\"驱动\");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/util/MyStringUtils.java",
    "content": "package com.zzg.mybatis.generator.util;\n\n/**\n * Created by Owen on 6/18/16.\n */\npublic class MyStringUtils {\n\n    /**\n     *\n     * convert string from slash style to camel style, such as my_course will convert to MyCourse\n     *\n     * @param str\n     * @return\n     */\n    public static String dbStringToCamelStyle(String str) {\n        if (str != null) {\n            if (str.contains(\"_\")) {\n                str = str.toLowerCase();\n                StringBuilder sb = new StringBuilder();\n                sb.append(String.valueOf(str.charAt(0)).toUpperCase());\n                for (int i = 1; i < str.length(); i++) {\n                    char c = str.charAt(i);\n                    if (c != '_') {\n                        sb.append(c);\n                    } else {\n                        if (i + 1 < str.length()) {\n                            sb.append(String.valueOf(str.charAt(i + 1)).toUpperCase());\n                            i++;\n                        }\n                    }\n                }\n                return sb.toString();\n            } else {\n                String firstChar = String.valueOf(str.charAt(0)).toUpperCase();\n                String otherChars = str.substring(1);\n                return firstChar + otherChars;\n            }\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/view/AlertUtil.java",
    "content": "package com.zzg.mybatis.generator.view;\n\nimport javafx.scene.control.Alert;\n\n/**\n * Created by Owen on 6/21/16.\n */\npublic class AlertUtil {\n\n    public static void showInfoAlert(String message) {\n        Alert alert = new Alert(Alert.AlertType.INFORMATION);\n        alert.setContentText(message);\n        alert.show();\n    }\n\n    public static void showWarnAlert(String message) {\n        Alert alert = new Alert(Alert.AlertType.WARNING);\n        alert.setContentText(message);\n        alert.show();\n    }\n\n    public static void showErrorAlert(String message) {\n        Alert alert = new Alert(Alert.AlertType.ERROR);\n        alert.setContentText(message);\n        alert.show();\n    }\n\n    /**\n     * build both OK and Cancel buttons for the user\n     * to click on to dismiss the dialog.\n     *\n     * @param message\n     */\n    public static Alert buildConfirmationAlert(String message) {\n        Alert alert = new Alert(Alert.AlertType.CONFIRMATION);\n        alert.setContentText(message);\n        return alert;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/view/LeftDbTreeCell.java",
    "content": "package com.zzg.mybatis.generator.view;\n\nimport com.zzg.mybatis.generator.model.DatabaseConfig;\nimport javafx.beans.InvalidationListener;\nimport javafx.beans.Observable;\nimport javafx.beans.WeakInvalidationListener;\nimport javafx.scene.control.TreeCell;\nimport javafx.scene.control.TreeItem;\nimport javafx.scene.layout.HBox;\n\nimport java.lang.ref.WeakReference;\n\n/**\n * Created by Owen on 6/14/16.\n */\npublic class LeftDbTreeCell extends TreeCell<DatabaseConfig> {\n    private HBox hbox;\n\n    private WeakReference<TreeItem<DatabaseConfig>> treeItemRef;\n\n    private InvalidationListener treeItemGraphicListener = observable -> {\n        updateDisplay(getItem(), isEmpty());\n    };\n\n    private InvalidationListener treeItemListener = new InvalidationListener() {\n        @Override\n        public void invalidated(Observable observable) {\n            TreeItem<DatabaseConfig> oldTreeItem = treeItemRef == null ? null : treeItemRef.get();\n            if (oldTreeItem != null) {\n                oldTreeItem.graphicProperty().removeListener(weakTreeItemGraphicListener);\n            }\n\n            TreeItem<DatabaseConfig> newTreeItem = getTreeItem();\n            if (newTreeItem != null) {\n                newTreeItem.graphicProperty().addListener(weakTreeItemGraphicListener);\n                treeItemRef = new WeakReference<TreeItem<DatabaseConfig>>(newTreeItem);\n            }\n        }\n    };\n\n    private WeakInvalidationListener weakTreeItemGraphicListener =\n            new WeakInvalidationListener(treeItemGraphicListener);\n\n    private WeakInvalidationListener weakTreeItemListener =\n            new WeakInvalidationListener(treeItemListener);\n\n    public LeftDbTreeCell() {\n        treeItemProperty().addListener(weakTreeItemListener);\n\n        if (getTreeItem() != null) {\n            getTreeItem().graphicProperty().addListener(weakTreeItemGraphicListener);\n        }\n    }\n\n    void updateDisplay(DatabaseConfig item, boolean empty) {\n        if (item == null || empty) {\n            hbox = null;\n            setText(null);\n            setGraphic(null);\n        } else {\n            // update the graphic if one is set in the TreeItem\n            TreeItem<DatabaseConfig> treeItem = getTreeItem();\n            if (treeItem != null && treeItem.getGraphic() != null) {\n                hbox = null;\n                setText(item.toString());\n                setGraphic(treeItem.getGraphic());\n            } else {\n                hbox = null;\n                setText(item.getName());\n                setGraphic(null);\n            }\n        }\n    }\n\n    @Override\n    public void updateItem(DatabaseConfig item, boolean empty) {\n        super.updateItem(item, empty);\n        updateDisplay(item, empty);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/zzg/mybatis/generator/view/UIProgressCallback.java",
    "content": "package com.zzg.mybatis.generator.view;\n\nimport javafx.beans.property.SimpleStringProperty;\nimport javafx.beans.property.StringProperty;\nimport javafx.scene.control.Alert;\nimport org.mybatis.generator.api.ProgressCallback;\n\n/**\n * Created by Owen on 6/21/16.\n */\npublic class UIProgressCallback extends Alert implements ProgressCallback  {\n\n    private StringProperty progressText = new SimpleStringProperty();\n\n    public UIProgressCallback(AlertType alertType) {\n\t\tsuper(alertType);\n\t\tthis.contentTextProperty().bindBidirectional(progressText);\n    }\n\n    @Override\n    public void introspectionStarted(int totalTasks) {\n\t\tprogressText.setValue(\"开始代码检查\");\n\t}\n\n    @Override\n    public void generationStarted(int totalTasks) {\n\t\tprogressText.setValue(\"开始代码生成\");\n    }\n\n    @Override\n    public void saveStarted(int totalTasks) {\n\t\tprogressText.setValue(\"开始保存生成的文件\");\n    }\n\n    @Override\n    public void startTask(String taskName) {\n\t\tprogressText.setValue(\"代码生成任务开始\");\n    }\n\n    @Override\n    public void done() {\n\t\tprogressText.setValue(\"代码生成完成\");\n    }\n\n    @Override\n    public void checkCancel() throws InterruptedException {\n    }\n}\n"
  },
  {
    "path": "src/main/resources/fxml/MainUI.fxml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<?import java.lang.*?>\n<?import javafx.collections.*?>\n<?import javafx.geometry.*?>\n<?import javafx.scene.*?>\n<?import javafx.scene.control.*?>\n<?import javafx.scene.layout.*?>\n<?import javafx.scene.text.*?>\n\n<BorderPane prefHeight=\"613.0\" prefWidth=\"918.0\" stylesheets=\"@../style.css\" xmlns=\"http://javafx.com/javafx/11.0.1\" xmlns:fx=\"http://javafx.com/fxml/1\" fx:controller=\"com.zzg.mybatis.generator.controller.MainUIController\">\n    <top>\n        <VBox>\n            <children>\n                <ToolBar minHeight=\"70.0\" prefHeight=\"81.0\" prefWidth=\"918.0\" BorderPane.alignment=\"CENTER\">\n                    <items>\n                        <Label fx:id=\"connectionLabel\" contentDisplay=\"TOP\" text=\"数据库连接\">\n                            <cursor>\n                                <Cursor fx:constant=\"HAND\" />\n                            </cursor>\n                     <font>\n                        <Font size=\"14.0\" />\n                     </font>\n                     <padding>\n                        <Insets left=\"10.0\" right=\"10.0\" />\n                     </padding>\n                        </Label>\n                  <Label fx:id=\"configsLabel\" contentDisplay=\"TOP\" text=\"配置\">\n                     <padding>\n                        <Insets right=\"10.0\" />\n                     </padding></Label>\n                    </items>\n                </ToolBar>\n            </children>\n        </VBox>\n    </top>\n    <center>\n        <SplitPane dividerPositions=\"0.15\">\n            <items>\n                <AnchorPane maxWidth=\"500.0\" minWidth=\"100.0\" prefHeight=\"618.0\" prefWidth=\"200.0\">\n                    <children>\n                        <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\" />\n                  <TextField fx:id=\"filterTreeBox\" layoutY=\"504.0\" prefHeight=\"26.0\" prefWidth=\"134.0\" AnchorPane.leftAnchor=\"0.0\" AnchorPane.rightAnchor=\"0.0\" AnchorPane.bottomAnchor=\"0.0\" promptText=\"搜索\" />\n                    </children>\n                </AnchorPane>\n            <AnchorPane minWidth=\"400.0\">\n               <children>\n                  <VBox AnchorPane.bottomAnchor=\"0.0\" AnchorPane.leftAnchor=\"0.0\" AnchorPane.rightAnchor=\"0.0\" AnchorPane.topAnchor=\"0.0\">\n                     <children>\n                              <GridPane alignment=\"TOP_RIGHT\" layoutX=\"5.0\" layoutY=\"29.0\" prefHeight=\"505.0\" prefWidth=\"766.0\" vgap=\"5.0\" AnchorPane.leftAnchor=\"-5.0\" AnchorPane.rightAnchor=\"10.0\">\n                                  <columnConstraints>\n                                      <ColumnConstraints halignment=\"RIGHT\" hgrow=\"SOMETIMES\" maxWidth=\"157.0\" minWidth=\"132.0\" prefWidth=\"138.0\" />\n                                      <ColumnConstraints hgrow=\"SOMETIMES\" maxWidth=\"688.0\" minWidth=\"10.0\" prefWidth=\"222.0\" />\n                                      <ColumnConstraints halignment=\"RIGHT\" hgrow=\"SOMETIMES\" maxWidth=\"688.0\" minWidth=\"69.0\" prefWidth=\"76.0\" />\n                                      <ColumnConstraints hgrow=\"SOMETIMES\" maxWidth=\"688.0\" minWidth=\"10.0\" prefWidth=\"108.0\" />\n                              <ColumnConstraints halignment=\"RIGHT\" hgrow=\"SOMETIMES\" maxWidth=\"688.0\" minWidth=\"10.0\" prefWidth=\"129.0\" />\n                              <ColumnConstraints hgrow=\"SOMETIMES\" maxWidth=\"688.0\" minWidth=\"10.0\" prefWidth=\"95.0\" />\n                                  </columnConstraints>\n                                  <rowConstraints>\n                                      <RowConstraints minHeight=\"10.0\" prefHeight=\"30.0\" vgrow=\"SOMETIMES\" />\n                                      <RowConstraints maxHeight=\"44.0\" minHeight=\"10.0\" prefHeight=\"27.0\" vgrow=\"SOMETIMES\" />\n                                      <RowConstraints maxHeight=\"25.0\" minHeight=\"8.0\" prefHeight=\"25.0\" vgrow=\"SOMETIMES\" />\n                                      <RowConstraints minHeight=\"10.0\" prefHeight=\"30.0\" vgrow=\"SOMETIMES\" />\n                                      <RowConstraints minHeight=\"10.0\" prefHeight=\"30.0\" vgrow=\"SOMETIMES\" />\n                                      <RowConstraints minHeight=\"10.0\" prefHeight=\"30.0\" vgrow=\"SOMETIMES\" />\n                              <RowConstraints minHeight=\"10.0\" prefHeight=\"30.0\" vgrow=\"SOMETIMES\" />\n                                      <RowConstraints minHeight=\"10.0\" prefHeight=\"30.0\" vgrow=\"SOMETIMES\" />\n                              <RowConstraints maxHeight=\"91.0\" minHeight=\"0.0\" prefHeight=\"0.0\" vgrow=\"SOMETIMES\" />\n                              <RowConstraints maxHeight=\"182.0\" minHeight=\"8.0\" prefHeight=\"182.0\" vgrow=\"SOMETIMES\" />\n                              <RowConstraints maxHeight=\"99.0\" minHeight=\"11.0\" prefHeight=\"43.0\" />\n                                  </rowConstraints>\n                                  <children>\n                                      <Label text=\"表名\" />\n                                      <TextField fx:id=\"tableNameField\" disable=\"true\" editable=\"false\" prefHeight=\"27.0\" prefWidth=\"156.0\" promptText=\"person\" GridPane.columnIndex=\"1\">\n                                          <GridPane.margin>\n                                              <Insets left=\"5.0\" right=\"5.0\" />\n                                          </GridPane.margin>\n                                      </TextField>\n                                      <Label text=\"Java实体类名\" GridPane.rowIndex=\"1\" />\n                              <HBox alignment=\"CENTER_LEFT\" GridPane.columnIndex=\"1\" GridPane.columnSpan=\"3\" GridPane.rowIndex=\"1\" GridPane.valignment=\"CENTER\">\n                                 <children>\n                                            <TextField fx:id=\"domainObjectNameField\" prefHeight=\"27.0\" prefWidth=\"154.0\" promptText=\"Person\" GridPane.columnIndex=\"1\" GridPane.rowIndex=\"2\">\n                                                <GridPane.margin>\n                                                    <Insets left=\"5.0\" right=\"5.0\" />\n                                                </GridPane.margin>\n                                       <HBox.margin>\n                                          <Insets right=\"5.0\" />\n                                       </HBox.margin>\n                                            </TextField>\n                                    <Button mnemonicParsing=\"false\" onAction=\"#openTableColumnCustomizationPage\" text=\"定制列\">\n                                       <styleClass>\n                                          <String fx:value=\"btn\" />\n                                          <String fx:value=\"btn-default\" />\n                                       </styleClass>\n                                    </Button>\n                                 </children>\n                                 <GridPane.margin>\n                                    <Insets left=\"5.0\" />\n                                 </GridPane.margin>\n                              </HBox>\n                              <Label text=\"主键(选填)\" GridPane.rowIndex=\"2\" />\n                              <HBox alignment=\"CENTER_LEFT\" GridPane.columnIndex=\"1\" GridPane.columnSpan=\"3\" GridPane.rowIndex=\"2\" GridPane.valignment=\"CENTER\">\n                                 <children>\n                                            <TextField fx:id=\"generateKeysField\" prefHeight=\"25.0\" prefWidth=\"216.0\" promptText=\"primary key, such as id\" GridPane.columnIndex=\"1\" GridPane.rowIndex=\"3\">\n                                                <GridPane.margin>\n                                                    <Insets left=\"5.0\" right=\"5.0\" />\n                                                </GridPane.margin>\n                                       <HBox.margin>\n                                          <Insets right=\"5.0\" />\n                                       </HBox.margin>\n                                            </TextField>\n                                 </children>\n                                 <GridPane.margin>\n                                    <Insets left=\"5.0\" />\n                                 </GridPane.margin>\n                              </HBox>\n                                      <Label text=\"项目所在目录\" GridPane.rowIndex=\"3\" />\n                                      <HBox alignment=\"CENTER_LEFT\" prefHeight=\"100.0\" prefWidth=\"200.0\" GridPane.columnIndex=\"1\" GridPane.columnSpan=\"4\" GridPane.rowIndex=\"3\">\n                                          <children>\n                                              <TextField fx:id=\"projectFolderField\" prefHeight=\"27.0\" prefWidth=\"463.0\" promptText=\"D:\\workspace\\example\">\n                                                  <HBox.margin>\n                                                      <Insets left=\"5.0\" right=\"5.0\" />\n                                                  </HBox.margin>\n                                              </TextField>\n                                              <Button mnemonicParsing=\"false\" onAction=\"#chooseProjectFolder\" text=\"选择\">\n                                       <styleClass>\n                                          <String fx:value=\"btn\" />\n                                          <String fx:value=\"btn-default\" />\n                                       </styleClass></Button>\n                                          </children>\n                                      </HBox>\n                                      <Label text=\"实体类名包名\" GridPane.rowIndex=\"4\" />\n                                        <TextField fx:id=\"modelTargetPackage\" prefHeight=\"27.0\" prefWidth=\"152.0\" promptText=\"com.example.model\" GridPane.columnIndex=\"1\" GridPane.rowIndex=\"4\">\n                                            <HBox.margin>\n                                                <Insets right=\"5.0\" />\n                                            </HBox.margin>\n                                 <GridPane.margin>\n                                    <Insets left=\"5.0\" right=\"5.0\" />\n                                 </GridPane.margin>\n                                        </TextField>\n                                      <Label text=\"存放目录\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"4\" />\n                                      <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=\"4\">\n                                 <GridPane.margin>\n                                    <Insets left=\"5.0\" />\n                                 </GridPane.margin></TextField>\n                                      <Label text=\"Mapper接口包名\" GridPane.rowIndex=\"5\" />\n                                        <TextField fx:id=\"daoTargetPackage\" prefHeight=\"27.0\" prefWidth=\"248.0\" promptText=\"com.example.mapper\" GridPane.columnIndex=\"1\" GridPane.rowIndex=\"5\">\n                                            <HBox.margin>\n                                                <Insets right=\"5.0\" />\n                                            </HBox.margin>\n                                 <GridPane.margin>\n                                    <Insets left=\"5.0\" right=\"5.0\" />\n                                 </GridPane.margin>\n                                        </TextField>\n                                      <Label text=\"存放目录\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"5\" />\n                                      <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=\"5\">\n                                 <GridPane.margin>\n                                    <Insets left=\"5.0\" />\n                                 </GridPane.margin></TextField>\n                                      <Label prefHeight=\"27.0\" prefWidth=\"99.0\" text=\"映射XML文件包名\" GridPane.rowIndex=\"7\" />\n                                        <TextField fx:id=\"mapperTargetPackage\" prefHeight=\"27.0\" prefWidth=\"248.0\" promptText=\"com.example\" GridPane.columnIndex=\"1\" GridPane.rowIndex=\"7\">\n                                            <HBox.margin>\n                                                <Insets right=\"5.0\" />\n                                            </HBox.margin>\n                                 <GridPane.margin>\n                                    <Insets left=\"5.0\" right=\"5.0\" />\n                                 </GridPane.margin>\n                                        </TextField>\n                                      <Label text=\"存放目录\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"7\" />\n                                      <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=\"7\">\n                                 <GridPane.margin>\n                                    <Insets left=\"5.0\" />\n                                 </GridPane.margin></TextField>\n                              <VBox prefHeight=\"53.0\" prefWidth=\"536.0\" spacing=\"10.0\" GridPane.columnIndex=\"1\" GridPane.columnSpan=\"4\" GridPane.rowIndex=\"9\">\n                                 <children>\n                                    <HBox alignment=\"CENTER_LEFT\">\n                                       <children>\n                                           <Label text=\"生成文件的编码\" />\n                                           <ChoiceBox fx:id=\"encodingChoice\" prefHeight=\"23.0\" prefWidth=\"71.0\">\n                                               <items>\n                                                   <FXCollections fx:factory=\"observableArrayList\">\n                                                       <String fx:value=\"UTF-8\" />\n                                                   </FXCollections>\n                                               </items>\n                                           </ChoiceBox>\n                                       </children>\n                                    </HBox>\n                                    <HBox alignment=\"CENTER_LEFT\" spacing=\"10.0\" GridPane.columnIndex=\"1\" GridPane.columnSpan=\"3\" GridPane.rowIndex=\"8\">\n                                       <children>\n                                           <CheckBox fx:id=\"useExample\" minWidth=\"100.0\" mnemonicParsing=\"false\" text=\"使用Example\" />\n                                          <CheckBox fx:id=\"offsetLimitCheckBox\" disable=\"true\" minWidth=\"100.0\" mnemonicParsing=\"false\" selected=\"true\" text=\"分页插件(暂时只支持MySQL和PostgreSQL)\" GridPane.columnIndex=\"1\" GridPane.rowIndex=\"8\" />\n                                       </children>\n                                    </HBox>\n                                    <HBox prefHeight=\"100.0\" prefWidth=\"200.0\" spacing=\"18.0\">\n                                       <children>\n                                          <CheckBox fx:id=\"commentCheckBox\" mnemonicParsing=\"false\" selected=\"true\" text=\"生成实体域注释(来自表注释)\" />\n                                          <CheckBox fx:id=\"overrideXML\" mnemonicParsing=\"false\" selected=\"true\" text=\"覆盖原XML\" />\n                                       </children>\n                                    </HBox>\n                                    <HBox spacing=\"18.0\">\n                                       <children>\n                                          <CheckBox fx:id=\"useLombokPlugin\" mnemonicParsing=\"false\" text=\"LombokPlugin\" />\n                                          <CheckBox fx:id=\"needToStringHashcodeEquals\" mnemonicParsing=\"false\" selected=\"true\" text=\"生成toString/hashCode/equals方法\" />\n                                          <CheckBox fx:id=\"useSchemaPrefix\" mnemonicParsing=\"false\" text=\"使用Schema前缀\" />\n                                       </children>\n                                    </HBox>\n                                     <HBox prefHeight=\"100.0\" prefWidth=\"200.0\" spacing=\"18.0\">\n                                         <children>\n                                             <CheckBox fx:id=\"forUpdateCheckBox\" mnemonicParsing=\"false\" selected=\"false\" text=\"select 增加ForUpdate\" />\n                                             <CheckBox fx:id=\"annotationDAOCheckBox\" mnemonicParsing=\"false\" selected=\"true\" text=\"DAO使用 @Repository 注解\" />\n                                         </children>\n                                     </HBox>\n                                     <HBox prefHeight=\"100.0\" prefWidth=\"200.0\">\n                                         <children>\n                                             <CheckBox fx:id=\"useDAOExtendStyle\" mnemonicParsing=\"false\" selected=\"true\" text=\"DAO方法抽出到公共父接口\">\n                                             <HBox.margin>\n                                                <Insets right=\"10.0\" />\n                                             </HBox.margin></CheckBox>\n                                             <CheckBox fx:id=\"jsr310Support\" mnemonicParsing=\"false\" prefHeight=\"16.0\" prefWidth=\"252.0\" text=\"JSR310: Date and Time API\" />\n                                         </children>\n                                     </HBox>\n                                    <HBox spacing=\"18.0\">\n                                       <children>\n                                          <CheckBox fx:id=\"annotationCheckBox\" mnemonicParsing=\"false\" selected=\"false\" text=\"生成JPA注解\" />\n                                          <CheckBox fx:id=\"useActualColumnNamesCheckbox\" mnemonicParsing=\"false\" selected=\"false\" text=\"使用实际的列名\" />\n                                           <CheckBox fx:id=\"useTableNameAliasCheckbox\" mnemonicParsing=\"false\" selected=\"false\" text=\"启用as别名查询\" />\n                                       </children>\n                                    </HBox>\n                                     <HBox prefHeight=\"100.0\" prefWidth=\"200.0\" />\n                                 </children>\n                                 <padding>\n                                    <Insets left=\"5.0\" />\n                                 </padding>\n                              </VBox>\n                              <HBox alignment=\"CENTER_LEFT\" prefHeight=\"100.0\" prefWidth=\"200.0\" spacing=\"10.0\" GridPane.columnIndex=\"1\" GridPane.columnSpan=\"3\" GridPane.rowIndex=\"10\">\n                                 <children>\n                                    <Button mnemonicParsing=\"false\" onAction=\"#generateCode\" text=\"代码生成\">\n                                       <styleClass>\n                                          <String fx:value=\"btn-success\" />\n                                          <String fx:value=\"btn\" />\n                                       </styleClass>\n                                    </Button>\n                                    <Button mnemonicParsing=\"false\" onAction=\"#saveGeneratorConfig\" text=\"保存配置\">\n                                       <styleClass>\n                                          <String fx:value=\"btn\" />\n                                          <String fx:value=\"btn-default\" />\n                                       </styleClass>\n                                    </Button>\n                                     <Button mnemonicParsing=\"false\" onAction=\"#openTargetFolder\" text=\"打开生成文件夹\">\n                                         <styleClass>\n                                             <String fx:value=\"btn\" />\n                                             <String fx:value=\"btn-default\" />\n                                         </styleClass>\n                                     </Button>\n                                 </children>\n                              </HBox>\n                              <Label text=\"自定义接口名称(选填)\" GridPane.rowIndex=\"6\">\n                                 <padding>\n                                    <Insets left=\"5.0\" />\n                                 </padding>\n                              </Label>\n                              <TextField fx:id=\"mapperName\" prefHeight=\"27.0\" prefWidth=\"532.0\" promptText=\"PersonDAO\" GridPane.columnIndex=\"1\" GridPane.columnSpan=\"4\" GridPane.rowIndex=\"6\">\n                                 <GridPane.margin>\n                                    <Insets left=\"5.0\" />\n                                 </GridPane.margin>\n                              </TextField>\n                                  </children>\n                              </GridPane>\n                     </children>\n                     <padding>\n                        <Insets bottom=\"5.0\" left=\"5.0\" right=\"5.0\" top=\"5.0\" />\n                     </padding>\n                  </VBox>\n               </children>\n            </AnchorPane>\n            </items>\n        </SplitPane>\n    </center>\n</BorderPane>\n"
  },
  {
    "path": "src/main/resources/fxml/basicConnection.fxml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<?import java.lang.String?>\n<?import javafx.collections.FXCollections?>\n<?import javafx.scene.control.CheckBox?>\n<?import javafx.scene.control.ChoiceBox?>\n<?import javafx.scene.control.Label?>\n<?import javafx.scene.control.PasswordField?>\n<?import javafx.scene.control.TextField?>\n<?import javafx.scene.layout.AnchorPane?>\n<?import javafx.scene.layout.ColumnConstraints?>\n<?import javafx.scene.layout.GridPane?>\n<?import javafx.scene.layout.HBox?>\n<?import javafx.scene.layout.RowConstraints?>\n\n<AnchorPane prefHeight=\"350.0\" prefWidth=\"769.0\" stylesheets=\"@../style.css\" xmlns=\"http://javafx.com/javafx/8.0.121\" xmlns:fx=\"http://javafx.com/fxml/1\" fx:controller=\"com.zzg.mybatis.generator.controller.DbConnectionController\">\n\n  <GridPane alignment=\"CENTER_RIGHT\" prefHeight=\"350.0\" prefWidth=\"769.0\" AnchorPane.bottomAnchor=\"20.0\" AnchorPane.leftAnchor=\"0.0\" AnchorPane.rightAnchor=\"0.0\" AnchorPane.topAnchor=\"20.0\">\n    <columnConstraints>\n      <ColumnConstraints halignment=\"RIGHT\" hgrow=\"SOMETIMES\" maxWidth=\"273.0\" minWidth=\"10.0\" prefWidth=\"180.0\" />\n      <ColumnConstraints halignment=\"RIGHT\" hgrow=\"SOMETIMES\" maxWidth=\"273.0\" minWidth=\"10.0\" prefWidth=\"38.0\" />\n      <ColumnConstraints hgrow=\"SOMETIMES\" maxWidth=\"482.0\" minWidth=\"10.0\" prefWidth=\"439.0\" />\n      <ColumnConstraints hgrow=\"SOMETIMES\" maxWidth=\"482.0\" minWidth=\"10.0\" prefWidth=\"112.0\" />\n    </columnConstraints>\n    <children>\n      <Label text=\"保存名称\" />\n      <TextField fx:id=\"nameField\" prefHeight=\"23.0\" prefWidth=\"383.0\" GridPane.columnIndex=\"2\" />\n      <Label text=\"数据库类型\" GridPane.rowIndex=\"1\" />\n      <ChoiceBox fx:id=\"dbTypeChoice\" prefWidth=\"150.0\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"1\">\n        <items>\n          <FXCollections fx:factory=\"observableArrayList\">\n            <String fx:value=\"MySQL\" />\n            <String fx:value=\"MySQL_8\" />\n            <String fx:value=\"Oracle\" />\n            <String fx:value=\"PostgreSQL\" />\n            <String fx:value=\"SQL_Server\" />\n            <String fx:value=\"Sqlite\" />\n          </FXCollections>\n        </items>\n      </ChoiceBox>\n      <Label text=\"主机名或IP地址\" GridPane.rowIndex=\"2\" />\n      <TextField fx:id=\"hostField\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"2\" />\n      <Label text=\"端口号\" GridPane.rowIndex=\"3\" />\n      <TextField fx:id=\"portField\" maxWidth=\"-Infinity\" prefHeight=\"27.0\" prefWidth=\"103.0\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"3\" />\n      <Label text=\"用户名\" GridPane.rowIndex=\"4\" />\n      <TextField fx:id=\"userNameField\" minWidth=\"-Infinity\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"4\" />\n      <Label text=\"密码\" GridPane.rowIndex=\"5\" />\n      <HBox alignment=\"CENTER_LEFT\" prefHeight=\"100.0\" prefWidth=\"200.0\" spacing=\"10.0\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"5\">\n        <children>\n          <PasswordField fx:id=\"passwordField\" />\n          <CheckBox fx:id=\"savePwdCheckBox\" mnemonicParsing=\"false\" text=\"Save password\" visible=\"false\" />\n        </children>\n      </HBox>\n      <Label text=\"编码\" GridPane.rowIndex=\"7\" />\n      <TextField fx:id=\"schemaField\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"6\" />\n      <ChoiceBox fx:id=\"encodingChoice\" maxWidth=\"1.7976931348623157E308\" prefHeight=\"26.0\" prefWidth=\"404.0\" GridPane.columnIndex=\"2\" GridPane.hgrow=\"ALWAYS\" GridPane.rowIndex=\"7\">\n        <items>\n          <FXCollections fx:factory=\"observableArrayList\">\n            <String fx:value=\"utf8\" />\n            <String fx:value=\"gb2312\" />\n            <String fx:value=\"gbk\" />\n          </FXCollections>\n        </items>\n      </ChoiceBox>\n      <Label text=\"Schema/数据库\" GridPane.rowIndex=\"6\" />\n    </children>\n    <rowConstraints>\n      <RowConstraints minHeight=\"17.0\" prefHeight=\"34.0\" />\n      <RowConstraints maxHeight=\"47.0\" minHeight=\"3.0\" prefHeight=\"30.0\" />\n      <RowConstraints maxHeight=\"39.0\" minHeight=\"5.0\" prefHeight=\"39.0\" />\n      <RowConstraints maxHeight=\"40.0\" minHeight=\"7.0\" prefHeight=\"37.0\" />\n      <RowConstraints maxHeight=\"65.0\" minHeight=\"19.0\" prefHeight=\"38.0\" />\n      <RowConstraints maxHeight=\"95.0\" minHeight=\"30.0\" prefHeight=\"30.0\" />\n      <RowConstraints maxHeight=\"34.0\" minHeight=\"28.0\" prefHeight=\"34.0\" />\n      <RowConstraints />\n    </rowConstraints>\n  </GridPane>\n\n</AnchorPane>\n"
  },
  {
    "path": "src/main/resources/fxml/generatorConfigs.fxml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<?import javafx.scene.control.TableColumn?>\n<?import javafx.scene.control.TableView?>\n<?import javafx.scene.layout.*?>\n<AnchorPane maxHeight=\"-Infinity\" maxWidth=\"-Infinity\" minHeight=\"-Infinity\" minWidth=\"-Infinity\" prefHeight=\"400.0\" prefWidth=\"600.0\" xmlns=\"http://javafx.com/javafx/8\" xmlns:fx=\"http://javafx.com/fxml/1\" fx:controller=\"com.zzg.mybatis.generator.controller.GeneratorConfigController\">\n   <children>\n      <TableView fx:id=\"configTable\" layoutX=\"47.0\" layoutY=\"53.0\" prefHeight=\"200.0\" prefWidth=\"200.0\" AnchorPane.bottomAnchor=\"0.0\" AnchorPane.leftAnchor=\"0.0\" AnchorPane.rightAnchor=\"0.0\" AnchorPane.topAnchor=\"0.0\">\n        <columns>\n          <TableColumn fx:id=\"nameColumn\" prefWidth=\"75.0\" text=\"配置名称\" />\n          <TableColumn fx:id=\"opsColumn\" editable=\"false\" prefWidth=\"75.0\" sortable=\"false\" text=\"操作\" />\n        </columns>\n         <columnResizePolicy>\n            <TableView fx:constant=\"CONSTRAINED_RESIZE_POLICY\" />\n         </columnResizePolicy>\n      </TableView>\n   </children>\n</AnchorPane>\n"
  },
  {
    "path": "src/main/resources/fxml/newConnection.fxml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<?import java.lang.*?>\n<?import javafx.scene.control.*?>\n<?import javafx.scene.layout.*?>\n<?import java.lang.String?>\n<?import javafx.scene.control.Button?>\n<?import javafx.scene.control.Tab?>\n<?import javafx.scene.control.TabPane?>\n<?import javafx.scene.layout.AnchorPane?>\n<?import javafx.scene.layout.ColumnConstraints?>\n<?import javafx.scene.layout.GridPane?>\n<?import javafx.scene.layout.RowConstraints?>\n\n<GridPane alignment=\"center\" hgap=\"10\" stylesheets=\"@../style.css\" vgap=\"0\" xmlns=\"http://javafx.com/javafx/8\" xmlns:fx=\"http://javafx.com/fxml/1\" fx:controller=\"com.zzg.mybatis.generator.controller.TabPaneController\">\n\n  <columnConstraints>\n    <ColumnConstraints />\n  </columnConstraints>\n  <rowConstraints>\n    <RowConstraints maxHeight=\"697.0\" minHeight=\"170.0\" />\n    <RowConstraints maxHeight=\"422.0\" minHeight=\"45.0\" />\n  </rowConstraints>\n  <children>\n    <TabPane fx:id=\"tabPane\" prefHeight=\"390.0\" prefWidth=\"769.0\" tabClosingPolicy=\"UNAVAILABLE\">\n      <tabs>\n        <Tab text=\"TCP/IP\">\n          <content>\n            <fx:include fx:id=\"tabControlA\" source=\"basicConnection.fxml\" />\n          </content>\n        </Tab>\n        <Tab text=\"SSH\">\n          <content>\n            <fx:include fx:id=\"tabControlB\" source=\"sshBasedConnection.fxml\" />\n          </content>\n        </Tab>\n      </tabs>\n    </TabPane>\n    <AnchorPane style=\"-fx-background-color: lightGrey;\" GridPane.rowIndex=\"1\">\n      <children>\n        <Button layoutX=\"27.0\" mnemonicParsing=\"false\" onAction=\"#testConnection\" text=\"测试连接\" AnchorPane.bottomAnchor=\"15.0\" AnchorPane.leftAnchor=\"15.0\" AnchorPane.topAnchor=\"15.0\">\n          <styleClass>\n            <String fx:value=\"btn\" />\n            <String fx:value=\"btn-default\" />\n          </styleClass>\n        </Button>\n        <Button layoutX=\"615.0\" mnemonicParsing=\"false\" onAction=\"#cancel\" style=\"-fx-border-color: transparent;\" text=\"取消\" AnchorPane.bottomAnchor=\"15.0\" AnchorPane.topAnchor=\"15.0\">\n          <styleClass>\n            <String fx:value=\"btn\" />\n            <String fx:value=\"btn-default\" />\n          </styleClass>\n        </Button>\n        <Button layoutX=\"687.0\" mnemonicParsing=\"false\" onAction=\"#saveConnection\" text=\"保存\" textFill=\"WHITE\" AnchorPane.bottomAnchor=\"15.0\" AnchorPane.rightAnchor=\"15.0\">\n          <styleClass>\n            <String fx:value=\"btn-success\" />\n            <String fx:value=\"btn\" />\n          </styleClass>\n        </Button>\n\n      </children>\n    </AnchorPane>\n  </children>\n</GridPane>\n"
  },
  {
    "path": "src/main/resources/fxml/selectTableColumn.fxml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<?import javafx.scene.control.Button?>\n<?import javafx.scene.control.TableColumn?>\n<?import javafx.scene.control.TableView?>\n<?import javafx.scene.layout.AnchorPane?>\n<?import javafx.scene.text.Text?>\n\n<AnchorPane maxHeight=\"-Infinity\" maxWidth=\"-Infinity\" minHeight=\"-Infinity\" minWidth=\"-Infinity\" prefHeight=\"526.0\" prefWidth=\"730.0\" xmlns=\"http://javafx.com/javafx/16\" xmlns:fx=\"http://javafx.com/fxml/1\" fx:controller=\"com.zzg.mybatis.generator.controller.SelectTableColumnController\">\n   <children>\n      <TableView fx:id=\"columnListView\" editable=\"true\" layoutY=\"123.0\" prefHeight=\"353.0\" prefWidth=\"730.0\" AnchorPane.bottomAnchor=\"50.0\" AnchorPane.leftAnchor=\"0.0\" AnchorPane.rightAnchor=\"0.0\" AnchorPane.topAnchor=\"100.0\">\n        <columns>\n          <TableColumn fx:id=\"checkedColumn\" prefWidth=\"75.0\" text=\"Checked\" />\n          <TableColumn fx:id=\"columnNameColumn\" prefWidth=\"132.0\" text=\"Column Name\" />\n            <TableColumn fx:id=\"jdbcTypeColumn\" prefWidth=\"122.0\" text=\"JDBC Type\" />\n            <TableColumn fx:id=\"javaTypeColumn\" prefWidth=\"121.0\" text=\"Java Type\" />\n            <TableColumn fx:id=\"propertyNameColumn\" prefWidth=\"104.0\" text=\"Property Name\" />\n            <TableColumn fx:id=\"typeHandlerColumn\" prefWidth=\"136.0\" text=\"Type Handler\" />\n        </columns>\n         <columnResizePolicy>\n            <TableView fx:constant=\"CONSTRAINED_RESIZE_POLICY\" />\n         </columnResizePolicy>\n      </TableView>\n      <Button focusTraversable=\"false\" layoutX=\"642.0\" layoutY=\"453.0\" mnemonicParsing=\"false\" onAction=\"#ok\" prefHeight=\"27.0\" prefWidth=\"59.0\" text=\"确认\" AnchorPane.bottomAnchor=\"13.0\" AnchorPane.rightAnchor=\"29.0\" />\n      <Button focusTraversable=\"false\" layoutX=\"556.0\" layoutY=\"486.0\" mnemonicParsing=\"false\" onAction=\"#cancel\" text=\"取消\" AnchorPane.bottomAnchor=\"13.0\" AnchorPane.rightAnchor=\"113.0\" />\n      <Text layoutX=\"12.0\" layoutY=\"62.0\" lineSpacing=\"5.0\" strokeType=\"OUTSIDE\" strokeWidth=\"0.0\" text=\"2. 如果要定制列的Java数据类型, 编辑Java Type和Property Name或者你自己的Type Handler, 注意要按Enter键保存，然后再点击确认方可生效。\" wrappingWidth=\"706.0\" />\n      <Text layoutX=\"14.0\" layoutY=\"35.0\" strokeType=\"OUTSIDE\" strokeWidth=\"0.0\" text=\"1. 如果不想生成某列请取消勾选对应的列\" />\n      <Button focusTraversable=\"false\" layoutX=\"14.0\" layoutY=\"489.0\" mnemonicParsing=\"false\" onAction=\"#configAction\" text=\"属性配置\" />\n   </children>\n</AnchorPane>\n"
  },
  {
    "path": "src/main/resources/fxml/sshBasedConnection.fxml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<?import java.lang.*?>\n<?import javafx.collections.*?>\n<?import javafx.geometry.*?>\n<?import javafx.scene.control.*?>\n<?import javafx.scene.layout.*?>\n\n<AnchorPane stylesheets=\"@../style.css\" xmlns=\"http://javafx.com/javafx/10.0.2-internal\" xmlns:fx=\"http://javafx.com/fxml/1\" fx:controller=\"com.zzg.mybatis.generator.controller.OverSshController\">\n  <children>\n    <GridPane fx:id=\"gridPane\" alignment=\"CENTER\" nodeOrientation=\"LEFT_TO_RIGHT\" AnchorPane.topAnchor=\"15.0\">\n      <columnConstraints>\n        <ColumnConstraints hgrow=\"SOMETIMES\" maxWidth=\"340.0\" minWidth=\"19.0\" prefWidth=\"194.0\" />\n        <ColumnConstraints maxWidth=\"302.0\" minWidth=\"29.0\" prefWidth=\"36.0\" />\n        <ColumnConstraints maxWidth=\"577.0\" minWidth=\"128.0\" prefWidth=\"406.0\" />\n        <ColumnConstraints maxWidth=\"446.0\" minWidth=\"113.0\" prefWidth=\"133.0\" />\n            <ColumnConstraints />\n            <ColumnConstraints />\n      </columnConstraints>\n      <rowConstraints>\n        <RowConstraints minHeight=\"35.0\" />\n        <RowConstraints minHeight=\"35.0\" />\n        <RowConstraints minHeight=\"35.0\" />\n        <RowConstraints minHeight=\"35.0\" />\n        <RowConstraints minHeight=\"35.0\" />\n        <RowConstraints minHeight=\"35.0\" />\n        <RowConstraints minHeight=\"35.0\" />\n        <RowConstraints minHeight=\"35.0\" />\n        <RowConstraints minHeight=\"35.0\" />\n        <RowConstraints minHeight=\"35.0\" />\n        <RowConstraints minHeight=\"35.0\" />\n        <RowConstraints minHeight=\"35.0\" />\n        <RowConstraints minHeight=\"35.0\" />\n        <RowConstraints minHeight=\"35.0\" />\n        <RowConstraints minHeight=\"35.0\" />\n        <RowConstraints minHeight=\"35.0\" />\n        <RowConstraints minHeight=\"35.0\" />\n            <RowConstraints />\n      </rowConstraints>\n      <children>\n        <Label text=\"保存名称\" GridPane.halignment=\"RIGHT\" GridPane.rowIndex=\"0\" />\n        <TextField fx:id=\"nameField\" prefHeight=\"23.0\" prefWidth=\"373.0\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"0\" />\n\n        <Label text=\"数据库类型\" GridPane.halignment=\"RIGHT\" GridPane.rowIndex=\"1\" />\n        <ChoiceBox fx:id=\"dbTypeChoice\" prefWidth=\"150.0\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"1\">\n          <items>\n            <FXCollections fx:factory=\"observableArrayList\">\n              <String fx:value=\"MySQL\" />\n              <String fx:value=\"MySQL_8\" />\n              <String fx:value=\"Oracle\" />\n              <String fx:value=\"PostgreSQL\" />\n              <String fx:value=\"SQL_Server\" />\n              <String fx:value=\"Sqlite\" />\n            </FXCollections>\n          </items>\n        </ChoiceBox>\n        <Label text=\"主机名或IP地址\" GridPane.halignment=\"RIGHT\" GridPane.rowIndex=\"2\" />\n        <TextField fx:id=\"hostField\" prefWidth=\"376.0\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"2\" />\n        <Label text=\"端口号\" GridPane.halignment=\"RIGHT\" GridPane.rowIndex=\"3\" />\n        <TextField fx:id=\"portField\" maxWidth=\"-Infinity\" prefHeight=\"18.0\" prefWidth=\"50.0\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"3\" />\n        <Label text=\"用户名\" GridPane.halignment=\"RIGHT\" GridPane.rowIndex=\"4\" />\n        <TextField fx:id=\"userNameField\" minWidth=\"-Infinity\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"4\" />\n        <Label text=\"密码\" GridPane.halignment=\"RIGHT\" GridPane.rowIndex=\"5\" />\n        <HBox alignment=\"CENTER_LEFT\" prefWidth=\"200.0\" spacing=\"10.0\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"5\">\n          <children>\n            <PasswordField fx:id=\"passwordField\" />\n            <CheckBox fx:id=\"savePwdCheckBox\" mnemonicParsing=\"false\" text=\"Save password\" visible=\"false\" />\n          </children>\n        </HBox>\n\n        <Label text=\"Schema/数据库\" GridPane.halignment=\"RIGHT\" GridPane.rowIndex=\"6\" />\n        <TextField fx:id=\"schemaField\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"6\" />\n\n        <Label text=\"编码\" GridPane.halignment=\"RIGHT\" GridPane.rowIndex=\"7\" />\n        <ChoiceBox fx:id=\"encodingChoice\" maxWidth=\"1.7976931348623157E308\" prefWidth=\"150.0\" GridPane.columnIndex=\"2\" GridPane.hgrow=\"ALWAYS\" GridPane.rowIndex=\"7\">\n          <items>\n            <FXCollections fx:factory=\"observableArrayList\">\n              <String fx:value=\"utf8\" />\n              <String fx:value=\"gb2312\" />\n              <String fx:value=\"gbk\" />\n            </FXCollections>\n          </items>\n        </ChoiceBox>\n\n        <Label alignment=\"CENTER_RIGHT\" contentDisplay=\"RIGHT\" text=\"SSH主机名\" GridPane.halignment=\"RIGHT\" GridPane.rowIndex=\"8\" />\n        <TextField fx:id=\"sshHostField\" maxWidth=\"200.0\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"8\" />\n\n        <Label alignment=\"CENTER_RIGHT\" text=\"SSH端口\" textAlignment=\"RIGHT\" GridPane.halignment=\"RIGHT\" GridPane.rowIndex=\"9\" />\n        <TextField fx:id=\"sshdPortField\" maxWidth=\"50.0\" minWidth=\"50.0\" prefWidth=\"50.0\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"9\" />\n\n        <Label text=\"本机端口\" GridPane.halignment=\"RIGHT\" GridPane.rowIndex=\"10\" />\n        <TextField fx:id=\"lportField\" maxWidth=\"50.0\" minWidth=\"50.0\" prefWidth=\"50.0\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"10\" />\n\n        <Label alignment=\"CENTER_RIGHT\" contentDisplay=\"RIGHT\" text=\"目标端口\" textAlignment=\"RIGHT\" GridPane.halignment=\"RIGHT\" GridPane.rowIndex=\"11\" />\n        <TextField fx:id=\"rportField\" maxWidth=\"50.0\" minWidth=\"50.0\" prefWidth=\"50.0\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"11\" />\n\n        <Label text=\"SSH用户名\" GridPane.halignment=\"RIGHT\" GridPane.rowIndex=\"12\" />\n        <TextField fx:id=\"sshUserField\" maxWidth=\"200.0\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"12\" />\n\n        <Label text=\"认证方式\" GridPane.halignment=\"RIGHT\" GridPane.rowIndex=\"13\" />\n        <ChoiceBox fx:id=\"authTypeChoice\" prefWidth=\"150.0\" value=\"Password\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"13\">\n          <items>\n            <FXCollections fx:factory=\"observableArrayList\">\n              <String fx:value=\"Password\" />\n              <String fx:value=\"PubKey\" />\n            </FXCollections>\n          </items>\n        </ChoiceBox>\n\n        <Label fx:id=\"sshPasswordLabel\" text=\"SSH密码\" GridPane.halignment=\"RIGHT\" GridPane.rowIndex=\"14\" />\n        <PasswordField fx:id=\"sshPasswordField\" maxWidth=\"200.0\" prefHeight=\"15.0\" prefWidth=\"200.0\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"14\" />\n\n        <Label fx:id=\"pubkeyBoxLabel\" text=\"私钥路径\" visible=\"false\" GridPane.halignment=\"RIGHT\" GridPane.rowIndex=\"14\" />\n        <HBox fx:id=\"pubkeyBox\" alignment=\"BASELINE_LEFT\" visible=\"false\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"14\">\n          <TextField fx:id=\"sshPubKeyField\" maxWidth=\"327.0\" prefHeight=\"23.0\" prefWidth=\"327.0\" />\n          <Button layoutY=\"2.0\" mnemonicParsing=\"false\" onAction=\"#choosePubKey\" text=\"选择文件\">\n            <styleClass>\n              <String fx:value=\"btn\" />\n              <String fx:value=\"btn-default\" />\n            </styleClass>\n          </Button>\n        </HBox>\n        <Label fx:id=\"sshPubkeyPasswordLabel\" text=\"私钥密码\" visible=\"false\" GridPane.columnIndex=\"0\" GridPane.halignment=\"RIGHT\" GridPane.rowIndex=\"15\" />\n        <PasswordField fx:id=\"sshPubkeyPasswordField\" maxWidth=\"200.0\" prefHeight=\"15.0\" prefWidth=\"200.0\" visible=\"false\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"15\" />\n        <Label fx:id=\"sshPubkeyPasswordNote\" visible=\"false\" prefHeight=\"15.0\" prefWidth=\"121.0\" text=\"私钥没有密码则留空\" textFill=\"#31b3b5\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"15\">\n          <GridPane.margin>\n            <Insets left=\"250.0\" />\n          </GridPane.margin>\n        </Label>\n\n        <AnchorPane prefHeight=\"40.0\" prefWidth=\"539.0\" GridPane.columnIndex=\"2\" GridPane.columnSpan=\"2\" GridPane.rowIndex=\"16\">\n          <children>\n            <Button layoutY=\"2.0\" mnemonicParsing=\"false\" onAction=\"#testSSH\" text=\"测试SSH连接\">\n              <styleClass>\n                <String fx:value=\"btn\" />\n                <String fx:value=\"btn-default\" />\n              </styleClass>\n            </Button>\n            <Button layoutX=\"122.0\" layoutY=\"2.0\" mnemonicParsing=\"false\" onAction=\"#reset\" text=\"重置SSH设置\">\n              <styleClass>\n                <String fx:value=\"btn\" />\n                <String fx:value=\"btn-default\" />\n              </styleClass>\n            </Button>\n          </children>\n        </AnchorPane>\n        <Label fx:id=\"note\" alignment=\"CENTER\" contentDisplay=\"CENTER\" onMouseEntered=\"#checkInput\" prefHeight=\"35.0\" prefWidth=\"769.0\" textAlignment=\"CENTER\" textFill=\"#ff666f\" GridPane.columnIndex=\"0\" GridPane.columnSpan=\"4\" GridPane.rowIndex=\"17\" />\n\n        <Label fx:id=\"lPortLabel\" text=\"注意不要填写被其他程序占用的端口\" textFill=\"#31b3b5\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"10\">\n           <GridPane.margin>\n              <Insets left=\"100.0\" />\n           </GridPane.margin>\n        </Label>\n        <Label text=\"目标端口可以和数据库的端口一致\" textFill=\"#1daeae\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"11\">\n           <GridPane.margin>\n              <Insets left=\"100.0\" />\n           </GridPane.margin>\n        </Label>\n        <Label prefHeight=\"15.0\" prefWidth=\"121.0\" text=\"SSH端口默认是22\" textFill=\"#31b3b5\" GridPane.columnIndex=\"2\" GridPane.rowIndex=\"9\">\n           <GridPane.margin>\n              <Insets left=\"100.0\" />\n           </GridPane.margin>\n        </Label>\n\n      </children>\n    </GridPane>\n  </children>\n</AnchorPane>\n"
  },
  {
    "path": "src/main/resources/fxml/tableColumnConfigs.fxml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<?import java.lang.String?>\n<?import javafx.geometry.Insets?>\n<?import javafx.scene.control.Button?>\n<?import javafx.scene.control.Label?>\n<?import javafx.scene.control.TextField?>\n<?import javafx.scene.layout.AnchorPane?>\n<?import javafx.scene.layout.ColumnConstraints?>\n<?import javafx.scene.layout.GridPane?>\n<?import javafx.scene.layout.RowConstraints?>\n<?import javafx.scene.layout.VBox?>\n\n\n<AnchorPane maxHeight=\"-Infinity\" maxWidth=\"-Infinity\" minHeight=\"-Infinity\" minWidth=\"-Infinity\" prefHeight=\"205.0\" prefWidth=\"538.0\" xmlns=\"http://javafx.com/javafx/16\" xmlns:fx=\"http://javafx.com/fxml/1\" fx:controller=\"com.zzg.mybatis.generator.controller.TableColumnConfigsController\">\n   <children>\n      <VBox prefHeight=\"64.0\" prefWidth=\"538.0\" AnchorPane.leftAnchor=\"5.0\" AnchorPane.rightAnchor=\"5.0\" AnchorPane.topAnchor=\"5.0\">\n         <children>\n            <GridPane alignment=\"TOP_RIGHT\" vgap=\"5.0\">\n              <columnConstraints>\n                  <ColumnConstraints hgrow=\"SOMETIMES\" maxWidth=\"332.0\" minWidth=\"10.0\" prefWidth=\"302.0\" />\n                  <ColumnConstraints hgrow=\"SOMETIMES\" maxWidth=\"332.0\" minWidth=\"10.0\" prefWidth=\"235.0\" />\n                  <ColumnConstraints hgrow=\"SOMETIMES\" maxWidth=\"332.0\" minWidth=\"10.0\" prefWidth=\"235.0\" />\n              </columnConstraints>\n              <rowConstraints>\n                <RowConstraints />\n                <RowConstraints minHeight=\"10.0\" prefHeight=\"30.0\" vgrow=\"SOMETIMES\" />\n                <RowConstraints minHeight=\"10.0\" prefHeight=\"30.0\" vgrow=\"SOMETIMES\" />\n                  <RowConstraints minHeight=\"10.0\" prefHeight=\"30.0\" vgrow=\"SOMETIMES\" />\n              </rowConstraints>\n               <children>\n                  <Label alignment=\"TOP_RIGHT\" contentDisplay=\"RIGHT\" prefHeight=\"17.0\" prefWidth=\"202.0\" text=\"去除前缀(多种前缀使用|分割):\" textAlignment=\"RIGHT\" GridPane.rowIndex=\"2\">\n                     <GridPane.margin>\n                        <Insets top=\"5.0\" />\n                     </GridPane.margin>\n                  </Label>\n                  <TextField fx:id=\"columnNamePrefixTextLabel\" prefHeight=\"23.0\" prefWidth=\"213.0\" GridPane.columnIndex=\"1\" GridPane.rowIndex=\"2\">\n                     <GridPane.margin>\n                        <Insets top=\"5.0\" />\n                     </GridPane.margin>\n                  </TextField>\n                  <Label alignment=\"TOP_RIGHT\" contentDisplay=\"RIGHT\" prefHeight=\"17.0\" prefWidth=\"202.0\" text=\"当前表名称:\" textAlignment=\"RIGHT\" GridPane.rowIndex=\"1\">\n                     <GridPane.margin>\n                        <Insets bottom=\"10.0\" />\n                     </GridPane.margin>\n                  </Label>\n                  <Label fx:id=\"currentTableNameLabel\" alignment=\"TOP_LEFT\" contentDisplay=\"RIGHT\" prefHeight=\"17.0\" prefWidth=\"202.0\" textAlignment=\"CENTER\" GridPane.columnIndex=\"1\" GridPane.rowIndex=\"1\">\n                     <GridPane.margin>\n                        <Insets bottom=\"10.0\" />\n                     </GridPane.margin>\n                  </Label>\n               </children>\n               <VBox.margin>\n                  <Insets top=\"5.0\" />\n               </VBox.margin>\n            </GridPane>\n         </children>\n      </VBox>\n      <Button layoutX=\"476.0\" layoutY=\"169.0\" mnemonicParsing=\"false\" onAction=\"#confirm\" text=\"确认\">\n         <styleClass>\n            <String fx:value=\"btn\" />\n            <String fx:value=\"btn-default\" />\n         </styleClass>\n      </Button>\n      <Button layoutX=\"412.0\" layoutY=\"169.0\" mnemonicParsing=\"false\" onAction=\"#cancel\" text=\"取消\">\n         <styleClass>\n            <String fx:value=\"btn\" />\n            <String fx:value=\"btn-default\" />\n         </styleClass>\n      </Button>\n   </children>\n</AnchorPane>\n"
  },
  {
    "path": "src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<jmxConfigurator />\n\t<appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<encoder>\n\t\t\t<pattern>[%level] [%date{HH:mm:ss.SSS}] [%thread] [%mdc] %logger.%method:%line --> %message%n</pattern>\n\t\t</encoder>\n\t\t<filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\n\t\t\t<level>DEBUG</level>\n\t\t</filter>\n\t</appender>\n\n\t<appender name=\"FILE\"\n\t\tclass=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t<rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n\t\t\t<fileNamePattern>logs/mybatis-generator.%d{yyyy-MM-dd}.%i.log.zip\n\t\t\t</fileNamePattern>\n\t\t\t<maxHistory>7</maxHistory>\n\t\t\t<timeBasedFileNamingAndTriggeringPolicy\n\t\t\t\tclass=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n\t\t\t\t<maxFileSize>500MB</maxFileSize>\n\t\t\t</timeBasedFileNamingAndTriggeringPolicy>\n\t\t</rollingPolicy>\n\t\t<encoder>\n\t\t\t<pattern>[%level] [%date{HH:mm:ss.SSS}] [%thread] [%mdc] %logger.%method:%line --> %message%n</pattern>\n\t\t</encoder>\n\t\t<filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\n\t\t\t<level>DEBUG</level>\n\t\t</filter>\n\t</appender>\n\n\t<root level=\"DEBUG\">\n\t\t<appender-ref ref=\"CONSOLE\" />\n\t\t<appender-ref ref=\"FILE\" />\n\t</root>\n\n</configuration>"
  },
  {
    "path": "src/main/resources/style.css",
    "content": "* {\n\t-fx-font-size: 12px;\n}\n\n.button {\n\t-fx-font-size: 14px;\n}\n\n.tool-bar .button {\n    -fx-border-width: 0px;\n}\n\n.btn {\n    -fx-border-width: 1px;\n    -fx-border-color: transparent;\n    -fx-border-radius: 4px;\n}\n\n.btn-primary {\n\t-fx-background-color: #378bfa;\n\t-fx-text-fill: white;\n}\n\n.btn-primary:hover {\n\t-fx-background-color: #579efa;\n}\n\n.btn-default {\n    -fx-text-fill: #333;\n    -fx-background-color: #fff;\n    -fx-border-color: #ccc;\n}\n\n.btn-default:hover {\n    -fx-background-color: #e6e6e6;\n    -fx-border-color: #adadad;\n}\n\n.btn-success:hover {\n    -fx-text-fill: #fff;\n    -fx-background-color: #449d44;\n    -fx-border-color: #398439;\n}\n\n.btn-success {\n    -fx-text-fill: #fff;\n    -fx-background-color: #5cb85c;\n    -fx-border-color: #4cae4c;\n}\n\n.consoleTextArea {\n\t-fx-stroke: white;\n\t-fx-fill: black;\n\t-fx-background-color: black;\n}\n\n.consoleTextArea:focused {\n}"
  },
  {
    "path": "src/test/java/com/zzg/mybatis/generator/util/ConfigHelperTest.java",
    "content": "package com.zzg.mybatis.generator.util;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport java.util.List;\n\n/**\n * Created by zouzhigang on 2016/9/18.\n */\npublic class ConfigHelperTest {\n\n    @Test\n    public void testFindConnectorLibPath_Oracle() {\n        String path = ConfigHelper.findConnectorLibPath(\"Oracle\");\n        Assert.assertTrue(path.contains(\"ojdbc\"));\n    }\n\n    @Test\n    public void testFindConnectorLibPath_Mysql() {\n        String path = ConfigHelper.findConnectorLibPath(\"MySQL\");\n        Assert.assertTrue(path.contains(\"mysql-connector\"));\n    }\n\n    @Test\n    public void testFindConnectorLibPath_PostgreSQL() {\n        String path = ConfigHelper.findConnectorLibPath(\"PostgreSQL\");\n        Assert.assertTrue(path.contains(\"postgresql\"));\n    }\n\n    @Test\n\tpublic void testGetAllJDBCDriverJarPaths() {\n    \tList<String> jarFilePaths = ConfigHelper.getAllJDBCDriverJarPaths();\n    \tAssert.assertTrue(jarFilePaths != null && jarFilePaths.size() > 0);\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/zzg/mybatis/generator/util/StringUtilTest.java",
    "content": "package com.zzg.mybatis.generator.util;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * Created by Owen on 6/18/16.\n */\npublic class StringUtilTest {\n\n    @Test\n    public void testDbStringToCamelStyle() {\n        String result = MyStringUtils.dbStringToCamelStyle(\"person_address\");\n        Assert.assertEquals(\"PersonAddress\", result);\n    }\n\n    @Test\n    public void testDbStringToCamelStyle_case2() {\n        String result = MyStringUtils.dbStringToCamelStyle(\"person_address_name\");\n        Assert.assertEquals(\"PersonAddressName\", result);\n    }\n\n    @Test\n    public void testDbStringToCamelStyle_case3() {\n        String result = MyStringUtils.dbStringToCamelStyle(\"person_db_name\");\n        Assert.assertEquals(\"PersonDbName\", result);\n    }\n\n    @Test\n    public void testDbStringToCamelStyle_case4() {\n        String result = MyStringUtils.dbStringToCamelStyle(\"person_jobs_\");\n        Assert.assertEquals(\"PersonJobs\", result);\n    }\n\n    @Test\n    public void testDbStringToCamelStyle_case5() {\n        String result = MyStringUtils.dbStringToCamelStyle(\"a\");\n        Assert.assertEquals(\"A\", result);\n    }\n\n}\n"
  }
]