Repository: zouzg/mybatis-generator-gui Branch: master Commit: dde137711ac1 Files: 55 Total size: 199.5 KB Directory structure: gitextract_tz7ayfc4/ ├── .gitignore ├── README.md ├── _config.yml ├── package/ │ └── macosx/ │ └── mybatis-generator-gui.icns ├── pom.xml └── src/ ├── main/ │ ├── java/ │ │ └── com/ │ │ └── zzg/ │ │ └── mybatis/ │ │ └── generator/ │ │ ├── Main.java │ │ ├── MainUI.java │ │ ├── bridge/ │ │ │ └── MybatisGeneratorBridge.java │ │ ├── controller/ │ │ │ ├── BaseFXController.java │ │ │ ├── DbConnectionController.java │ │ │ ├── FXMLPage.java │ │ │ ├── GeneratorConfigController.java │ │ │ ├── MainUIController.java │ │ │ ├── OverSshController.java │ │ │ ├── PictureProcessStateController.java │ │ │ ├── SelectTableColumnController.java │ │ │ ├── TabPaneController.java │ │ │ └── TableColumnConfigsController.java │ │ ├── exception/ │ │ │ └── DbDriverLoadingException.java │ │ ├── model/ │ │ │ ├── CachedFXMLLoader.java │ │ │ ├── DatabaseConfig.java │ │ │ ├── DatabaseDTO.java │ │ │ ├── DbType.java │ │ │ ├── GeneratorConfig.java │ │ │ └── UITableColumnVO.java │ │ ├── plugins/ │ │ │ ├── CommonDAOInterfacePlugin.java │ │ │ ├── DbRemarksCommentGenerator.java │ │ │ ├── JavaTypeResolverJsr310Impl.java │ │ │ ├── MySQLForUpdatePlugin.java │ │ │ ├── MySQLLimitPlugin.java │ │ │ └── RepositoryPlugin.java │ │ ├── util/ │ │ │ ├── ConfigHelper.java │ │ │ ├── ConnectionManager.java │ │ │ ├── DbUtil.java │ │ │ └── MyStringUtils.java │ │ └── view/ │ │ ├── AlertUtil.java │ │ ├── LeftDbTreeCell.java │ │ └── UIProgressCallback.java │ └── resources/ │ ├── fxml/ │ │ ├── MainUI.fxml │ │ ├── basicConnection.fxml │ │ ├── generatorConfigs.fxml │ │ ├── newConnection.fxml │ │ ├── selectTableColumn.fxml │ │ ├── sshBasedConnection.fxml │ │ └── tableColumnConfigs.fxml │ ├── lib/ │ │ ├── mysql-connector-java-5.1.38.jar │ │ ├── mysql-connector-java-8.0.11.jar │ │ ├── ojdbc6.jar │ │ ├── postgresql-9.4.1209.jar │ │ ├── sqlite-jdbc-3.19.3.jar │ │ └── sqljdbc4-4.0.jar │ ├── logback.xml │ └── style.css └── test/ └── java/ └── com/ └── zzg/ └── mybatis/ └── generator/ └── util/ ├── ConfigHelperTest.java └── StringUtilTest.java ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ /target/ /config/ .idea .settings logs *.iml .project .classpath /src/main/resources/sqlite3.db /config/ ================================================ FILE: README.md ================================================ mybatis-generator-gui ============== mybatis-generator-gui是基于 [mybatis generator](http://www.mybatis.org/generator/index.html) 开发一款界面工具, 本工具可以使你非常容易及快速生成Mybatis的Java POJO文件及数据库Mapping文件。 ![image](https://user-images.githubusercontent.com/3505708/49334784-1a42c980-f619-11e8-914d-9ea85db9cec3.png) ![basic](https://user-images.githubusercontent.com/3505708/51911610-45754980-240d-11e9-85ad-643e55cafab2.png) ![overSSH](https://user-images.githubusercontent.com/3505708/51911646-5920b000-240d-11e9-9048-738306a56d14.png) ![SearchSupport](https://user-images.githubusercontent.com/8142133/115959972-881d2200-a541-11eb-8ad4-052f379b91f1.png) ### 核心特性 * 按照界面步骤轻松生成代码,省去XML繁琐的学习与配置过程 * 保存数据库连接与Generator配置,每次代码生成轻松搞定 * 内置常用插件,比如分页插件 * 支持OverSSH 方式,通过SSH隧道连接至公司内网访问数据库 * 把数据库中表列的注释生成为Java实体的注释,生成的实体清晰明了 * 可选的去除掉对版本管理不友好的注释,这样新增或删除字段重新生成的文件比较过来清楚 * 目前已经支持Mysql、Mysql8、Oracle、PostgreSQL与SQL Server,暂不对其他非主流数据库提供支持。(MySQL支持的比较好,其他数据库有什么问题可以在issue中反馈) ### 运行要求(重要!!!) 本工具仅支持Java的2个最新的LTS版本,jdk8和jdk11 * jdk1.8要求版本在1.8.0.60以上版本 * Java 11无版本要求 ### 直接运行(非必须) 推荐使用IDE直接运行,如果需要二进制安装包,可以关注公众号获取二进制安装版,目前支持Windows和MacOS,注意你的JDK是不是1.8,并且版本大于1.8.0.60 ### 启动本软件 * 方法一:关注微信公众号“搬砖头也要有态度”,回复“GUI”获取下载链接 ![image](https://user-images.githubusercontent.com/3505708/61360019-2893dc00-a8b0-11e9-8dc9-a020e997ab87.png) * 方法二: 自助构建 ```bash git clone https://github.com/zouzg/mybatis-generator-gui cd mybatis-generator-gui mvn jfx:jar cd target/jfx/app/ java -jar mybatis-generator-gui.jar ``` * 方法三: IDE中运行 Eclipse or IntelliJ IDEA中启动, 找到`com.zzg.mybatis.generator.MainUI`类并运行就可以了(主要你的IED运行的jdk版本是否符合要求) * 方法四:打包为本地原生应用,双击快捷方式即可启动,方便快捷 如果不想打包后的安装包logo为Java的灰色的茶杯,需要在pom文件里将对应操作系统平台的图标注释放开 ```bash #${project.basedir}/package/windows/mybatis-generator-gui.ico为windows #${project.basedir}/package/macosx/mybatis-generator-gui.icns为mac mvn jfx:native ``` 另外需要注意,windows系统打包成exe的话需要安装WiXToolset3+的环境;由于打包后会把jre打入安装包,两个平台均100M左右,体积较大请自行打包;打包后的安装包在target/jfx/native目录下 ### 注意事项 * 本自动生成代码工具只适合生成单表的增删改查,对于需要做数据库联合查询的,请自行写新的XML与Mapper; * 部分系统在中文输入方法时输入框中无法输入文字,请切换成英文输入法; * 如果不明白对应字段或选项是什么意思的时候,把光标放在对应字段或Label上停留一会然后如果有解释会出现解释; ### 文档 更多详细文档请参考本库的Wiki * [Usage](https://github.com/astarring/mybatis-generator-gui/wiki/Usage-Guide) ### 贡献 目前本工具只是本人项目人使用到了并且觉得非常有用所以把它开源,如果你觉得有用并且想改进本软件,你可以: * 对于你认为有用的功能,你可以在Issue提,我可以开发的尽量满足 * 对于有Bug的地方,请按如下方式在Issue中提bug * 如何重现你的bug,包括你使用的系统,JDK版本,数据库类型及版本 * 如果有任何的错误截图会更好 * 如果你是一些常见的数据库连接、软件启动不了等问题,请先仔细阅读上面的文档,再解决不了在下面的QQ群中问(问问题的时候尽量把各种信息都提供好,否则只是几行文字是没有人愿意为你解答的)。 ### QQ群 鉴于有的同学可能有一些特殊情况不能使用,我建了一个钉钉群供大家交流,钉钉群号:35412531 (原QQ群已不再提供,QQ不方便打开) - - - Licensed under the Apache 2.0 License Copyright 2017 by Owen Zou ================================================ FILE: _config.yml ================================================ theme: jekyll-theme-cayman ================================================ FILE: pom.xml ================================================ 4.0.0 com.zzg mybatis-generator-gui 0.8.9-SNAPSHOT UTF-8 UTF-8 UTF-8 1.8 org.mybatis.generator mybatis-generator-core 1.3.6 ch.qos.logback logback-classic 1.2.0 ch.qos.logback logback-core 1.2.0 org.apache.commons commons-lang3 3.4 commons-io commons-io [2.7,) org.xerial sqlite-jdbc 3.8.11.2 commons-beanutils commons-beanutils 1.9.2 com.alibaba fastjson 1.2.76 junit junit 4.13.1 org.slf4j slf4j-api 1.7.25 com.jcraft jsch 0.1.54 com.softwareloop mybatis-generator-lombok-plugin 1.0 maven-compiler-plugin 3.1 1.8 1.8 com.zenjava javafx-maven-plugin 8.8.3 ${project.basedir}/package/windows/mybatis-generator-gui.ico ${project.basedir}/package/macosx/mybatis-generator-gui.icns com.zzg.mybatis.generator.MainUI Owen Zou false mybatis-generator-gui.jar true true true ${project.basedir}/src/main/resources ================================================ FILE: src/main/java/com/zzg/mybatis/generator/Main.java ================================================ package com.zzg.mybatis.generator; import javafx.application.Application; /** * @author 欧闻 * @version $Id: Main, v 0.1 2021/4/20 欧闻 Exp $$ */ public class Main { public static void main(String[] args) { Application.launch(MainUI.class); } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/MainUI.java ================================================ package com.zzg.mybatis.generator; import com.zzg.mybatis.generator.controller.MainUIController; import com.zzg.mybatis.generator.util.ConfigHelper; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.stage.Stage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.swing.*; import java.net.URL; /** * 这是本软件的主入口,要运行本软件请直接运行本类就可以了,不用传入任何参数 * 本软件要求jkd版本大于1.8.0.40 */ public class MainUI extends Application { private static final Logger _LOG = LoggerFactory.getLogger(MainUI.class); @Override public void start(Stage primaryStage) throws Exception { ConfigHelper.createEmptyFiles(); URL url = Thread.currentThread().getContextClassLoader().getResource("fxml/MainUI.fxml"); FXMLLoader fxmlLoader = new FXMLLoader(url); Parent root = fxmlLoader.load(); primaryStage.setResizable(true); primaryStage.setScene(new Scene(root)); primaryStage.setTitle("Mybatis Generator GUI"); Image imageIcon = new Image("icons/mybatis-logo.png"); primaryStage.getIcons().add(imageIcon); primaryStage.show(); MainUIController controller = fxmlLoader.getController(); controller.setPrimaryStage(primaryStage); } public static void main(String[] args) { launch(args); } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/bridge/MybatisGeneratorBridge.java ================================================ package com.zzg.mybatis.generator.bridge; import com.jcraft.jsch.Session; import com.zzg.mybatis.generator.controller.PictureProcessStateController; import com.zzg.mybatis.generator.model.DatabaseConfig; import com.zzg.mybatis.generator.model.DbType; import com.zzg.mybatis.generator.model.GeneratorConfig; import com.zzg.mybatis.generator.plugins.DbRemarksCommentGenerator; import com.zzg.mybatis.generator.util.ConfigHelper; import com.zzg.mybatis.generator.util.DbUtil; import org.apache.commons.lang3.StringUtils; import org.mybatis.generator.api.MyBatisGenerator; import org.mybatis.generator.api.ProgressCallback; import org.mybatis.generator.api.ShellCallback; import org.mybatis.generator.config.*; import org.mybatis.generator.internal.DefaultShellCallback; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; /** * The bridge between GUI and the mybatis generator. All the operation to mybatis generator should proceed through this * class *

* Created by Owen on 6/30/16. */ public class MybatisGeneratorBridge { private static final Logger _LOG = LoggerFactory.getLogger(MybatisGeneratorBridge.class); private GeneratorConfig generatorConfig; private DatabaseConfig selectedDatabaseConfig; private ProgressCallback progressCallback; private List ignoredColumns; private List columnOverrides; public MybatisGeneratorBridge() { } public void setGeneratorConfig(GeneratorConfig generatorConfig) { this.generatorConfig = generatorConfig; } public void setDatabaseConfig(DatabaseConfig databaseConfig) { this.selectedDatabaseConfig = databaseConfig; } public void generate() throws Exception { Configuration configuration = new Configuration(); Context context = new Context(ModelType.CONDITIONAL); configuration.addContext(context); context.addProperty("javaFileEncoding", "UTF-8"); String dbType = selectedDatabaseConfig.getDbType(); String connectorLibPath = ConfigHelper.findConnectorLibPath(dbType); _LOG.info("connectorLibPath: {}", connectorLibPath); configuration.addClasspathEntry(connectorLibPath); // Table configuration TableConfiguration tableConfig = new TableConfiguration(context); tableConfig.setTableName(generatorConfig.getTableName()); tableConfig.setDomainObjectName(generatorConfig.getDomainObjectName()); if(!generatorConfig.isUseExample()) { tableConfig.setUpdateByExampleStatementEnabled(false); tableConfig.setCountByExampleStatementEnabled(false); tableConfig.setDeleteByExampleStatementEnabled(false); tableConfig.setSelectByExampleStatementEnabled(false); } context.addProperty("autoDelimitKeywords", "true"); if (DbType.MySQL.name().equals(dbType) || DbType.MySQL_8.name().equals(dbType)) { tableConfig.setSchema(selectedDatabaseConfig.getSchema()); // 由于beginningDelimiter和endingDelimiter的默认值为双引号("),在Mysql中不能这么写,所以还要将这两个默认值改为` context.addProperty("beginningDelimiter", "`"); context.addProperty("endingDelimiter", "`"); } else { tableConfig.setCatalog(selectedDatabaseConfig.getSchema()); } if (generatorConfig.isUseSchemaPrefix()) { if (DbType.MySQL.name().equals(dbType) || DbType.MySQL_8.name().equals(dbType)) { tableConfig.setSchema(selectedDatabaseConfig.getSchema()); } else if (DbType.Oracle.name().equals(dbType)) { //Oracle的schema为用户名,如果连接用户拥有dba等高级权限,若不设schema,会导致把其他用户下同名的表也生成一遍导致mapper中代码重复 tableConfig.setSchema(selectedDatabaseConfig.getUsername()); } else { tableConfig.setCatalog(selectedDatabaseConfig.getSchema()); } } // 针对 postgresql 单独配置 if (DbType.PostgreSQL.name().equals(dbType)) { tableConfig.setDelimitIdentifiers(true); } //添加GeneratedKey主键生成 if (StringUtils.isNotEmpty(generatorConfig.getGenerateKeys())) { String dbType2 = dbType; if (DbType.MySQL.name().equals(dbType2) || DbType.MySQL_8.name().equals(dbType)) { dbType2 = "JDBC"; //dbType为JDBC,且配置中开启useGeneratedKeys时,Mybatis会使用Jdbc3KeyGenerator, //使用该KeyGenerator的好处就是直接在一次INSERT 语句内,通过resultSet获取得到 生成的主键值, //并很好的支持设置了读写分离代理的数据库 //例如阿里云RDS + 读写分离代理 //无需指定主库 //当使用SelectKey时,Mybatis会使用SelectKeyGenerator,INSERT之后,多发送一次查询语句,获得主键值 //在上述读写分离被代理的情况下,会得不到正确的主键 } tableConfig.setGeneratedKey(new GeneratedKey(generatorConfig.getGenerateKeys(), dbType2, true, null)); } if (generatorConfig.getMapperName() != null) { tableConfig.setMapperName(generatorConfig.getMapperName()); } // add ignore columns if (ignoredColumns != null) { ignoredColumns.forEach(tableConfig::addIgnoredColumn); } if (columnOverrides != null) { columnOverrides.forEach(tableConfig::addColumnOverride); } if (generatorConfig.isUseActualColumnNames()) { tableConfig.addProperty("useActualColumnNames", "true"); } if(generatorConfig.isUseTableNameAlias()){ tableConfig.setAlias(generatorConfig.getTableName()); } JDBCConnectionConfiguration jdbcConfig = new JDBCConnectionConfiguration(); if (DbType.MySQL.name().equals(dbType) || DbType.MySQL_8.name().equals(dbType)) { jdbcConfig.addProperty("nullCatalogMeansCurrent", "true"); // useInformationSchema可以拿到表注释,从而生成类注释可以使用表的注释 jdbcConfig.addProperty("useInformationSchema", "true"); } jdbcConfig.setDriverClass(DbType.valueOf(dbType).getDriverClass()); jdbcConfig.setConnectionURL(DbUtil.getConnectionUrlWithSchema(selectedDatabaseConfig)); jdbcConfig.setUserId(selectedDatabaseConfig.getUsername()); jdbcConfig.setPassword(selectedDatabaseConfig.getPassword()); if(DbType.Oracle.name().equals(dbType)){ jdbcConfig.getProperties().setProperty("remarksReporting", "true"); } // java model JavaModelGeneratorConfiguration modelConfig = new JavaModelGeneratorConfiguration(); modelConfig.setTargetPackage(generatorConfig.getModelPackage()); modelConfig.setTargetProject(generatorConfig.getProjectFolder() + "/" + generatorConfig.getModelPackageTargetFolder()); // Mapper configuration SqlMapGeneratorConfiguration mapperConfig = new SqlMapGeneratorConfiguration(); mapperConfig.setTargetPackage(generatorConfig.getMappingXMLPackage()); mapperConfig.setTargetProject(generatorConfig.getProjectFolder() + "/" + generatorConfig.getMappingXMLTargetFolder()); // DAO JavaClientGeneratorConfiguration daoConfig = new JavaClientGeneratorConfiguration(); daoConfig.setConfigurationType("XMLMAPPER"); daoConfig.setTargetPackage(generatorConfig.getDaoPackage()); daoConfig.setTargetProject(generatorConfig.getProjectFolder() + "/" + generatorConfig.getDaoTargetFolder()); context.setId("myid"); context.addTableConfiguration(tableConfig); context.setJdbcConnectionConfiguration(jdbcConfig); context.setJavaModelGeneratorConfiguration(modelConfig); context.setSqlMapGeneratorConfiguration(mapperConfig); context.setJavaClientGeneratorConfiguration(daoConfig); // Comment CommentGeneratorConfiguration commentConfig = new CommentGeneratorConfiguration(); commentConfig.setConfigurationType(DbRemarksCommentGenerator.class.getName()); if (generatorConfig.isComment()) { commentConfig.addProperty("columnRemarks", "true"); } if (generatorConfig.isAnnotation()) { commentConfig.addProperty("annotations", "true"); } context.setCommentGeneratorConfiguration(commentConfig); // set java file encoding context.addProperty(PropertyRegistry.CONTEXT_JAVA_FILE_ENCODING, generatorConfig.getEncoding()); //实体添加序列化 PluginConfiguration serializablePluginConfiguration = new PluginConfiguration(); serializablePluginConfiguration.addProperty("type", "org.mybatis.generator.plugins.SerializablePlugin"); serializablePluginConfiguration.setConfigurationType("org.mybatis.generator.plugins.SerializablePlugin"); context.addPluginConfiguration(serializablePluginConfiguration); // Lombok 插件 if (generatorConfig.isUseLombokPlugin()) { PluginConfiguration pluginConfiguration = new PluginConfiguration(); pluginConfiguration.addProperty("type", "com.softwareloop.mybatis.generator.plugins.LombokPlugin"); pluginConfiguration.setConfigurationType("com.softwareloop.mybatis.generator.plugins.LombokPlugin"); context.addPluginConfiguration(pluginConfiguration); } // toString, hashCode, equals插件 else if (generatorConfig.isNeedToStringHashcodeEquals()) { PluginConfiguration pluginConfiguration1 = new PluginConfiguration(); pluginConfiguration1.addProperty("type", "org.mybatis.generator.plugins.EqualsHashCodePlugin"); pluginConfiguration1.setConfigurationType("org.mybatis.generator.plugins.EqualsHashCodePlugin"); context.addPluginConfiguration(pluginConfiguration1); PluginConfiguration pluginConfiguration2 = new PluginConfiguration(); pluginConfiguration2.addProperty("type", "org.mybatis.generator.plugins.ToStringPlugin"); pluginConfiguration2.setConfigurationType("org.mybatis.generator.plugins.ToStringPlugin"); context.addPluginConfiguration(pluginConfiguration2); } // limit/offset插件 if (generatorConfig.isOffsetLimit()) { if (DbType.MySQL.name().equals(dbType) || DbType.MySQL_8.name().equals(dbType) || DbType.PostgreSQL.name().equals(dbType)) { PluginConfiguration pluginConfiguration = new PluginConfiguration(); pluginConfiguration.addProperty("type", "com.zzg.mybatis.generator.plugins.MySQLLimitPlugin"); pluginConfiguration.setConfigurationType("com.zzg.mybatis.generator.plugins.MySQLLimitPlugin"); context.addPluginConfiguration(pluginConfiguration); } } //for JSR310 if (generatorConfig.isJsr310Support()) { JavaTypeResolverConfiguration javaTypeResolverConfiguration = new JavaTypeResolverConfiguration(); javaTypeResolverConfiguration.setConfigurationType("com.zzg.mybatis.generator.plugins.JavaTypeResolverJsr310Impl"); context.setJavaTypeResolverConfiguration(javaTypeResolverConfiguration); } //forUpdate 插件 if(generatorConfig.isNeedForUpdate()) { if (DbType.MySQL.name().equals(dbType) || DbType.PostgreSQL.name().equals(dbType)) { PluginConfiguration pluginConfiguration = new PluginConfiguration(); pluginConfiguration.addProperty("type", "com.zzg.mybatis.generator.plugins.MySQLForUpdatePlugin"); pluginConfiguration.setConfigurationType("com.zzg.mybatis.generator.plugins.MySQLForUpdatePlugin"); context.addPluginConfiguration(pluginConfiguration); } } //repository 插件 if(generatorConfig.isAnnotationDAO()) { if (DbType.MySQL.name().equals(dbType) || DbType.MySQL_8.name().equals(dbType) || DbType.PostgreSQL.name().equals(dbType)) { PluginConfiguration pluginConfiguration = new PluginConfiguration(); pluginConfiguration.addProperty("type", "com.zzg.mybatis.generator.plugins.RepositoryPlugin"); pluginConfiguration.setConfigurationType("com.zzg.mybatis.generator.plugins.RepositoryPlugin"); context.addPluginConfiguration(pluginConfiguration); } } if (generatorConfig.isUseDAOExtendStyle()) { if (DbType.MySQL.name().equals(dbType) || DbType.MySQL_8.name().equals(dbType) || DbType.PostgreSQL.name().equals(dbType)) { PluginConfiguration pluginConfiguration = new PluginConfiguration(); pluginConfiguration.addProperty("useExample", String.valueOf(generatorConfig.isUseExample())); pluginConfiguration.addProperty("type", "com.zzg.mybatis.generator.plugins.CommonDAOInterfacePlugin"); pluginConfiguration.setConfigurationType("com.zzg.mybatis.generator.plugins.CommonDAOInterfacePlugin"); context.addPluginConfiguration(pluginConfiguration); } } context.setTargetRuntime("MyBatis3"); List warnings = new ArrayList<>(); Set fullyqualifiedTables = new HashSet<>(); Set contexts = new HashSet<>(); ShellCallback shellCallback = new DefaultShellCallback(true); // override=true MyBatisGenerator myBatisGenerator = new MyBatisGenerator(configuration, shellCallback, warnings); // if overrideXML selected, delete oldXML ang generate new one if (generatorConfig.isOverrideXML()) { String mappingXMLFilePath = getMappingXMLFilePath(generatorConfig); File mappingXMLFile = new File(mappingXMLFilePath); if (mappingXMLFile.exists()) { mappingXMLFile.delete(); } } myBatisGenerator.generate(progressCallback, contexts, fullyqualifiedTables); } private String getMappingXMLFilePath(GeneratorConfig generatorConfig) { StringBuilder sb = new StringBuilder(); sb.append(generatorConfig.getProjectFolder()).append("/"); sb.append(generatorConfig.getMappingXMLTargetFolder()).append("/"); String mappingXMLPackage = generatorConfig.getMappingXMLPackage(); if (StringUtils.isNotEmpty(mappingXMLPackage)) { sb.append(mappingXMLPackage.replace(".", "/")).append("/"); } if (StringUtils.isNotEmpty(generatorConfig.getMapperName())) { sb.append(generatorConfig.getMapperName()).append(".xml"); } else { sb.append(generatorConfig.getDomainObjectName()).append("Mapper.xml"); } return sb.toString(); } public void setProgressCallback(ProgressCallback progressCallback) { this.progressCallback = progressCallback; } public void setIgnoredColumns(List ignoredColumns) { this.ignoredColumns = ignoredColumns; } public void setColumnOverrides(List columnOverrides) { this.columnOverrides = columnOverrides; } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/controller/BaseFXController.java ================================================ package com.zzg.mybatis.generator.controller; import com.zzg.mybatis.generator.view.AlertUtil; import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Modality; import javafx.stage.Stage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.lang.ref.SoftReference; import java.net.URL; import java.util.HashMap; import java.util.Map; public abstract class BaseFXController implements Initializable { private static final Logger _LOG = LoggerFactory.getLogger(BaseFXController.class); private Stage primaryStage; private Stage dialogStage; private static Map> cacheNodeMap = new HashMap<>(); public BaseFXController loadFXMLPage(String title, FXMLPage fxmlPage, boolean cache) { SoftReference parentNodeRef = cacheNodeMap.get(fxmlPage); if (cache && parentNodeRef != null) { return parentNodeRef.get(); } URL skeletonResource = Thread.currentThread().getContextClassLoader().getResource(fxmlPage.getFxml()); FXMLLoader loader = new FXMLLoader(skeletonResource); Parent loginNode; try { loginNode = loader.load(); BaseFXController controller = loader.getController(); // fix bug: 嵌套弹出时会发生dialogStage被覆盖的情况 Stage tmpDialogStage = new Stage(); tmpDialogStage.setTitle(title); tmpDialogStage.initModality(Modality.APPLICATION_MODAL); tmpDialogStage.initOwner(getPrimaryStage()); tmpDialogStage.setScene(new Scene(loginNode)); tmpDialogStage.setMaximized(false); tmpDialogStage.setResizable(false); tmpDialogStage.show(); controller.setDialogStage(tmpDialogStage); // put into cache map SoftReference softReference = new SoftReference<>(controller); cacheNodeMap.put(fxmlPage, softReference); return controller; } catch (IOException e) { _LOG.error(e.getMessage(), e); AlertUtil.showErrorAlert(e.getMessage()); } return null; } public Stage getPrimaryStage() { return primaryStage; } public void setPrimaryStage(Stage primaryStage) { this.primaryStage = primaryStage; } public Stage getDialogStage() { return dialogStage; } public void setDialogStage(Stage dialogStage) { this.dialogStage = dialogStage; } public void showDialogStage() { if (dialogStage != null) { dialogStage.show(); } } public void closeDialogStage() { if (dialogStage != null) { dialogStage.close(); } } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/controller/DbConnectionController.java ================================================ package com.zzg.mybatis.generator.controller; import com.zzg.mybatis.generator.model.DatabaseConfig; import com.zzg.mybatis.generator.util.ConfigHelper; import com.zzg.mybatis.generator.view.AlertUtil; import javafx.fxml.FXML; import javafx.scene.control.ChoiceBox; import javafx.scene.control.TextField; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.URL; import java.util.ResourceBundle; public class DbConnectionController extends BaseFXController { private static final Logger _LOG = LoggerFactory.getLogger(DbConnectionController.class); @FXML protected TextField nameField; @FXML protected TextField hostField; @FXML protected TextField portField; @FXML protected TextField userNameField; @FXML protected TextField passwordField; @FXML protected TextField schemaField; @FXML protected ChoiceBox encodingChoice; @FXML protected ChoiceBox dbTypeChoice; protected MainUIController mainUIController; protected TabPaneController tabPaneController; protected boolean isUpdate = false; protected Integer primayKey; @Override public void initialize(URL location, ResourceBundle resources) { } final void saveConnection() { DatabaseConfig config = extractConfigForUI(); if (config == null) { return; } try { ConfigHelper.saveDatabaseConfig(this.isUpdate, primayKey, config); this.tabPaneController.getDialogStage().close(); mainUIController.loadLeftDBTree(); } catch (Exception e) { _LOG.error(e.getMessage(), e); AlertUtil.showErrorAlert(e.getMessage()); } } void setMainUIController(MainUIController controller) { this.mainUIController = controller; super.setDialogStage(mainUIController.getDialogStage()); } public void setTabPaneController(TabPaneController tabPaneController) { this.tabPaneController = tabPaneController; } public DatabaseConfig extractConfigForUI() { String name = nameField.getText(); String host = hostField.getText(); String port = portField.getText(); String userName = userNameField.getText(); String password = passwordField.getText(); String encoding = encodingChoice.getValue(); String dbType = dbTypeChoice.getValue(); String schema = schemaField.getText(); DatabaseConfig config = new DatabaseConfig(); config.setName(name); config.setDbType(dbType); config.setHost(host); config.setPort(port); config.setUsername(userName); config.setPassword(password); config.setSchema(schema); config.setEncoding(encoding); if (StringUtils.isAnyEmpty(name, host, port, userName, encoding, dbType, schema)) { AlertUtil.showWarnAlert("密码以外其他字段必填"); return null; } return config; } public void setConfig(DatabaseConfig config) { isUpdate = true; primayKey = config.getId(); // save id for update config nameField.setText(config.getName()); hostField.setText(config.getHost()); portField.setText(config.getPort()); userNameField.setText(config.getUsername()); passwordField.setText(config.getPassword()); encodingChoice.setValue(config.getEncoding()); dbTypeChoice.setValue(config.getDbType()); schemaField.setText(config.getSchema()); } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/controller/FXMLPage.java ================================================ package com.zzg.mybatis.generator.controller; /** * FXML User Interface enum *

* Created by Owen on 6/20/16. */ public enum FXMLPage { NEW_CONNECTION("fxml/newConnection.fxml"), SELECT_TABLE_COLUMN("fxml/selectTableColumn.fxml"), TABLE_COLUMN_CONFIG("fxml/tableColumnConfigs.fxml"), GENERATOR_CONFIG("fxml/generatorConfigs.fxml"), ; private String fxml; FXMLPage(String fxml) { this.fxml = fxml; } public String getFxml() { return this.fxml; } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/controller/GeneratorConfigController.java ================================================ package com.zzg.mybatis.generator.controller; import com.zzg.mybatis.generator.model.GeneratorConfig; import com.zzg.mybatis.generator.util.ConfigHelper; import com.zzg.mybatis.generator.view.AlertUtil; import javafx.collections.FXCollections; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.layout.HBox; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.URL; import java.util.List; import java.util.ResourceBundle; /** * 管理GeneratorConfig的Controller * * Created by Owen on 8/21/16. */ public class GeneratorConfigController extends BaseFXController { private static final Logger _LOG = LoggerFactory.getLogger(GeneratorConfigController.class); @FXML private TableView configTable; @FXML private TableColumn nameColumn; @FXML private TableColumn opsColumn; private MainUIController mainUIController; private GeneratorConfigController controller; @Override public void initialize(URL location, ResourceBundle resources) { controller = this; nameColumn.setCellValueFactory(new PropertyValueFactory<>("name")); // 自定义操作列 opsColumn.setCellValueFactory(new PropertyValueFactory<>("name")); opsColumn.setCellFactory(cell -> { return new TableCell() { @Override protected void updateItem(Object item, boolean empty) { super.updateItem(item, empty); if (item == null || empty) { setText(null); setGraphic(null); } else { Button btn1 = new Button("应用"); Button btn2 = new Button("删除"); HBox hBox = new HBox(); hBox.setSpacing(10); hBox.getChildren().add(btn1); hBox.getChildren().add(btn2); btn1.setOnAction(event -> { try { // 应用配置 GeneratorConfig generatorConfig = ConfigHelper.loadGeneratorConfig(item.toString()); mainUIController.setGeneratorConfigIntoUI(generatorConfig); controller.closeDialogStage(); } catch (Exception e) { AlertUtil.showErrorAlert(e.getMessage()); } }); btn2.setOnAction(event -> { try { // 删除配置 _LOG.debug("item: {}", item); ConfigHelper.deleteGeneratorConfig(item.toString()); refreshTableView(); } catch (Exception e) { AlertUtil.showErrorAlert(e.getMessage()); } }); setGraphic(hBox); } } }; }); refreshTableView(); } public void refreshTableView() { try { List configs = ConfigHelper.loadGeneratorConfigs(); configTable.setItems(FXCollections.observableList(configs)); } catch (Exception e) { AlertUtil.showErrorAlert(e.getMessage()); } } void setMainUIController(MainUIController mainUIController) { this.mainUIController = mainUIController; } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/controller/MainUIController.java ================================================ package com.zzg.mybatis.generator.controller; import com.jcraft.jsch.Session; import com.zzg.mybatis.generator.bridge.MybatisGeneratorBridge; import com.zzg.mybatis.generator.model.DatabaseConfig; import com.zzg.mybatis.generator.model.GeneratorConfig; import com.zzg.mybatis.generator.model.UITableColumnVO; import com.zzg.mybatis.generator.util.ConfigHelper; import com.zzg.mybatis.generator.util.DbUtil; import com.zzg.mybatis.generator.util.MyStringUtils; import com.zzg.mybatis.generator.view.AlertUtil; import com.zzg.mybatis.generator.view.UIProgressCallback; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.concurrent.Task; import javafx.fxml.FXML; import javafx.scene.control.*; import javafx.scene.control.Label; import javafx.scene.control.MenuItem; import javafx.scene.control.TextField; import javafx.scene.control.cell.TextFieldTreeCell; import javafx.scene.image.ImageView; import javafx.scene.input.KeyCode; import javafx.scene.input.MouseEvent; import javafx.scene.input.KeyEvent; import javafx.stage.DirectoryChooser; import javafx.util.Callback; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.mybatis.generator.config.ColumnOverride; import org.mybatis.generator.config.IgnoredColumn; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.awt.*; import java.io.File; import java.net.URL; import java.sql.SQLRecoverableException; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.ResourceBundle; public class MainUIController extends BaseFXController { private static final Logger _LOG = LoggerFactory.getLogger(MainUIController.class); private static final String FOLDER_NO_EXIST = "部分目录不存在,是否创建"; // tool bar buttons @FXML private Label connectionLabel; @FXML private Label configsLabel; @FXML private TextField modelTargetPackage; @FXML private TextField mapperTargetPackage; @FXML private TextField daoTargetPackage; @FXML private TextField tableNameField; @FXML private TextField domainObjectNameField; @FXML private TextField generateKeysField; //主键ID @FXML private TextField modelTargetProject; @FXML private TextField mappingTargetProject; @FXML private TextField daoTargetProject; @FXML private TextField mapperName; @FXML private TextField projectFolderField; @FXML private CheckBox offsetLimitCheckBox; @FXML private CheckBox commentCheckBox; @FXML private CheckBox overrideXML; @FXML private CheckBox needToStringHashcodeEquals; @FXML private CheckBox useLombokPlugin; @FXML private CheckBox forUpdateCheckBox; @FXML private CheckBox annotationDAOCheckBox; @FXML private CheckBox useTableNameAliasCheckbox; @FXML private CheckBox annotationCheckBox; @FXML private CheckBox useActualColumnNamesCheckbox; @FXML private CheckBox useExample; @FXML private CheckBox useDAOExtendStyle; @FXML private CheckBox useSchemaPrefix; @FXML private CheckBox jsr310Support; @FXML private TreeView leftDBTree; @FXML public TextField filterTreeBox; // Current selected databaseConfig private DatabaseConfig selectedDatabaseConfig; // Current selected tableName private String tableName; private List ignoredColumns; private List columnOverrides; @FXML private ChoiceBox encodingChoice; @Override public void initialize(URL location, ResourceBundle resources) { ImageView dbImage = new ImageView("icons/computer.png"); dbImage.setFitHeight(40); dbImage.setFitWidth(40); connectionLabel.setGraphic(dbImage); connectionLabel.setOnMouseClicked(event -> { TabPaneController controller = (TabPaneController) loadFXMLPage("新建数据库连接", FXMLPage.NEW_CONNECTION, false); controller.setMainUIController(this); controller.showDialogStage(); }); ImageView configImage = new ImageView("icons/config-list.png"); configImage.setFitHeight(40); configImage.setFitWidth(40); configsLabel.setGraphic(configImage); configsLabel.setOnMouseClicked(event -> { GeneratorConfigController controller = (GeneratorConfigController) loadFXMLPage("配置", FXMLPage.GENERATOR_CONFIG, false); controller.setMainUIController(this); controller.showDialogStage(); }); useExample.setOnMouseClicked(event -> { if (useExample.isSelected()) { offsetLimitCheckBox.setDisable(false); } else { offsetLimitCheckBox.setDisable(true); } }); // selectedProperty().addListener 解决应用配置的时候未触发Clicked事件 useLombokPlugin.selectedProperty().addListener((observable, oldValue, newValue) -> { needToStringHashcodeEquals.setDisable(newValue); }); leftDBTree.setShowRoot(false); leftDBTree.setRoot(new TreeItem<>()); Callback, TreeCell> defaultCellFactory = TextFieldTreeCell.forTreeView(); filterTreeBox.addEventHandler(KeyEvent.KEY_PRESSED, ev -> { if (ev.getCode() == KeyCode.ENTER) { ObservableList> schemas = leftDBTree.getRoot().getChildren(); schemas.filtered(TreeItem::isExpanded).forEach(this::displayTables); ev.consume(); } }); leftDBTree.setCellFactory((TreeView tv) -> { TreeCell cell = defaultCellFactory.call(tv); cell.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> { int level = leftDBTree.getTreeItemLevel(cell.getTreeItem()); TreeCell treeCell = (TreeCell) event.getSource(); TreeItem treeItem = treeCell.getTreeItem(); if (level == 1) { final ContextMenu contextMenu = new ContextMenu(); MenuItem item1 = new MenuItem("关闭连接"); item1.setOnAction(event1 -> treeItem.getChildren().clear()); MenuItem item2 = new MenuItem("编辑连接"); item2.setOnAction(event1 -> { DatabaseConfig selectedConfig = (DatabaseConfig) treeItem.getGraphic().getUserData(); TabPaneController controller = (TabPaneController) loadFXMLPage("编辑数据库连接", FXMLPage.NEW_CONNECTION, false); controller.setMainUIController(this); controller.setConfig(selectedConfig); controller.showDialogStage(); }); MenuItem item3 = new MenuItem("删除连接"); item3.setOnAction(event1 -> { DatabaseConfig selectedConfig = (DatabaseConfig) treeItem.getGraphic().getUserData(); try { ConfigHelper.deleteDatabaseConfig(selectedConfig); this.loadLeftDBTree(); } catch (Exception e) { AlertUtil.showErrorAlert("Delete connection failed! Reason: " + e.getMessage()); } }); contextMenu.getItems().addAll(item1, item2, item3); cell.setContextMenu(contextMenu); } if (event.getClickCount() == 2) { if(treeItem == null) { return ; } treeItem.setExpanded(true); if (level == 1) { displayTables(treeItem); } else if (level == 2) { // left DB tree level3 String tableName = treeCell.getTreeItem().getValue(); selectedDatabaseConfig = (DatabaseConfig) treeItem.getParent().getGraphic().getUserData(); this.tableName = tableName; tableNameField.setText(tableName); domainObjectNameField.setText(MyStringUtils.dbStringToCamelStyle(tableName)); mapperName.setText(domainObjectNameField.getText().concat("DAO")); } } }); return cell; }); loadLeftDBTree(); setTooltip(); //默认选中第一个,否则如果忘记选择,没有对应错误提示 encodingChoice.getSelectionModel().selectFirst(); } private void displayTables(TreeItem treeItem) { if(treeItem == null) { return ; } if (!treeItem.isExpanded()) { return; } DatabaseConfig selectedConfig = (DatabaseConfig) treeItem.getGraphic().getUserData(); try { String filter = filterTreeBox.getText(); List tables = DbUtil.getTableNames(selectedConfig, filter); if (tables.size() > 0) { ObservableList> children = treeItem.getChildren(); children.clear(); for (String tableName : tables) { TreeItem newTreeItem = new TreeItem<>(); ImageView imageView = new ImageView("icons/table.png"); imageView.setFitHeight(16); imageView.setFitWidth(16); newTreeItem.setGraphic(imageView); newTreeItem.setValue(tableName); children.add(newTreeItem); } }else if (StringUtils.isNotBlank(filter)){ treeItem.getChildren().clear(); } if (StringUtils.isNotBlank(filter)) { ImageView imageView = new ImageView("icons/filter.png"); imageView.setFitHeight(16); imageView.setFitWidth(16); imageView.setUserData(treeItem.getGraphic().getUserData()); treeItem.setGraphic(imageView); }else { ImageView dbImage = new ImageView("icons/computer.png"); dbImage.setFitHeight(16); dbImage.setFitWidth(16); dbImage.setUserData(treeItem.getGraphic().getUserData()); treeItem.setGraphic(dbImage); } } catch (SQLRecoverableException e) { _LOG.error(e.getMessage(), e); AlertUtil.showErrorAlert("连接超时"); } catch (Exception e) { _LOG.error(e.getMessage(), e); AlertUtil.showErrorAlert(e.getMessage()); } } private void setTooltip() { encodingChoice.setTooltip(new Tooltip("生成文件的编码,必选")); generateKeysField.setTooltip(new Tooltip("insert时可以返回主键ID")); offsetLimitCheckBox.setTooltip(new Tooltip("是否要生成分页查询代码")); commentCheckBox.setTooltip(new Tooltip("使用数据库的列注释作为实体类字段名的Java注释 ")); useActualColumnNamesCheckbox.setTooltip(new Tooltip("是否使用数据库实际的列名作为实体类域的名称")); useTableNameAliasCheckbox.setTooltip(new Tooltip("在Mapper XML文件中表名使用别名,并且列全部使用as查询")); overrideXML.setTooltip(new Tooltip("重新生成时把原XML文件覆盖,否则是追加")); useDAOExtendStyle.setTooltip(new Tooltip("将通用接口方法放在公共接口中,DAO接口留空")); forUpdateCheckBox.setTooltip(new Tooltip("在Select语句中增加for update后缀")); useLombokPlugin.setTooltip(new Tooltip("实体类使用Lombok @Data简化代码")); } void loadLeftDBTree() { TreeItem rootTreeItem = leftDBTree.getRoot(); rootTreeItem.getChildren().clear(); try { List dbConfigs = ConfigHelper.loadDatabaseConfig(); for (DatabaseConfig dbConfig : dbConfigs) { TreeItem treeItem = new TreeItem<>(); treeItem.setValue(dbConfig.getName()); ImageView dbImage = new ImageView("icons/computer.png"); dbImage.setFitHeight(16); dbImage.setFitWidth(16); dbImage.setUserData(dbConfig); treeItem.setGraphic(dbImage); rootTreeItem.getChildren().add(treeItem); } } catch (Exception e) { _LOG.error("connect db failed, reason", e); AlertUtil.showErrorAlert(e.getMessage() + "\n" + ExceptionUtils.getStackTrace(e)); } } @FXML public void chooseProjectFolder() { DirectoryChooser directoryChooser = new DirectoryChooser(); File selectedFolder = directoryChooser.showDialog(getPrimaryStage()); if (selectedFolder != null) { projectFolderField.setText(selectedFolder.getAbsolutePath()); } } @FXML public void generateCode() { if (tableName == null) { AlertUtil.showWarnAlert("请先在左侧选择数据库表"); return; } String result = validateConfig(); if (result != null) { AlertUtil.showErrorAlert(result); return; } GeneratorConfig generatorConfig = getGeneratorConfigFromUI(); if (!checkDirs(generatorConfig)) { return; } MybatisGeneratorBridge bridge = new MybatisGeneratorBridge(); bridge.setGeneratorConfig(generatorConfig); bridge.setDatabaseConfig(selectedDatabaseConfig); bridge.setIgnoredColumns(ignoredColumns); bridge.setColumnOverrides(columnOverrides); UIProgressCallback alert = new UIProgressCallback(Alert.AlertType.INFORMATION); bridge.setProgressCallback(alert); alert.show(); PictureProcessStateController pictureProcessStateController = null; try { //Engage PortForwarding Session sshSession = DbUtil.getSSHSession(selectedDatabaseConfig); DbUtil.engagePortForwarding(sshSession, selectedDatabaseConfig); if (sshSession != null) { pictureProcessStateController = new PictureProcessStateController(); pictureProcessStateController.setDialogStage(getDialogStage()); pictureProcessStateController.startPlay(); } bridge.generate(); if (pictureProcessStateController != null) { Task task = new Task() { @Override protected Void call() throws Exception { Thread.sleep(3000); return null; } }; PictureProcessStateController finalPictureProcessStateController = pictureProcessStateController; task.setOnSucceeded(event -> { finalPictureProcessStateController.close(); }); task.setOnFailed(event -> { finalPictureProcessStateController.close(); }); new Thread(task).start(); } } catch (Exception e) { e.printStackTrace(); AlertUtil.showErrorAlert(e.getMessage()); if (pictureProcessStateController != null) { pictureProcessStateController.close(); pictureProcessStateController.playFailState(e.getMessage(), true); } } } private String validateConfig() { String projectFolder = projectFolderField.getText(); if (StringUtils.isEmpty(projectFolder)) { return "项目目录不能为空"; } if (StringUtils.isEmpty(domainObjectNameField.getText())) { return "类名不能为空"; } if (StringUtils.isAnyEmpty(modelTargetPackage.getText(), mapperTargetPackage.getText(), daoTargetPackage.getText())) { return "包名不能为空"; } return null; } @FXML public void saveGeneratorConfig() { TextInputDialog dialog = new TextInputDialog(""); dialog.setTitle("保存当前配置"); dialog.setContentText("请输入配置名称"); Optional result = dialog.showAndWait(); if (result.isPresent()) { String name = result.get(); if (StringUtils.isEmpty(name)) { AlertUtil.showErrorAlert("名称不能为空"); return; } _LOG.info("user choose name: {}", name); try { GeneratorConfig generatorConfig = getGeneratorConfigFromUI(); generatorConfig.setName(name); ConfigHelper.deleteGeneratorConfig(name); ConfigHelper.saveGeneratorConfig(generatorConfig); } catch (Exception e) { _LOG.error("保存配置失败", e); AlertUtil.showErrorAlert("保存配置失败"); } } } public GeneratorConfig getGeneratorConfigFromUI() { GeneratorConfig generatorConfig = new GeneratorConfig(); generatorConfig.setProjectFolder(projectFolderField.getText()); generatorConfig.setModelPackage(modelTargetPackage.getText()); generatorConfig.setGenerateKeys(generateKeysField.getText()); generatorConfig.setModelPackageTargetFolder(modelTargetProject.getText()); generatorConfig.setDaoPackage(daoTargetPackage.getText()); generatorConfig.setDaoTargetFolder(daoTargetProject.getText()); generatorConfig.setMapperName(mapperName.getText()); generatorConfig.setMappingXMLPackage(mapperTargetPackage.getText()); generatorConfig.setMappingXMLTargetFolder(mappingTargetProject.getText()); generatorConfig.setTableName(tableNameField.getText()); generatorConfig.setDomainObjectName(domainObjectNameField.getText()); generatorConfig.setOffsetLimit(offsetLimitCheckBox.isSelected()); generatorConfig.setComment(commentCheckBox.isSelected()); generatorConfig.setOverrideXML(overrideXML.isSelected()); generatorConfig.setNeedToStringHashcodeEquals(needToStringHashcodeEquals.isSelected()); generatorConfig.setUseLombokPlugin(useLombokPlugin.isSelected()); generatorConfig.setUseTableNameAlias(useTableNameAliasCheckbox.isSelected()); generatorConfig.setNeedForUpdate(forUpdateCheckBox.isSelected()); generatorConfig.setAnnotationDAO(annotationDAOCheckBox.isSelected()); generatorConfig.setAnnotation(annotationCheckBox.isSelected()); generatorConfig.setUseActualColumnNames(useActualColumnNamesCheckbox.isSelected()); generatorConfig.setEncoding(encodingChoice.getValue()); generatorConfig.setUseExample(useExample.isSelected()); generatorConfig.setUseDAOExtendStyle(useDAOExtendStyle.isSelected()); generatorConfig.setUseSchemaPrefix(useSchemaPrefix.isSelected()); generatorConfig.setJsr310Support(jsr310Support.isSelected()); return generatorConfig; } public void setGeneratorConfigIntoUI(GeneratorConfig generatorConfig) { projectFolderField.setText(generatorConfig.getProjectFolder()); modelTargetPackage.setText(generatorConfig.getModelPackage()); generateKeysField.setText(generatorConfig.getGenerateKeys()); modelTargetProject.setText(generatorConfig.getModelPackageTargetFolder()); daoTargetPackage.setText(generatorConfig.getDaoPackage()); daoTargetProject.setText(generatorConfig.getDaoTargetFolder()); mapperTargetPackage.setText(generatorConfig.getMappingXMLPackage()); mappingTargetProject.setText(generatorConfig.getMappingXMLTargetFolder()); if (StringUtils.isBlank(tableNameField.getText())) { tableNameField.setText(generatorConfig.getTableName()); mapperName.setText(generatorConfig.getMapperName()); domainObjectNameField.setText(generatorConfig.getDomainObjectName()); } offsetLimitCheckBox.setSelected(generatorConfig.isOffsetLimit()); commentCheckBox.setSelected(generatorConfig.isComment()); overrideXML.setSelected(generatorConfig.isOverrideXML()); needToStringHashcodeEquals.setSelected(generatorConfig.isNeedToStringHashcodeEquals()); useLombokPlugin.setSelected(generatorConfig.isUseLombokPlugin()); useTableNameAliasCheckbox.setSelected(generatorConfig.getUseTableNameAlias()); forUpdateCheckBox.setSelected(generatorConfig.isNeedForUpdate()); annotationDAOCheckBox.setSelected(generatorConfig.isAnnotationDAO()); annotationCheckBox.setSelected(generatorConfig.isAnnotation()); useActualColumnNamesCheckbox.setSelected(generatorConfig.isUseActualColumnNames()); encodingChoice.setValue(generatorConfig.getEncoding()); useExample.setSelected(generatorConfig.isUseExample()); useDAOExtendStyle.setSelected(generatorConfig.isUseDAOExtendStyle()); useSchemaPrefix.setSelected(generatorConfig.isUseSchemaPrefix()); jsr310Support.setSelected(generatorConfig.isJsr310Support()); } @FXML public void openTableColumnCustomizationPage() { if (tableName == null) { AlertUtil.showWarnAlert("请先在左侧选择数据库表"); return; } SelectTableColumnController controller = (SelectTableColumnController) loadFXMLPage("定制列", FXMLPage.SELECT_TABLE_COLUMN, true); controller.setMainUIController(this); try { // If select same schema and another table, update table data if (!tableName.equals(controller.getTableName())) { List tableColumns = DbUtil.getTableColumns(selectedDatabaseConfig, tableName); controller.setColumnList(FXCollections.observableList(tableColumns)); controller.setTableName(tableName); } controller.showDialogStage(); } catch (Exception e) { _LOG.error(e.getMessage(), e); AlertUtil.showErrorAlert(e.getMessage()); } } public void setIgnoredColumns(List ignoredColumns) { this.ignoredColumns = ignoredColumns; } public void setColumnOverrides(List columnOverrides) { this.columnOverrides = columnOverrides; } /** * 检查并创建不存在的文件夹 * * @return */ private boolean checkDirs(GeneratorConfig config) { List dirs = new ArrayList<>(); dirs.add(config.getProjectFolder()); dirs.add(config.getProjectFolder().concat("/").concat(config.getModelPackageTargetFolder())); dirs.add(config.getProjectFolder().concat("/").concat(config.getDaoTargetFolder())); dirs.add(config.getProjectFolder().concat("/").concat(config.getMappingXMLTargetFolder())); boolean haveNotExistFolder = false; for (String dir : dirs) { File file = new File(dir); if (!file.exists()) { haveNotExistFolder = true; } } if (haveNotExistFolder) { Alert alert = new Alert(Alert.AlertType.CONFIRMATION); alert.setContentText(FOLDER_NO_EXIST); Optional optional = alert.showAndWait(); if (optional.isPresent()) { if (ButtonType.OK == optional.get()) { try { for (String dir : dirs) { FileUtils.forceMkdir(new File(dir)); } return true; } catch (Exception e) { AlertUtil.showErrorAlert("创建目录失败,请检查目录是否是文件而非目录"); } } else { return false; } } } return true; } @FXML public void openTargetFolder() { GeneratorConfig generatorConfig = getGeneratorConfigFromUI(); String projectFolder = generatorConfig.getProjectFolder(); try { Desktop.getDesktop().browse(new File(projectFolder).toURI()); }catch (Exception e) { AlertUtil.showErrorAlert("打开目录失败,请检查目录是否填写正确" + e.getMessage()); } } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/controller/OverSshController.java ================================================ package com.zzg.mybatis.generator.controller; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; import com.zzg.mybatis.generator.model.DatabaseConfig; import com.zzg.mybatis.generator.util.ConfigHelper; import com.zzg.mybatis.generator.util.DbUtil; import com.zzg.mybatis.generator.view.AlertUtil; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.ChoiceBox; import javafx.scene.control.Label; import javafx.scene.control.PasswordField; import javafx.scene.control.TextField; import javafx.scene.layout.HBox; import javafx.scene.paint.Paint; import javafx.stage.FileChooser; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.net.URL; import java.util.ResourceBundle; import java.util.concurrent.*; /** * Project: mybatis-generator-gui * * @author slankka on 2018/12/30. */ public class OverSshController extends DbConnectionController { private Logger logger = LoggerFactory.getLogger(OverSshController.class); @FXML public HBox pubkeyBox; @FXML public Label lPortLabel; @FXML public TextField sshUserField; @FXML public ChoiceBox authTypeChoice; @FXML public Label sshPasswordLabel; @FXML public PasswordField sshPasswordField; @FXML private TextField sshHostField; @FXML private TextField sshdPortField; @FXML private TextField lportField; @FXML private TextField rportField; @FXML private Label note; @FXML private Label pubkeyBoxLabel; @FXML private TextField sshPubKeyField; @FXML public PasswordField sshPubkeyPasswordField; @FXML public Label sshPubkeyPasswordLabel; @FXML public Label sshPubkeyPasswordNote; private FileChooser fileChooser = new FileChooser(); private File privateKey; @Override public void initialize(URL location, ResourceBundle resources) { fileChooser.setTitle("选择SSH秘钥文件"); fileChooser.setInitialDirectory(new File(System.getProperty("user.home"))); authTypeChoice.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { if ("PubKey".equals(newValue)) { //公钥认证 sshPasswordField.setVisible(false); sshPasswordLabel.setVisible(false); pubkeyBox.setVisible(true); pubkeyBoxLabel.setVisible(true); sshPubkeyPasswordField.setVisible(true); sshPubkeyPasswordLabel.setVisible(true); sshPubkeyPasswordNote.setVisible(true); }else { //密码认证 pubkeyBox.setVisible(false); pubkeyBoxLabel.setVisible(false); sshPubkeyPasswordField.setVisible(false); sshPubkeyPasswordLabel.setVisible(false); sshPubkeyPasswordNote.setVisible(false); sshPasswordLabel.setVisible(true); sshPasswordField.setVisible(true); } }); } public void setDbConnectionConfig(DatabaseConfig databaseConfig) { if (databaseConfig == null) { return; } isUpdate = true; super.setConfig(databaseConfig); this.sshdPortField.setText(databaseConfig.getSshPort()); this.sshHostField.setText(databaseConfig.getSshHost()); this.lportField.setText(databaseConfig.getLport()); this.rportField.setText(databaseConfig.getRport()); this.sshUserField.setText(databaseConfig.getSshUser()); this.sshPasswordField.setText(databaseConfig.getSshPassword()); //例如:默认从本机的 3306 -> 转发到 3306 if (StringUtils.isBlank(this.lportField.getText())) { this.lportField.setText(databaseConfig.getPort()); } if (StringUtils.isBlank(this.rportField.getText())) { this.rportField.setText(databaseConfig.getPort()); } if (StringUtils.isNotBlank(databaseConfig.getPrivateKey())) { this.sshPubKeyField.setText(databaseConfig.getPrivateKey()); this.sshPubkeyPasswordField.setText(databaseConfig.getPrivateKeyPassword()); authTypeChoice.getSelectionModel().select("PubKey"); } checkInput(); } @FXML public void checkInput() { DatabaseConfig databaseConfig = extractConfigFromUi(); if (authTypeChoice.getValue().equals("Password") && ( StringUtils.isBlank(databaseConfig.getSshHost()) || StringUtils.isBlank(databaseConfig.getSshPort()) || StringUtils.isBlank(databaseConfig.getSshUser()) || StringUtils.isBlank(databaseConfig.getSshPassword()) ) || authTypeChoice.getValue().equals("PubKey") && ( StringUtils.isBlank(databaseConfig.getSshHost()) || StringUtils.isBlank(databaseConfig.getSshPort()) || StringUtils.isBlank(databaseConfig.getSshUser()) || StringUtils.isBlank(databaseConfig.getPrivateKey()) ) ) { note.setText("当前SSH配置输入不完整,OVER SSH不生效"); note.setTextFill(Paint.valueOf("#ff666f")); } else { note.setText("当前SSH配置生效"); note.setTextFill(Paint.valueOf("#5da355")); } } public void setLPortLabelText(String text) { lPortLabel.setText(text); } public void recoverNotice() { this.lPortLabel.setText("注意不要填写被其他程序占用的端口"); } public DatabaseConfig extractConfigFromUi() { String name = nameField.getText(); String host = hostField.getText(); String port = portField.getText(); String userName = userNameField.getText(); String password = passwordField.getText(); String encoding = encodingChoice.getValue(); String dbType = dbTypeChoice.getValue(); String schema = schemaField.getText(); String authType = authTypeChoice.getValue(); DatabaseConfig config = new DatabaseConfig(); config.setName(name); config.setDbType(dbType); config.setHost(host); config.setPort(port); config.setUsername(userName); config.setPassword(password); config.setSchema(schema); config.setEncoding(encoding); config.setSshHost(this.sshHostField.getText()); config.setSshPort(this.sshdPortField.getText()); config.setLport(this.lportField.getText()); config.setRport(this.rportField.getText()); config.setSshUser(this.sshUserField.getText()); config.setSshPassword(this.sshPasswordField.getText()); if ("PubKey".equals(authType)) { config.setPrivateKey(this.privateKey.getAbsolutePath()); config.setPrivateKeyPassword(this.sshPubkeyPasswordField.getText()); } return config; } public void saveConfig() { DatabaseConfig databaseConfig = extractConfigFromUi(); if (StringUtils.isAnyEmpty( databaseConfig.getName(), databaseConfig.getHost(), databaseConfig.getPort(), databaseConfig.getUsername(), databaseConfig.getEncoding(), databaseConfig.getDbType(), databaseConfig.getSchema())) { AlertUtil.showWarnAlert("密码以外其他字段必填"); return; } try { ConfigHelper.saveDatabaseConfig(this.isUpdate, primayKey, databaseConfig); this.tabPaneController.getDialogStage().close(); mainUIController.loadLeftDBTree(); } catch (Exception e) { logger.error(e.getMessage(), e); AlertUtil.showErrorAlert(e.getMessage()); } } @FXML public void testSSH() { Session session = DbUtil.getSSHSession(extractConfigFromUi()); if (session == null) { AlertUtil.showErrorAlert("请检查主机,端口,用户名,以及密码/秘钥是否填写正确"); return; } ExecutorService executorService = Executors.newSingleThreadExecutor(); Future result = executorService.submit(() -> { try { session.connect(); } catch (JSchException e) { logger.error("Connect Over SSH failed", e); throw new RuntimeException(e.getMessage()); } }); executorService.shutdown(); try { boolean b = executorService.awaitTermination(5, TimeUnit.SECONDS); if (!b) { throw new TimeoutException("连接超时"); } result.get(); AlertUtil.showInfoAlert("连接SSH服务器成功,恭喜你可以使用OverSSH功能"); recoverNotice(); } catch (Exception e) { AlertUtil.showErrorAlert("请检查主机,端口,用户名,以及密码/秘钥是否填写正确: " + e.getMessage()); } finally { DbUtil.shutdownPortForwarding(session); } } @FXML public void reset(ActionEvent actionEvent) { this.sshUserField.clear(); this.sshPasswordField.clear(); this.sshdPortField.clear(); this.sshHostField.clear(); this.lportField.clear(); this.rportField.clear(); this.sshPubKeyField.clear(); recoverNotice(); } public void choosePubKey(ActionEvent actionEvent) { this.privateKey = fileChooser.showOpenDialog(getDialogStage()); sshPubKeyField.setText(this.privateKey.getAbsolutePath()); } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/controller/PictureProcessStateController.java ================================================ package com.zzg.mybatis.generator.controller; import javafx.animation.RotateTransition; import javafx.animation.Timeline; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.scene.text.Font; import javafx.scene.text.Text; import javafx.stage.Modality; import javafx.stage.Stage; import javafx.stage.StageStyle; import javafx.util.Duration; import static javafx.scene.paint.Color.DARKSEAGREEN; public class PictureProcessStateController { private ImageView dbImage = new ImageView("icons/SSH_tunnel.png"); private final Rectangle rect = new Rectangle(20, 20, 30, 30); private final RotateTransition rotateTransition = new RotateTransition(); private final Text text = new Text(""); private final Stage dialogStage = new Stage(StageStyle.TRANSPARENT); private double initX; private double initY; private Stage parentStage; private final Button button = new Button(""); public void setDialogStage(Stage stage) { this.parentStage = stage; } public void startPlay() { dbImage.setFitHeight(192); dbImage.setFitWidth(798); Group rootGroup = new Group(); Scene scene = new Scene(rootGroup, 800, 212, Color.TRANSPARENT); dialogStage.initModality(Modality.APPLICATION_MODAL); dialogStage.setScene(scene); dialogStage.initOwner(parentStage); dialogStage.centerOnScreen(); dialogStage.setTitle("OverSSH"); rect.setArcHeight(10); rect.setArcWidth(10); rect.setFill(DARKSEAGREEN); rotateTransition.setNode(rect); rotateTransition.setDuration(Duration.seconds(0.8d)); rotateTransition.setFromAngle(0); rotateTransition.setToAngle(720); rotateTransition.setCycleCount(Timeline.INDEFINITE); rotateTransition.setAutoReverse(true); VBox vBoxRect = new VBox(); vBoxRect.setAlignment(Pos.TOP_CENTER); vBoxRect.getChildren().add(rect); VBox.setMargin(rect, new Insets(125, 0, 0, 350)); rotateTransition.play(); text.setFont(Font.font(12)); VBox vBoxLabel = new VBox(); vBoxLabel.getChildren().add(text); VBox.setMargin(text, new Insets(175, 0, 15, 40)); button.setPrefSize(90, 40); HBox hBoxButton = new HBox(); hBoxButton.setPrefSize(505, 170); hBoxButton.getChildren().add(button); hBoxButton.setAlignment(Pos.BOTTOM_RIGHT); hBoxButton.getStylesheets().add(Thread.currentThread().getContextClassLoader().getResource("style.css").toExternalForm()); HBox.setMargin(button, new Insets(0, 15, 5, 0)); button.setStyle("-fx-border-width: 0px;"); button.setStyle("-fx-border-color: transparent;"); button.setStyle("-fx-background-color: transparent;"); rootGroup.getChildren().addAll(dbImage, vBoxRect, vBoxLabel, hBoxButton); dialogStage.show(); button.setOnMouseClicked((event) -> dialogStage.close()); rootGroup.setOnMousePressed((me) -> { initX = me.getScreenX() - dialogStage.getX(); initY = me.getScreenY() - dialogStage.getY(); }); rootGroup.setOnMouseDragged((me) -> { dialogStage.setX(me.getScreenX() - initX); dialogStage.setY(me.getScreenY() - initY); }); } public void playFailState(String message, boolean showButton) { rect.setFill(Color.ORANGERED); rotateTransition.stop(); dbImage.setImage(new Image("icons/SSH_tunnel_disconnected.png")); rotateTransition.setDuration(Duration.seconds(3)); rotateTransition.play(); text.setText(message); if (showButton) { showCloseButton(); } if (!dialogStage.isShowing()) { dialogStage.show(); } } private void showCloseButton() { button.getStyleClass().add("btn"); button.getStyleClass().add("btn-default"); button.setStyle("-fx-border-width: 1px;"); button.setStyle("-fx-background-color: #fff;"); button.setText("我知道了"); } public void playSuccessState(String message, boolean showButton) { rect.setFill(DARKSEAGREEN); rotateTransition.stop(); dbImage.setImage(new Image("icons/SSH_tunnel.png")); rotateTransition.setDuration(Duration.seconds(0.8)); rotateTransition.play(); text.setText(message); if (showButton) { showCloseButton(); } } public void close() { dialogStage.close(); } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/controller/SelectTableColumnController.java ================================================ package com.zzg.mybatis.generator.controller; import com.zzg.mybatis.generator.model.UITableColumnVO; import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.cell.CheckBoxTableCell; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.control.cell.TextFieldTableCell; import org.mybatis.generator.config.ColumnOverride; import org.mybatis.generator.config.IgnoredColumn; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.ResourceBundle; /** * Created by Owen on 6/20/16. */ public class SelectTableColumnController extends BaseFXController { @FXML private TableView columnListView; @FXML private TableColumn checkedColumn; @FXML private TableColumn columnNameColumn; @FXML private TableColumn jdbcTypeColumn; @FXML private TableColumn javaTypeColumn; @FXML private TableColumn propertyNameColumn; @FXML private TableColumn typeHandlerColumn; private MainUIController mainUIController; private String tableName; @Override public void initialize(URL location, ResourceBundle resources) { // cellvaluefactory checkedColumn.setCellValueFactory(new PropertyValueFactory<>("checked")); columnNameColumn.setCellValueFactory(new PropertyValueFactory<>("columnName")); jdbcTypeColumn.setCellValueFactory(new PropertyValueFactory<>("jdbcType")); propertyNameColumn.setCellValueFactory(new PropertyValueFactory<>("propertyName")); typeHandlerColumn.setCellValueFactory(new PropertyValueFactory<>("typeHandler")); // Cell Factory that customize how the cell should render checkedColumn.setCellFactory(CheckBoxTableCell.forTableColumn(checkedColumn)); jdbcTypeColumn.setCellFactory(TextFieldTableCell.forTableColumn()); // handle commit event to save the user input data jdbcTypeColumn.setOnEditCommit(event -> { event.getTableView().getItems().get(event.getTablePosition().getRow()).setJdbcType(event.getNewValue()); }); javaTypeColumn.setCellFactory(TextFieldTableCell.forTableColumn()); // handle commit event to save the user input data javaTypeColumn.setOnEditCommit(event -> { event.getTableView().getItems().get(event.getTablePosition().getRow()).setJavaType(event.getNewValue()); }); propertyNameColumn.setCellFactory(TextFieldTableCell.forTableColumn()); propertyNameColumn.setOnEditCommit(event -> { event.getTableView().getItems().get(event.getTablePosition().getRow()).setPropertyName(event.getNewValue()); }); typeHandlerColumn.setCellFactory(TextFieldTableCell.forTableColumn()); typeHandlerColumn.setOnEditCommit(event -> { event.getTableView().getItems().get(event.getTablePosition().getRow()).setTypeHandle(event.getNewValue()); }); } @FXML public void ok() { ObservableList items = columnListView.getItems(); if (items != null && items.size() > 0) { List ignoredColumns = new ArrayList<>(); List columnOverrides = new ArrayList<>(); items.stream().forEach(item -> { if (!item.getChecked()) { IgnoredColumn ignoredColumn = new IgnoredColumn(item.getColumnName()); ignoredColumns.add(ignoredColumn); } else if (item.getTypeHandle() != null || item.getJavaType() != null || item.getPropertyName() != null) { // unchecked and have typeHandler value ColumnOverride columnOverride = new ColumnOverride(item.getColumnName()); columnOverride.setTypeHandler(item.getTypeHandle()); columnOverride.setJdbcType(item.getJdbcType()); columnOverride.setJavaProperty(item.getPropertyName()); columnOverride.setJavaType(item.getJavaType()); columnOverrides.add(columnOverride); } }); mainUIController.setIgnoredColumns(ignoredColumns); mainUIController.setColumnOverrides(columnOverrides); } getDialogStage().close(); } @FXML public void cancel() { getDialogStage().close(); } @FXML public void configAction() { TableColumnConfigsController controller = (TableColumnConfigsController) loadFXMLPage("定制列配置", FXMLPage.TABLE_COLUMN_CONFIG,true); controller.setColumnListView(this.columnListView); controller.setTableName(this.tableName); controller.showDialogStage(); } public void setColumnList(ObservableList columns) { columnListView.setItems(columns); } public void setMainUIController(MainUIController mainUIController) { this.mainUIController = mainUIController; } public String getTableName() { return tableName; } public void setTableName(String tableName) { this.tableName = tableName; } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/controller/TabPaneController.java ================================================ package com.zzg.mybatis.generator.controller; import com.jcraft.jsch.Session; import com.zzg.mybatis.generator.model.DatabaseConfig; import com.zzg.mybatis.generator.util.DbUtil; import com.zzg.mybatis.generator.view.AlertUtil; import javafx.concurrent.Task; import javafx.fxml.FXML; import javafx.scene.control.TabPane; import javafx.scene.layout.AnchorPane; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.EOFException; import java.net.URL; import java.util.ResourceBundle; /** * Project: mybatis-generator-gui * * @author github.com/slankka on 2019/1/22. */ public class TabPaneController extends BaseFXController { private static Logger logger = LoggerFactory.getLogger(TabPaneController.class); @FXML private TabPane tabPane; @FXML private DbConnectionController tabControlAController; @FXML private OverSshController tabControlBController; private boolean isOverssh; private MainUIController mainUIController; @Override public void initialize(URL location, ResourceBundle resources) { tabPane.setPrefHeight(((AnchorPane) tabPane.getSelectionModel().getSelectedItem().getContent()).getPrefHeight()); tabPane.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { isOverssh = observable.getValue().getText().equals("SSH"); tabPane.prefHeightProperty().bind(((AnchorPane) tabPane.getSelectionModel().getSelectedItem().getContent()).prefHeightProperty()); getDialogStage().close(); getDialogStage().show(); }); } public void setMainUIController(MainUIController mainUIController) { this.mainUIController = mainUIController; this.tabControlAController.setMainUIController(mainUIController); this.tabControlAController.setTabPaneController(this); this.tabControlBController.setMainUIController(mainUIController); this.tabControlBController.setTabPaneController(this); } public void setConfig(DatabaseConfig selectedConfig) { tabControlAController.setConfig(selectedConfig); tabControlBController.setDbConnectionConfig(selectedConfig); if (StringUtils.isNoneBlank( selectedConfig.getSshHost(), selectedConfig.getSshPassword(), selectedConfig.getSshPort(), selectedConfig.getSshUser(), selectedConfig.getLport())) { logger.info("Found SSH based Config"); tabPane.getSelectionModel().selectLast(); } } private DatabaseConfig extractConfigForUI() { if (isOverssh) { return tabControlBController.extractConfigFromUi(); } else { return tabControlAController.extractConfigForUI(); } } @FXML void saveConnection() { if (isOverssh) { tabControlBController.saveConfig(); } else { tabControlAController.saveConnection(); } } @FXML void testConnection() { DatabaseConfig config = extractConfigForUI(); if (config == null) { return; } if (StringUtils.isAnyEmpty(config.getName(), config.getHost(), config.getPort(), config.getUsername(), config.getEncoding(), config.getDbType(), config.getSchema())) { AlertUtil.showWarnAlert("密码以外其他字段必填"); return; } Session sshSession = DbUtil.getSSHSession(config); if (isOverssh && sshSession != null) { PictureProcessStateController pictureProcessState = new PictureProcessStateController(); pictureProcessState.setDialogStage(getDialogStage()); pictureProcessState.startPlay(); //如果不用异步,则视图会等方法返回才会显示 Task task = new Task() { @Override protected Void call() throws Exception { DbUtil.engagePortForwarding(sshSession, config); DbUtil.getConnection(config); return null; } }; task.setOnFailed(event -> { Throwable e = task.getException(); logger.error("task Failed", e); if (e instanceof RuntimeException) { if (e.getMessage().equals("Address already in use: JVM_Bind")) { tabControlBController.setLPortLabelText(config.getLport() + "已经被占用,请换其他端口"); } //端口转发一定不成功,导致数据库连接不上 pictureProcessState.playFailState("连接失败:" + e.getMessage(), true); return; } if (e.getCause() instanceof EOFException) { pictureProcessState.playFailState("连接失败, 请检查数据库的主机名,并且检查端口和目标端口是否一致", true); //端口转发已经成功,但是数据库连接不上,故需要释放连接 DbUtil.shutdownPortForwarding(sshSession); return; } pictureProcessState.playFailState("连接失败:" + e.getMessage(), true); //可能是端口转发已经成功,但是数据库连接不上,故需要释放连接 DbUtil.shutdownPortForwarding(sshSession); }); task.setOnSucceeded(event -> { try { pictureProcessState.playSuccessState("连接成功", true); DbUtil.shutdownPortForwarding(sshSession); tabControlBController.recoverNotice(); } catch (Exception e) { logger.error("", e); } }); new Thread(task).start(); } else { try { DbUtil.getConnection(config); AlertUtil.showInfoAlert("连接成功"); } catch (RuntimeException e) { logger.error("", e); AlertUtil.showWarnAlert("连接失败, " + e.getMessage()); } catch (Exception e) { logger.error(e.getMessage(), e); AlertUtil.showWarnAlert("连接失败"); } } } @FXML void cancel() { getDialogStage().close(); } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/controller/TableColumnConfigsController.java ================================================ package com.zzg.mybatis.generator.controller; import com.zzg.mybatis.generator.model.UITableColumnVO; import com.zzg.mybatis.generator.view.AlertUtil; import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.control.Label; import javafx.scene.control.TableView; import javafx.scene.control.TextField; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.mybatis.generator.internal.util.JavaBeansUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.URL; import java.util.ResourceBundle; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 定制列配置UI Controller * * @author xueqi * @date 2021-06-24 */ public class TableColumnConfigsController extends BaseFXController { private static final Logger _LOG = LoggerFactory.getLogger(TableColumnConfigsController.class); private static final String COL_NAME_PREFIX_REGEX = "(?<=%s)[^\"]+"; // pattern regex and split prefix: (?<=aggregate_|f_)[^"]+ f_ or d_ prefix private static final String OR_REGEX = "|"; @FXML private Label currentTableNameLabel; @FXML private TextField columnNamePrefixTextLabel; private TableView columnListView; private String tableName; @Override public void initialize(URL location, ResourceBundle resources) { // do nothing } @FXML public void cancel() { this.closeDialogStage(); } @FXML public void confirm() { try { // 1. generator bean propert name this.genProertyNameByColumnNamePrefix(); // close window this.closeDialogStage(); } catch (Exception e) { _LOG.error("confirm throw exception.", e); AlertUtil.showErrorAlert(e.getMessage()); } } public void setColumnListView(TableView columnListView) { this.columnListView = columnListView; } public void setTableName(String tableName) { this.tableName = tableName; currentTableNameLabel.setText(tableName); } private void genProertyNameByColumnNamePrefix() { String columnNamePrefix = this.columnNamePrefixTextLabel.getText(); if (StringUtils.isNotBlank(columnNamePrefix)) { if (StringUtils.endsWith(columnNamePrefix.trim(), OR_REGEX)) { columnNamePrefix = StringUtils.removeEnd(columnNamePrefix.trim(), OR_REGEX); } String regex = String.format(COL_NAME_PREFIX_REGEX, columnNamePrefix); _LOG.info("table:{}, column_name_prefix:{}, regex:{}", this.tableName, columnNamePrefix, regex); Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); ObservableList items = columnListView.getItems(); if (CollectionUtils.isNotEmpty(items)) { items.stream().forEach(item -> { String columnName = item.getColumnName(); Matcher matcher = pattern.matcher(columnName); if (matcher.find()) { // use first match result String regexColumnName = matcher.group(); if (StringUtils.isNotBlank(regexColumnName)) { String propertyName = JavaBeansUtil.getCamelCaseString(regexColumnName, false); _LOG.debug("table:{} column_name:{} regex_column_name:{} property_name:{}", tableName, columnName, regexColumnName, propertyName); if (StringUtils.isNotBlank(propertyName)) item.setPropertyName(propertyName); } else { _LOG.warn("table:{} column_name:{} regex_column_name is blank", tableName, columnName); } } else { // if not match, set property name is null item.setPropertyName(null); } }); } } } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/exception/DbDriverLoadingException.java ================================================ package com.zzg.mybatis.generator.exception; /** * 数据库驱动加载异常 * @Date 2017/8/15 21:46 * @Author jy */ public class DbDriverLoadingException extends RuntimeException{ public DbDriverLoadingException(String message){ super(message); } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/model/CachedFXMLLoader.java ================================================ package com.zzg.mybatis.generator.model; public class CachedFXMLLoader { } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/model/DatabaseConfig.java ================================================ package com.zzg.mybatis.generator.model; import java.util.Objects; /** * Created by Owen on 5/13/16. */ public class DatabaseConfig { /** * The primary key in the sqlite db */ private Integer id; private String dbType; /** * The name of the config */ private String name; private String host; private String port; private String schema; private String username; private String password; private String encoding; private String lport; private String rport; private String sshPort; private String sshHost; private String sshUser; private String sshPassword; private String privateKeyPassword; private String privateKey; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getHost() { return host; } public void setHost(String host) { this.host = host; } public String getPort() { return port; } public void setPort(String port) { this.port = port; } public String getSchema() { return schema; } public void setSchema(String schema) { this.schema = schema; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getEncoding() { return encoding; } public void setEncoding(String encoding) { this.encoding = encoding; } public String getDbType() { return dbType; } public void setDbType(String dbType) { this.dbType = dbType; } public String getLport() { return lport; } public void setLport(String lport) { this.lport = lport; } public String getRport() { return rport; } public void setRport(String rport) { this.rport = rport; } public String getSshPort() { return sshPort; } public void setSshPort(String sshPort) { this.sshPort = sshPort; } public String getSshHost() { return sshHost; } public void setSshHost(String sshHost) { this.sshHost = sshHost; } public String getSshUser() { return sshUser; } public void setSshUser(String sshUser) { this.sshUser = sshUser; } public String getSshPassword() { return sshPassword; } public void setSshPassword(String sshPassword) { this.sshPassword = sshPassword; } public String getPrivateKeyPassword() { return privateKeyPassword; } public void setPrivateKeyPassword(String privateKeyPassword) { this.privateKeyPassword = privateKeyPassword; } public String getPrivateKey() { return privateKey; } public void setPrivateKey(String privateKey) { this.privateKey = privateKey; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; DatabaseConfig that = (DatabaseConfig) o; return Objects.equals(id, that.id) && Objects.equals(dbType, that.dbType) && Objects.equals(name, that.name) && Objects.equals(host, that.host) && Objects.equals(port, that.port) && Objects.equals(schema, that.schema) && Objects.equals(username, that.username) && Objects.equals(password, that.password) && Objects.equals(encoding, that.encoding) && Objects.equals(lport, that.lport) && Objects.equals(rport, that.rport) && Objects.equals(sshPort, that.sshPort) && Objects.equals(sshHost, that.sshHost) && Objects.equals(sshUser, that.sshUser) && Objects.equals(sshPassword, that.sshPassword) && Objects.equals(privateKeyPassword, that.privateKeyPassword) && Objects.equals(privateKey, that.privateKey); } @Override public int hashCode() { return Objects.hash(id, dbType, name, host, port, schema, username, password, encoding, lport, rport, sshPort, sshHost, sshUser, sshPassword, privateKeyPassword, privateKey); } @Override public String toString() { return "DatabaseConfig{" + "id=" + id + ", dbType='" + dbType + '\'' + ", name='" + name + '\'' + ", host='" + host + '\'' + ", port='" + port + '\'' + ", schema='" + schema + '\'' + ", username='" + username + '\'' + ", password='" + password + '\'' + ", encoding='" + encoding + '\'' + ", lport='" + lport + '\'' + ", rport='" + rport + '\'' + ", sshPort='" + sshPort + '\'' + ", sshHost='" + sshHost + '\'' + ", sshUser='" + sshUser + '\'' + ", sshPassword='" + sshPassword + '\'' + '}'; } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/model/DatabaseDTO.java ================================================ package com.zzg.mybatis.generator.model; public class DatabaseDTO { private String name; private int value; private String driverClass; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } public String getDriverClass() { return driverClass; } public void setDriverClass(String driverClass) { this.driverClass = driverClass; } @Override public String toString() { return name; } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/model/DbType.java ================================================ package com.zzg.mybatis.generator.model; /** * Created by Owen on 6/14/16. */ public enum DbType { MySQL("com.mysql.jdbc.Driver", "jdbc:mysql://%s:%s/%s?useUnicode=true&useSSL=false&characterEncoding=%s", "mysql-connector-java-5.1.38.jar"), 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"), Oracle("oracle.jdbc.OracleDriver", "jdbc:oracle:thin:@//%s:%s/%s", "ojdbc6.jar"), PostgreSQL("org.postgresql.Driver", "jdbc:postgresql://%s:%s/%s", "postgresql-9.4.1209.jar"), SQL_Server("com.microsoft.sqlserver.jdbc.SQLServerDriver", "jdbc:sqlserver://%s:%s;databaseName=%s", "sqljdbc4-4.0.jar"), Sqlite("org.sqlite.JDBC", "jdbc:sqlite:%s", "sqlite-jdbc-3.19.3.jar"); private final String driverClass; private final String connectionUrlPattern; private final String connectorJarFile; DbType(String driverClass, String connectionUrlPattern, String connectorJarFile) { this.driverClass = driverClass; this.connectionUrlPattern = connectionUrlPattern; this.connectorJarFile = connectorJarFile; } public String getDriverClass() { return driverClass; } public String getConnectionUrlPattern() { return connectionUrlPattern; } public String getConnectorJarFile() { return connectorJarFile; } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/model/GeneratorConfig.java ================================================ package com.zzg.mybatis.generator.model; /** * * GeneratorConfig is the Config of mybatis generator config exclude database * config * * Created by Owen on 6/16/16. */ public class GeneratorConfig { /** * 本配置的名称 */ private String name; private String connectorJarPath; private String projectFolder; private String modelPackage; private String modelPackageTargetFolder; private String daoPackage; private String daoTargetFolder; private String mapperName; private String mappingXMLPackage; private String mappingXMLTargetFolder; private String tableName; private String domainObjectName; private boolean offsetLimit; private boolean comment; private boolean overrideXML; private boolean needToStringHashcodeEquals; private boolean useLombokPlugin; private boolean needForUpdate; private boolean annotationDAO; private boolean annotation; private boolean useActualColumnNames; private boolean useExample; private String generateKeys; private String encoding; private boolean useTableNameAlias; private boolean useDAOExtendStyle; private boolean useSchemaPrefix; private boolean jsr310Support; public boolean isJsr310Support() { return jsr310Support; } public void setJsr310Support(boolean jsr310Support) { this.jsr310Support = jsr310Support; } public boolean isUseSchemaPrefix() { return useSchemaPrefix; } public void setUseSchemaPrefix(boolean useSchemaPrefix) { this.useSchemaPrefix = useSchemaPrefix; } public boolean isUseExample() { return useExample; } public void setUseExample(boolean useExample) { this.useExample = useExample; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getTableName() { return tableName; } public void setTableName(String tableName) { this.tableName = tableName; } public String getDomainObjectName() { return domainObjectName; } public void setDomainObjectName(String domainObjectName) { this.domainObjectName = domainObjectName; } public String getConnectorJarPath() { return connectorJarPath; } public void setConnectorJarPath(String connectorJarPath) { this.connectorJarPath = connectorJarPath; } public String getProjectFolder() { return projectFolder; } public void setProjectFolder(String projectFolder) { this.projectFolder = projectFolder; } public String getModelPackage() { return modelPackage; } public void setModelPackage(String modelPackage) { this.modelPackage = modelPackage; } public String getModelPackageTargetFolder() { return modelPackageTargetFolder; } public void setModelPackageTargetFolder(String modelPackageTargetFolder) { this.modelPackageTargetFolder = modelPackageTargetFolder; } public String getDaoPackage() { return daoPackage; } public void setDaoPackage(String daoPackage) { this.daoPackage = daoPackage; } public String getDaoTargetFolder() { return daoTargetFolder; } public void setDaoTargetFolder(String daoTargetFolder) { this.daoTargetFolder = daoTargetFolder; } public String getMappingXMLPackage() { return mappingXMLPackage; } public void setMappingXMLPackage(String mappingXMLPackage) { this.mappingXMLPackage = mappingXMLPackage; } public String getMappingXMLTargetFolder() { return mappingXMLTargetFolder; } public void setMappingXMLTargetFolder(String mappingXMLTargetFolder) { this.mappingXMLTargetFolder = mappingXMLTargetFolder; } public boolean isOffsetLimit() { return offsetLimit; } public void setOffsetLimit(boolean offsetLimit) { this.offsetLimit = offsetLimit; } public boolean isComment() { return comment; } public void setComment(boolean comment) { this.comment = comment; } public boolean isNeedToStringHashcodeEquals() { return needToStringHashcodeEquals; } public void setNeedToStringHashcodeEquals(boolean needToStringHashcodeEquals) { this.needToStringHashcodeEquals = needToStringHashcodeEquals; } public boolean isUseLombokPlugin() { return useLombokPlugin; } public void setUseLombokPlugin(boolean useLombokPlugin) { this.useLombokPlugin = useLombokPlugin; } public boolean isNeedForUpdate() { return needForUpdate; } public void setNeedForUpdate(boolean needForUpdate) { this.needForUpdate = needForUpdate; } public boolean isAnnotationDAO() { return annotationDAO; } public void setAnnotationDAO(boolean annotationDAO) { this.annotationDAO = annotationDAO; } public boolean isAnnotation() { return annotation; } public void setAnnotation(boolean annotation) { this.annotation = annotation; } public boolean isUseActualColumnNames() { return useActualColumnNames; } public void setUseActualColumnNames(boolean useActualColumnNames) { this.useActualColumnNames = useActualColumnNames; } public String getMapperName() { return mapperName; } public void setMapperName(String mapperName) { this.mapperName = mapperName; } public String getGenerateKeys() { return generateKeys; } public void setGenerateKeys(String generateKeys) { this.generateKeys = generateKeys; } public String getEncoding() { return encoding; } public void setEncoding(String encoding) { this.encoding = encoding; } public boolean getUseTableNameAlias() { return useTableNameAlias; } public void setUseTableNameAlias(boolean useTableNameAlias) { this.useTableNameAlias = useTableNameAlias; } public boolean isUseTableNameAlias() { return useTableNameAlias; } public boolean isOverrideXML() { return overrideXML; } public void setOverrideXML(boolean overrideXML) { this.overrideXML = overrideXML; } public void setUseDAOExtendStyle(boolean useDAOExtendStyle) { this.useDAOExtendStyle = useDAOExtendStyle; } public boolean isUseDAOExtendStyle() { return useDAOExtendStyle; } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/model/UITableColumnVO.java ================================================ package com.zzg.mybatis.generator.model; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; /** * Created by Owen on 6/22/16. */ public class UITableColumnVO { private BooleanProperty checked = new SimpleBooleanProperty(true); // Default set to true private StringProperty columnName = new SimpleStringProperty(); private StringProperty javaType = new SimpleStringProperty(); private StringProperty jdbcType = new SimpleStringProperty(); private StringProperty propertyName = new SimpleStringProperty(); private StringProperty typeHandle = new SimpleStringProperty(); public String getColumnName() { return columnName.get(); } public void setColumnName(String columnName) { this.columnName.set(columnName); } public String getJdbcType() { return jdbcType.get(); } public void setJdbcType(String jdbcType) { this.jdbcType.set(jdbcType); } public String getPropertyName() { return propertyName.get(); } public void setPropertyName(String propertyName) { this.propertyName.set(propertyName); } public BooleanProperty checkedProperty() { return checked; } public Boolean getChecked() { return this.checked.get(); } public void setChecked(Boolean checked) { this.checked.set(checked); } public StringProperty typeHandleProperty() { return typeHandle; } public String getTypeHandle() { return typeHandle.get(); } public void setTypeHandle(String typeHandle) { this.typeHandle.set(typeHandle); } public StringProperty columnNameProperty() { return columnName; } public StringProperty jdbcTypeProperty() { return jdbcType; } public StringProperty propertyNameProperty() { return propertyName; } public String getJavaType() { return javaType.get(); } public StringProperty javaTypeProperty() { return javaType; } public void setJavaType(String javaType) { this.javaType.set(javaType); } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/plugins/CommonDAOInterfacePlugin.java ================================================ package com.zzg.mybatis.generator.plugins; import org.mybatis.generator.api.*; import org.mybatis.generator.api.dom.java.*; import org.mybatis.generator.exception.ShellException; import org.mybatis.generator.internal.DefaultShellCallback; import java.io.File; import java.util.ArrayList; import java.util.List; import static org.mybatis.generator.internal.util.StringUtility.stringHasValue; /** * Project: mybatis-generator-gui * * @author slankka on 2018/3/11. */ public class CommonDAOInterfacePlugin extends PluginAdapter { private static final String DEFAULT_DAO_SUPER_CLASS = ".MyBatisBaseDao"; private static final FullyQualifiedJavaType SERIALIZEBLE_TYPE = new FullyQualifiedJavaType("java.io.Serializable"); private List methods = new ArrayList<>(); private ShellCallback shellCallback = null; public CommonDAOInterfacePlugin() { shellCallback = new DefaultShellCallback(false); } private boolean isUseExample() { return "true".equals(getProperties().getProperty("useExample")); } @Override public List contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) { boolean hasPk = introspectedTable.hasPrimaryKeyColumns(); JavaFormatter javaFormatter = context.getJavaFormatter(); String daoTargetDir = context.getJavaClientGeneratorConfiguration().getTargetProject(); String daoTargetPackage = context.getJavaClientGeneratorConfiguration().getTargetPackage(); List mapperJavaFiles = new ArrayList<>(); String javaFileEncoding = context.getProperty("javaFileEncoding"); Interface mapperInterface = new Interface(daoTargetPackage + DEFAULT_DAO_SUPER_CLASS); if (stringHasValue(daoTargetPackage)) { mapperInterface.addImportedType(SERIALIZEBLE_TYPE); mapperInterface.setVisibility(JavaVisibility.PUBLIC); mapperInterface.addJavaDocLine("/**"); mapperInterface.addJavaDocLine(" * " + "DAO公共基类,由MybatisGenerator自动生成请勿修改"); mapperInterface.addJavaDocLine(" * " + "@param The Model Class 这里是泛型不是Model类"); mapperInterface.addJavaDocLine(" * " + "@param The Primary Key Class 如果是无主键,则可以用Model来跳过,如果是多主键则是Key类"); if (isUseExample()) { mapperInterface.addJavaDocLine(" * " + "@param The Example Class"); } mapperInterface.addJavaDocLine(" */"); FullyQualifiedJavaType daoBaseInterfaceJavaType = mapperInterface.getType(); daoBaseInterfaceJavaType.addTypeArgument(new FullyQualifiedJavaType("Model")); daoBaseInterfaceJavaType.addTypeArgument(new FullyQualifiedJavaType("PK extends Serializable")); if (isUseExample()) { daoBaseInterfaceJavaType.addTypeArgument(new FullyQualifiedJavaType("E")); } if (!this.methods.isEmpty()) { for (Method method : methods) { mapperInterface.addMethod(method); } } List generatedJavaFiles = introspectedTable.getGeneratedJavaFiles(); for (GeneratedJavaFile generatedJavaFile : generatedJavaFiles) { CompilationUnit compilationUnit = generatedJavaFile.getCompilationUnit(); FullyQualifiedJavaType type = compilationUnit.getType(); String modelName = type.getShortName(); if (modelName.endsWith("DAO")) { } } GeneratedJavaFile mapperJavafile = new GeneratedJavaFile(mapperInterface, daoTargetDir, javaFileEncoding, javaFormatter); try { File mapperDir = shellCallback.getDirectory(daoTargetDir, daoTargetPackage); File mapperFile = new File(mapperDir, mapperJavafile.getFileName()); // 文件不存在 if (!mapperFile.exists()) { mapperJavaFiles.add(mapperJavafile); } } catch (ShellException e) { e.printStackTrace(); } } return mapperJavaFiles; } @Override public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { interfaze.addJavaDocLine("/**"); interfaze.addJavaDocLine(" * " + interfaze.getType().getShortName() + "继承基类"); interfaze.addJavaDocLine(" */"); String daoSuperClass = interfaze.getType().getPackageName() + DEFAULT_DAO_SUPER_CLASS; FullyQualifiedJavaType daoSuperType = new FullyQualifiedJavaType(daoSuperClass); String targetPackage = introspectedTable.getContext().getJavaModelGeneratorConfiguration().getTargetPackage(); String domainObjectName = introspectedTable.getTableConfiguration().getDomainObjectName(); FullyQualifiedJavaType baseModelJavaType = new FullyQualifiedJavaType(targetPackage + "." + domainObjectName); daoSuperType.addTypeArgument(baseModelJavaType); FullyQualifiedJavaType primaryKeyTypeJavaType = null; if (introspectedTable.getPrimaryKeyColumns().size() > 1) { primaryKeyTypeJavaType = new FullyQualifiedJavaType(targetPackage + "." + domainObjectName + "Key"); }else if(introspectedTable.hasPrimaryKeyColumns()){ primaryKeyTypeJavaType = introspectedTable.getPrimaryKeyColumns().get(0).getFullyQualifiedJavaType(); }else { primaryKeyTypeJavaType = baseModelJavaType; } daoSuperType.addTypeArgument(primaryKeyTypeJavaType); interfaze.addImportedType(primaryKeyTypeJavaType); if (isUseExample()) { String exampleType = introspectedTable.getExampleType(); FullyQualifiedJavaType exampleTypeJavaType = new FullyQualifiedJavaType(exampleType); daoSuperType.addTypeArgument(exampleTypeJavaType); interfaze.addImportedType(exampleTypeJavaType); } interfaze.addImportedType(baseModelJavaType); interfaze.addImportedType(daoSuperType); interfaze.addSuperInterface(daoSuperType); return true; } @Override public boolean validate(List list) { return true; } private void interceptExampleParam(Method method) { if (isUseExample()) { method.getParameters().clear(); method.addParameter(new Parameter(new FullyQualifiedJavaType("E"), "example")); methods.add(method); } } private void interceptPrimaryKeyParam(Method method) { method.getParameters().clear(); method.addParameter(new Parameter(new FullyQualifiedJavaType("PK"), "id")); methods.add(method); } private void interceptModelParam(Method method) { method.getParameters().clear(); method.addParameter(new Parameter(new FullyQualifiedJavaType("Model"), "record")); methods.add(method); } private void interceptModelAndExampleParam(Method method) { if (isUseExample()) { List parameters = method.getParameters(); if (parameters.size() == 1) { interceptExampleParam(method); }else{ method.getParameters().clear(); Parameter parameter1 = new Parameter(new FullyQualifiedJavaType("Model"), "record"); parameter1.addAnnotation("@Param(\"record\")"); method.addParameter(parameter1); Parameter parameter2 = new Parameter(new FullyQualifiedJavaType("E"), "example"); parameter2.addAnnotation("@Param(\"example\")"); method.addParameter(parameter2); methods.add(method); } } } @Override public boolean clientCountByExampleMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { // interface if (isUseExample()) { interceptExampleParam(method); } return false; } @Override public boolean clientDeleteByExampleMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { if (isUseExample()) { interceptExampleParam(method); } return false; } @Override public boolean clientDeleteByPrimaryKeyMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { interceptPrimaryKeyParam(method); return false; } @Override public boolean clientInsertMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { interceptModelParam(method); return false; } @Override public boolean clientSelectByExampleWithBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { if (isUseExample()) { interceptExampleParam(method); method.setReturnType(new FullyQualifiedJavaType("List")); } return false; } @Override public boolean clientSelectByExampleWithoutBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { if (isUseExample()) { interceptExampleParam(method); method.setReturnType(new FullyQualifiedJavaType("List")); } return false; } @Override public boolean clientSelectByPrimaryKeyMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { interceptPrimaryKeyParam(method); method.setReturnType(new FullyQualifiedJavaType("Model")); return false; } @Override public boolean clientUpdateByExampleSelectiveMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { if (isUseExample()) { interceptModelAndExampleParam(method); } return false; } @Override public boolean clientUpdateByExampleWithBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { if (isUseExample()) { interceptModelAndExampleParam(method); } return false; } @Override public boolean clientUpdateByExampleWithoutBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { if (isUseExample()) { interceptModelAndExampleParam(method); } return false; } @Override public boolean clientUpdateByPrimaryKeySelectiveMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { interceptModelParam(method); return false; } @Override public boolean clientUpdateByExampleWithoutBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { if (isUseExample()) { interceptModelAndExampleParam(method); } return false; } @Override public boolean clientUpdateByExampleSelectiveMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { if (isUseExample()) { interceptModelAndExampleParam(method); } return false; } @Override public boolean clientUpdateByPrimaryKeyWithBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { interceptModelParam(method); return false; } @Override public boolean clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated( Method method, Interface interfaze, IntrospectedTable introspectedTable) { interceptModelParam(method); return false; } @Override public boolean clientInsertSelectiveMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) { interceptModelParam(method); return false; } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/plugins/DbRemarksCommentGenerator.java ================================================ /* * Copyright 2008 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.zzg.mybatis.generator.plugins; import org.mybatis.generator.api.CommentGenerator; import org.mybatis.generator.api.IntrospectedColumn; import org.mybatis.generator.api.IntrospectedTable; import org.mybatis.generator.api.dom.java.*; import org.mybatis.generator.api.dom.xml.XmlElement; import org.mybatis.generator.internal.util.StringUtility; import java.util.Properties; import java.util.Set; import static org.mybatis.generator.internal.util.StringUtility.isTrue; /** * 此插件使用数据库表中列的注释来生成Java Model中属性的注释 * * @author Owen Zou * */ public class DbRemarksCommentGenerator implements CommentGenerator { private Properties properties; private boolean columnRemarks; private boolean isAnnotations; public DbRemarksCommentGenerator() { super(); properties = new Properties(); } public void addJavaFileComment(CompilationUnit compilationUnit) { // add no file level comments by default if (isAnnotations) { compilationUnit.addImportedType(new FullyQualifiedJavaType("javax.persistence.Table")); compilationUnit.addImportedType(new FullyQualifiedJavaType("javax.persistence.Id")); compilationUnit.addImportedType(new FullyQualifiedJavaType("javax.persistence.Column")); compilationUnit.addImportedType(new FullyQualifiedJavaType("javax.persistence.GeneratedValue")); compilationUnit.addImportedType(new FullyQualifiedJavaType("org.hibernate.validator.constraints.NotEmpty")); } } /** * Adds a suitable comment to warn users that the element was generated, and * when it was generated. */ public void addComment(XmlElement xmlElement) { } public void addRootComment(XmlElement rootElement) { // add no document level comments by default return; } @Override public void addGeneralMethodAnnotation(Method method, IntrospectedTable introspectedTable, Set set) { } @Override public void addGeneralMethodAnnotation(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn, Set set) { } @Override public void addFieldAnnotation(Field field, IntrospectedTable introspectedTable, Set set) { } @Override public void addFieldAnnotation(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn, Set set) { } @Override public void addClassAnnotation(InnerClass innerClass, IntrospectedTable introspectedTable, Set set) { } public void addConfigurationProperties(Properties properties) { this.properties.putAll(properties); columnRemarks = isTrue(properties .getProperty("columnRemarks")); isAnnotations = isTrue(properties .getProperty("annotations")); } public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable) { } public void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { topLevelClass.addJavaDocLine("/**"); topLevelClass.addJavaDocLine(" * @author "); topLevelClass.addJavaDocLine(" * " + introspectedTable.getRemarks()); topLevelClass.addJavaDocLine(" */"); if(isAnnotations) { topLevelClass.addAnnotation("@Table(name=\"" + introspectedTable.getFullyQualifiedTableNameAtRuntime() + "\")"); } } public void addEnumComment(InnerEnum innerEnum, IntrospectedTable introspectedTable) { } public void addFieldComment(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) { if (StringUtility.stringHasValue(introspectedColumn.getRemarks())) { field.addJavaDocLine("/**"); StringBuilder sb = new StringBuilder(); sb.append(" * "); sb.append(introspectedColumn.getRemarks()); field.addJavaDocLine(sb.toString()); field.addJavaDocLine(" */"); } if (isAnnotations) { boolean isId = false; for (IntrospectedColumn column : introspectedTable.getPrimaryKeyColumns()) { if (introspectedColumn == column) { isId = true; field.addAnnotation("@Id"); field.addAnnotation("@GeneratedValue"); break; } } if (!introspectedColumn.isNullable() && !isId){ field.addAnnotation("@NotEmpty"); } if (introspectedColumn.isIdentity()) { if (introspectedTable.getTableConfiguration().getGeneratedKey().getRuntimeSqlStatement().equals("JDBC")) { field.addAnnotation("@GeneratedValue(generator = \"JDBC\")"); } else { field.addAnnotation("@GeneratedValue(strategy = GenerationType.IDENTITY)"); } } else if (introspectedColumn.isSequenceColumn()) { field.addAnnotation("@SequenceGenerator(name=\"\",sequenceName=\"" + introspectedTable.getTableConfiguration().getGeneratedKey().getRuntimeSqlStatement() + "\")"); } } } public void addFieldComment(Field field, IntrospectedTable introspectedTable) { } public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable) { } public void addGetterComment(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) { } public void addSetterComment(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) { } public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable, boolean markAsDoNotDelete) { innerClass.addJavaDocLine("/**"); //$NON-NLS-1$ innerClass.addJavaDocLine(" */"); //$NON-NLS-1$ } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/plugins/JavaTypeResolverJsr310Impl.java ================================================ package com.zzg.mybatis.generator.plugins; import org.mybatis.generator.api.IntrospectedColumn; import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType; import org.mybatis.generator.internal.types.JavaTypeResolverDefaultImpl; import java.sql.Types; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; /** * @author hanakei * @since 2018/4/28 */ public class JavaTypeResolverJsr310Impl extends JavaTypeResolverDefaultImpl { @Override protected FullyQualifiedJavaType overrideDefaultType(IntrospectedColumn column, FullyQualifiedJavaType defaultType) { FullyQualifiedJavaType answer = defaultType; switch (column.getJdbcType()) { case Types.BIT: answer = calculateBitReplacement(column, defaultType); break; case Types.DECIMAL: case Types.NUMERIC: answer = calculateBigDecimalReplacement(column, defaultType); break; case Types.DATE: answer = new FullyQualifiedJavaType(LocalDate.class.getName()); break; case Types.TIME: answer = new FullyQualifiedJavaType(LocalTime.class.getName()); break; case Types.TIMESTAMP: answer = new FullyQualifiedJavaType(LocalDateTime.class.getName()); break; default: break; } return answer; } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/plugins/MySQLForUpdatePlugin.java ================================================ package com.zzg.mybatis.generator.plugins; import org.mybatis.generator.api.IntrospectedTable; import org.mybatis.generator.api.PluginAdapter; import org.mybatis.generator.api.dom.java.*; import org.mybatis.generator.api.dom.xml.Attribute; import org.mybatis.generator.api.dom.xml.TextElement; import org.mybatis.generator.api.dom.xml.XmlElement; import java.util.List; /** * Project: mybatis-generator-gui * * @author slankka on 2017/11/4. */ public class MySQLForUpdatePlugin extends PluginAdapter { @Override public boolean validate(List warnings) { return true; } @Override public boolean modelExampleClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { PrimitiveTypeWrapper booleanWrapper = FullyQualifiedJavaType.getBooleanPrimitiveInstance().getPrimitiveTypeWrapper(); Field forUpdate = new Field(); forUpdate.setName("forUpdate"); forUpdate.setVisibility(JavaVisibility.PRIVATE); forUpdate.setType(booleanWrapper); topLevelClass.addField(forUpdate); Method setForUpdate = new Method(); setForUpdate.setVisibility(JavaVisibility.PUBLIC); setForUpdate.setName("setForUpdate"); setForUpdate.addParameter(new Parameter(booleanWrapper, "forUpdate")); setForUpdate.addBodyLine("this.forUpdate = forUpdate;"); topLevelClass.addMethod(setForUpdate); Method getForUpdate = new Method(); getForUpdate.setVisibility(JavaVisibility.PUBLIC); getForUpdate.setReturnType(booleanWrapper); getForUpdate.setName("getForUpdate"); getForUpdate.addBodyLine("return forUpdate;"); topLevelClass.addMethod(getForUpdate); return true; } private void appendForUpdate(XmlElement element, IntrospectedTable introspectedTable) { XmlElement forUpdateElement = new XmlElement("if"); forUpdateElement.addAttribute(new Attribute("test", "forUpdate != null and forUpdate == true")); forUpdateElement.addElement(new TextElement("for update")); element.addElement(forUpdateElement); } @Override public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) { appendForUpdate(element, introspectedTable); return true; } @Override public boolean sqlMapSelectByExampleWithBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) { appendForUpdate(element, introspectedTable); return true; } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/plugins/MySQLLimitPlugin.java ================================================ package com.zzg.mybatis.generator.plugins; /** * Created by zouzhigang on 2016/6/14. */ import org.mybatis.generator.api.IntrospectedTable; import org.mybatis.generator.api.PluginAdapter; import org.mybatis.generator.api.dom.java.*; import org.mybatis.generator.api.dom.xml.Attribute; import org.mybatis.generator.api.dom.xml.TextElement; import org.mybatis.generator.api.dom.xml.XmlElement; import java.util.List; public class MySQLLimitPlugin extends PluginAdapter { @Override public boolean validate(List list) { return true; } /** * 为每个Example类添加limit和offset属性已经set、get方法 */ @Override public boolean modelExampleClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { PrimitiveTypeWrapper integerWrapper = FullyQualifiedJavaType.getIntInstance().getPrimitiveTypeWrapper(); PrimitiveTypeWrapper longWrapper = new FullyQualifiedJavaType("long").getPrimitiveTypeWrapper(); Field limit = new Field(); limit.setName("limit"); limit.setVisibility(JavaVisibility.PRIVATE); limit.setType(integerWrapper); topLevelClass.addField(limit); Method setLimit = new Method(); setLimit.setVisibility(JavaVisibility.PUBLIC); setLimit.setName("setLimit"); setLimit.addParameter(new Parameter(integerWrapper, "limit")); setLimit.addBodyLine("this.limit = limit;"); topLevelClass.addMethod(setLimit); Method getLimit = new Method(); getLimit.setVisibility(JavaVisibility.PUBLIC); getLimit.setReturnType(integerWrapper); getLimit.setName("getLimit"); getLimit.addBodyLine("return limit;"); topLevelClass.addMethod(getLimit); Field offset = new Field(); offset.setName("offset"); offset.setVisibility(JavaVisibility.PRIVATE); offset.setType(longWrapper); topLevelClass.addField(offset); Method setOffset = new Method(); setOffset.setVisibility(JavaVisibility.PUBLIC); setOffset.setName("setOffset"); setOffset.addParameter(new Parameter(longWrapper, "offset")); setOffset.addBodyLine("this.offset = offset;"); topLevelClass.addMethod(setOffset); Method getOffset = new Method(); getOffset.setVisibility(JavaVisibility.PUBLIC); getOffset.setReturnType(longWrapper); getOffset.setName("getOffset"); getOffset.addBodyLine("return offset;"); topLevelClass.addMethod(getOffset); return true; } /** * 为Mapper.xml的selectByExample添加limit */ @Override public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) { XmlElement ifLimitNotNullElement = new XmlElement("if"); ifLimitNotNullElement.addAttribute(new Attribute("test", "limit != null")); XmlElement ifOffsetNotNullElement = new XmlElement("if"); ifOffsetNotNullElement.addAttribute(new Attribute("test", "offset != null")); ifOffsetNotNullElement.addElement(new TextElement("limit ${offset}, ${limit}")); ifLimitNotNullElement.addElement(ifOffsetNotNullElement); XmlElement ifOffsetNullElement = new XmlElement("if"); ifOffsetNullElement.addAttribute(new Attribute("test", "offset == null")); ifOffsetNullElement.addElement(new TextElement("limit ${limit}")); ifLimitNotNullElement.addElement(ifOffsetNullElement); element.addElement(ifLimitNotNullElement); return true; } /** * 为Mapper.xml的selectByExampleWithBLOBs添加limit */ @Override public boolean sqlMapSelectByExampleWithBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) { XmlElement ifLimitNotNullElement = new XmlElement("if"); ifLimitNotNullElement.addAttribute(new Attribute("test", "limit != null")); XmlElement ifOffsetNotNullElement = new XmlElement("if"); ifOffsetNotNullElement.addAttribute(new Attribute("test", "offset != null")); ifOffsetNotNullElement.addElement(new TextElement("limit ${offset}, ${limit}")); ifLimitNotNullElement.addElement(ifOffsetNotNullElement); XmlElement ifOffsetNullElement = new XmlElement("if"); ifOffsetNullElement.addAttribute(new Attribute("test", "offset == null")); ifOffsetNullElement.addElement(new TextElement("limit ${limit}")); ifLimitNotNullElement.addElement(ifOffsetNullElement); element.addElement(ifLimitNotNullElement); return true; } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/plugins/RepositoryPlugin.java ================================================ package com.zzg.mybatis.generator.plugins; import org.mybatis.generator.api.IntrospectedTable; import org.mybatis.generator.api.PluginAdapter; import org.mybatis.generator.api.dom.java.*; import java.util.List; /** * Project: mybatis-generator-gui * * @author slankka on 2017/12/13. */ public class RepositoryPlugin extends PluginAdapter { private FullyQualifiedJavaType annotationRepository; private String annotation = "@Repository"; public RepositoryPlugin () { annotationRepository = new FullyQualifiedJavaType("org.springframework.stereotype.Repository"); //$NON-NLS-1$ } @Override public boolean validate(List list) { return true; } @Override public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { interfaze.addImportedType(annotationRepository); interfaze.addAnnotation(annotation); return true; } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/util/ConfigHelper.java ================================================ package com.zzg.mybatis.generator.util; import com.alibaba.fastjson.JSON; import com.zzg.mybatis.generator.model.DatabaseConfig; import com.zzg.mybatis.generator.model.DbType; import com.zzg.mybatis.generator.model.GeneratorConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLDecoder; import java.nio.charset.Charset; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; import java.util.ArrayList; import java.util.List; /** * XML based config file help class *

* Created by Owen on 6/16/16. */ public class ConfigHelper { private static final Logger _LOG = LoggerFactory.getLogger(ConfigHelper.class); private static final String BASE_DIR = "config"; private static final String CONFIG_FILE = "/sqlite3.db"; public static void createEmptyFiles() throws Exception { File file = new File(BASE_DIR); if (!file.exists()) { file.mkdir(); } File uiConfigFile = new File(BASE_DIR + CONFIG_FILE); if (!uiConfigFile.exists()) { createEmptyXMLFile(uiConfigFile); } } static void createEmptyXMLFile(File uiConfigFile) throws IOException { InputStream fis = null; FileOutputStream fos = null; try { fis = Thread.currentThread().getContextClassLoader().getResourceAsStream("sqlite3.db"); fos = new FileOutputStream(uiConfigFile); byte[] buffer = new byte[1024]; int byteread = 0; while ((byteread = fis.read(buffer)) != -1) { fos.write(buffer, 0, byteread); } } finally { if (fis != null) fis.close(); if (fos != null) fos.close(); } } public static List loadDatabaseConfig() throws Exception { Connection conn = null; Statement stat = null; ResultSet rs = null; try { conn = ConnectionManager.getConnection(); stat = conn.createStatement(); rs = stat.executeQuery("SELECT * FROM dbs"); List configs = new ArrayList<>(); while (rs.next()) { int id = rs.getInt("id"); String value = rs.getString("value"); DatabaseConfig databaseConfig = JSON.parseObject(value, DatabaseConfig.class); databaseConfig.setId(id); configs.add(databaseConfig); } return configs; } finally { if (rs != null) rs.close(); if (stat != null) stat.close(); if (conn != null) conn.close(); } } public static void saveDatabaseConfig(boolean isUpdate, Integer primaryKey, DatabaseConfig dbConfig) throws Exception { String configName = dbConfig.getName(); Connection conn = null; Statement stat = null; ResultSet rs = null; try { conn = ConnectionManager.getConnection(); stat = conn.createStatement(); if (!isUpdate) { ResultSet rs1 = stat.executeQuery("SELECT * from dbs where name = '" + configName + "'"); if (rs1.next()) { throw new RuntimeException("配置已经存在, 请使用其它名字"); } } String jsonStr = JSON.toJSONString(dbConfig); String sql; if (isUpdate) { sql = String.format("UPDATE dbs SET name = '%s', value = '%s' where id = %d", configName, jsonStr, primaryKey); } else { sql = String.format("INSERT INTO dbs (name, value) values('%s', '%s')", configName, jsonStr); } stat.executeUpdate(sql); } finally { if (rs != null) rs.close(); if (stat != null) stat.close(); if (conn != null) conn.close(); } } public static void deleteDatabaseConfig(DatabaseConfig databaseConfig) throws Exception { Connection conn = null; Statement stat = null; ResultSet rs = null; try { conn = ConnectionManager.getConnection(); stat = conn.createStatement(); String sql = String.format("delete from dbs where id=%d", databaseConfig.getId()); stat.executeUpdate(sql); } finally { if (rs != null) rs.close(); if (stat != null) stat.close(); if (conn != null) conn.close(); } } public static void saveGeneratorConfig(GeneratorConfig generatorConfig) throws Exception { Connection conn = null; Statement stat = null; ResultSet rs = null; try { conn = ConnectionManager.getConnection(); stat = conn.createStatement(); String jsonStr = JSON.toJSONString(generatorConfig); String sql = String.format("INSERT INTO generator_config values('%s', '%s')", generatorConfig.getName(), jsonStr); stat.executeUpdate(sql); } finally { if (rs != null) rs.close(); if (stat != null) stat.close(); if (conn != null) conn.close(); } } public static GeneratorConfig loadGeneratorConfig(String name) throws Exception { Connection conn = null; Statement stat = null; ResultSet rs = null; try { conn = ConnectionManager.getConnection(); stat = conn.createStatement(); String sql = String.format("SELECT * FROM generator_config where name='%s'", name); _LOG.info("sql: {}", sql); rs = stat.executeQuery(sql); GeneratorConfig generatorConfig = null; if (rs.next()) { String value = rs.getString("value"); generatorConfig = JSON.parseObject(value, GeneratorConfig.class); } return generatorConfig; } finally { if (rs != null) rs.close(); if (stat != null) stat.close(); if (conn != null) conn.close(); } } public static List loadGeneratorConfigs() throws Exception { Connection conn = null; Statement stat = null; ResultSet rs = null; try { conn = ConnectionManager.getConnection(); stat = conn.createStatement(); String sql = String.format("SELECT * FROM generator_config"); _LOG.info("sql: {}", sql); rs = stat.executeQuery(sql); List configs = new ArrayList<>(); while (rs.next()) { String value = rs.getString("value"); configs.add(JSON.parseObject(value, GeneratorConfig.class)); } return configs; } finally { if (rs != null) rs.close(); if (stat != null) stat.close(); if (conn != null) conn.close(); } } public static int deleteGeneratorConfig(String name) throws Exception { Connection conn = null; Statement stat = null; try { conn = ConnectionManager.getConnection(); stat = conn.createStatement(); String sql = String.format("DELETE FROM generator_config where name='%s'", name); _LOG.info("sql: {}", sql); return stat.executeUpdate(sql); } finally { if (stat != null) stat.close(); if (conn != null) conn.close(); } } public static String findConnectorLibPath(String dbType) { DbType type = DbType.valueOf(dbType); URL resource = Thread.currentThread().getContextClassLoader().getResource("logback.xml"); _LOG.info("jar resource: {}", resource); if (resource != null) { try { File file = new File(resource.toURI().getRawPath() + "/../lib/" + type.getConnectorJarFile()); return URLDecoder.decode(file.getCanonicalPath(), Charset.forName("UTF-8").displayName()); } catch (Exception e) { throw new RuntimeException("找不到驱动文件,请联系开发者"); } } else { throw new RuntimeException("lib can't find"); } } public static List getAllJDBCDriverJarPaths() { List jarFilePathList = new ArrayList<>(); URL url = Thread.currentThread().getContextClassLoader().getResource("logback.xml"); try { File file; if (url.getPath().contains(".jar")) { file = new File("lib/"); } else { file = new File("src/main/resources/lib"); } _LOG.info("jar lib path: {}", file.getCanonicalPath()); File[] jarFiles = file.listFiles(); if (jarFiles != null && jarFiles.length > 0) { for (File jarFile : jarFiles) { _LOG.info("jar file: {}", jarFile.getAbsolutePath()); if (jarFile.isFile() && jarFile.getAbsolutePath().endsWith(".jar")) { jarFilePathList.add(jarFile.getAbsolutePath()); } } } } catch (Exception e) { throw new RuntimeException("找不到驱动文件,请联系开发者"); } return jarFilePathList; } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/util/ConnectionManager.java ================================================ package com.zzg.mybatis.generator.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.sql.Connection; import java.sql.DriverManager; /** * Created by Owen on 8/21/16. */ public class ConnectionManager { private static final Logger _LOG = LoggerFactory.getLogger(ConnectionManager.class); private static final String DB_URL = "jdbc:sqlite:./config/sqlite3.db"; public static Connection getConnection() throws Exception { Class.forName("org.sqlite.JDBC"); File file = new File(DB_URL.substring("jdbc:sqlite:".length())).getAbsoluteFile(); _LOG.info("database FilePath :{}", file.getAbsolutePath()); Connection conn = DriverManager.getConnection(DB_URL); return conn; } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/util/DbUtil.java ================================================ package com.zzg.mybatis.generator.util; import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; import com.zzg.mybatis.generator.exception.DbDriverLoadingException; import com.zzg.mybatis.generator.model.DatabaseConfig; import com.zzg.mybatis.generator.model.DbType; import com.zzg.mybatis.generator.model.UITableColumnVO; import com.zzg.mybatis.generator.view.AlertUtil; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; import org.mybatis.generator.internal.util.ClassloaderUtility; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.sql.*; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; /** * Created by Owen on 6/12/16. */ public class DbUtil { private static final Logger _LOG = LoggerFactory.getLogger(DbUtil.class); private static final int DB_CONNECTION_TIMEOUTS_SECONDS = 1; private static Map drivers = new HashMap<>(); private static ExecutorService executorService = Executors.newSingleThreadExecutor(); private static volatile boolean portForwaring = false; private static Map portForwardingSession = new ConcurrentHashMap<>(); public static Session getSSHSession(DatabaseConfig databaseConfig) { if (StringUtils.isBlank(databaseConfig.getSshHost()) || StringUtils.isBlank(databaseConfig.getSshPort()) || StringUtils.isBlank(databaseConfig.getSshUser()) || (StringUtils.isBlank(databaseConfig.getPrivateKey()) && StringUtils.isBlank(databaseConfig.getSshPassword())) ) { return null; } Session session = null; try { //Set StrictHostKeyChecking property to no to avoid UnknownHostKey issue java.util.Properties config = new java.util.Properties(); config.put("StrictHostKeyChecking", "no"); JSch jsch = new JSch(); Integer sshPort = NumberUtils.createInteger(databaseConfig.getSshPort()); int port = sshPort == null ? 22 : sshPort; session = jsch.getSession(databaseConfig.getSshUser(), databaseConfig.getSshHost(), port); if (StringUtils.isNotBlank(databaseConfig.getPrivateKey())) { //使用秘钥方式认证 jsch.addIdentity(databaseConfig.getPrivateKey(), StringUtils.defaultIfBlank(databaseConfig.getPrivateKeyPassword(), null)); }else { session.setPassword(databaseConfig.getSshPassword()); } session.setConfig(config); }catch (JSchException e) { //Ignore } return session; } public static void engagePortForwarding(Session sshSession, DatabaseConfig config) { if (sshSession != null) { AtomicInteger assinged_port = new AtomicInteger(); Future result = executorService.submit(() -> { try { Integer localPort = NumberUtils.createInteger(config.getLport()); Integer RemotePort = NumberUtils.createInteger(config.getRport()); int lport = localPort == null ? Integer.parseInt(config.getPort()) : localPort; int rport = RemotePort == null ? Integer.parseInt(config.getPort()) : RemotePort; Session session = portForwardingSession.get(lport); if (session != null && session.isConnected()) { String s = session.getPortForwardingL()[0]; String[] split = StringUtils.split(s, ":"); boolean portForwarding = String.format("%s:%s", split[0], split[1]).equals(lport + ":" + config.getHost()); if (portForwarding) { return; } } sshSession.connect(); assinged_port.set(sshSession.setPortForwardingL(lport, config.getHost(), rport)); portForwardingSession.put(lport, sshSession); portForwaring = true; _LOG.info("portForwarding Enabled, {}", assinged_port); } catch (JSchException e) { _LOG.error("Connect Over SSH failed", e); if (e.getCause() != null && e.getCause().getMessage().equals("Address already in use: JVM_Bind")) { throw new RuntimeException("Address already in use: JVM_Bind"); } throw new RuntimeException(e.getMessage()); } }); try { result.get(5, TimeUnit.SECONDS); }catch (Exception e) { shutdownPortForwarding(sshSession); if (e.getCause() instanceof RuntimeException) { throw (RuntimeException)e.getCause(); } if (e instanceof TimeoutException) { throw new RuntimeException("OverSSH 连接超时:超过5秒"); } _LOG.info("executorService isShutdown:{}", executorService.isShutdown()); AlertUtil.showErrorAlert("OverSSH 失败,请检查连接设置:" + e.getMessage()); } } } public static void shutdownPortForwarding(Session session) { portForwaring = false; if (session != null && session.isConnected()) { session.disconnect(); _LOG.info("portForwarding turn OFF"); } // executorService.shutdown(); } public static Connection getConnection(DatabaseConfig config) throws ClassNotFoundException, SQLException { DbType dbType = DbType.valueOf(config.getDbType()); if (drivers.get(dbType) == null){ loadDbDriver(dbType); } String url = getConnectionUrlWithSchema(config); Properties props = new Properties(); props.setProperty("user", config.getUsername()); //$NON-NLS-1$ props.setProperty("password", config.getPassword()); //$NON-NLS-1$ DriverManager.setLoginTimeout(DB_CONNECTION_TIMEOUTS_SECONDS); Connection connection = drivers.get(dbType).connect(url, props); _LOG.info("getConnection, connection url: {}", connection); return connection; } public static List getTableNames(DatabaseConfig config, String filter) throws Exception { Session sshSession = getSSHSession(config); engagePortForwarding(sshSession, config); try (Connection connection = getConnection(config)) { List tables = new ArrayList<>(); DatabaseMetaData md = connection.getMetaData(); ResultSet rs; if (DbType.valueOf(config.getDbType()) == DbType.SQL_Server) { String sql = "select name from sysobjects where xtype='u' or xtype='v' order by name"; rs = connection.createStatement().executeQuery(sql); while (rs.next()) { tables.add(rs.getString("name")); } } else if (DbType.valueOf(config.getDbType()) == DbType.Oracle) { rs = md.getTables(null, config.getUsername().toUpperCase(), null, new String[]{"TABLE", "VIEW"}); } else if (DbType.valueOf(config.getDbType()) == DbType.Sqlite) { String sql = "Select name from sqlite_master;"; rs = connection.createStatement().executeQuery(sql); while (rs.next()) { tables.add(rs.getString("name")); } } else { // rs = md.getTables(null, config.getUsername().toUpperCase(), null, null); rs = md.getTables(config.getSchema(), null, "%", new String[]{"TABLE", "VIEW"});//针对 postgresql 的左侧数据表显示 } while (rs.next()) { tables.add(rs.getString(3)); } if (StringUtils.isNotBlank(filter)) { tables.removeIf(x -> !x.contains(filter) && !(x.replaceAll("_", "").contains(filter)));; } if (tables.size() > 1) { Collections.sort(tables); } return tables; } finally { shutdownPortForwarding(sshSession); } } public static List getTableColumns(DatabaseConfig dbConfig, String tableName) throws Exception { String url = getConnectionUrlWithSchema(dbConfig); _LOG.info("getTableColumns, connection url: {}", url); Session sshSession = getSSHSession(dbConfig); engagePortForwarding(sshSession, dbConfig); Connection conn = getConnection(dbConfig); try { DatabaseMetaData md = conn.getMetaData(); ResultSet rs = md.getColumns(dbConfig.getSchema(), null, tableName, null); List columns = new ArrayList<>(); while (rs.next()) { UITableColumnVO columnVO = new UITableColumnVO(); String columnName = rs.getString("COLUMN_NAME"); columnVO.setColumnName(columnName); columnVO.setJdbcType(rs.getString("TYPE_NAME")); columns.add(columnVO); } return columns; } finally { conn.close(); shutdownPortForwarding(sshSession); } } public static String getConnectionUrlWithSchema(DatabaseConfig dbConfig) throws ClassNotFoundException { DbType dbType = DbType.valueOf(dbConfig.getDbType()); String connectionUrl = String.format(dbType.getConnectionUrlPattern(), portForwaring ? "127.0.0.1" : dbConfig.getHost(), portForwaring ? dbConfig.getLport() : dbConfig.getPort(), dbConfig.getSchema(), dbConfig.getEncoding()); _LOG.info("getConnectionUrlWithSchema, connection url: {}", connectionUrl); return connectionUrl; } /** * 加载数据库驱动 * @param dbType 数据库类型 */ private static void loadDbDriver(DbType dbType){ List driverJars = ConfigHelper.getAllJDBCDriverJarPaths(); ClassLoader classloader = ClassloaderUtility.getCustomClassloader(driverJars); try { Class clazz = Class.forName(dbType.getDriverClass(), true, classloader); Driver driver = (Driver) clazz.newInstance(); _LOG.info("load driver class: {}", driver); drivers.put(dbType, driver); } catch (Exception e) { _LOG.error("load driver error", e); throw new DbDriverLoadingException("找不到"+dbType.getConnectorJarFile()+"驱动"); } } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/util/MyStringUtils.java ================================================ package com.zzg.mybatis.generator.util; /** * Created by Owen on 6/18/16. */ public class MyStringUtils { /** * * convert string from slash style to camel style, such as my_course will convert to MyCourse * * @param str * @return */ public static String dbStringToCamelStyle(String str) { if (str != null) { if (str.contains("_")) { str = str.toLowerCase(); StringBuilder sb = new StringBuilder(); sb.append(String.valueOf(str.charAt(0)).toUpperCase()); for (int i = 1; i < str.length(); i++) { char c = str.charAt(i); if (c != '_') { sb.append(c); } else { if (i + 1 < str.length()) { sb.append(String.valueOf(str.charAt(i + 1)).toUpperCase()); i++; } } } return sb.toString(); } else { String firstChar = String.valueOf(str.charAt(0)).toUpperCase(); String otherChars = str.substring(1); return firstChar + otherChars; } } return null; } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/view/AlertUtil.java ================================================ package com.zzg.mybatis.generator.view; import javafx.scene.control.Alert; /** * Created by Owen on 6/21/16. */ public class AlertUtil { public static void showInfoAlert(String message) { Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setContentText(message); alert.show(); } public static void showWarnAlert(String message) { Alert alert = new Alert(Alert.AlertType.WARNING); alert.setContentText(message); alert.show(); } public static void showErrorAlert(String message) { Alert alert = new Alert(Alert.AlertType.ERROR); alert.setContentText(message); alert.show(); } /** * build both OK and Cancel buttons for the user * to click on to dismiss the dialog. * * @param message */ public static Alert buildConfirmationAlert(String message) { Alert alert = new Alert(Alert.AlertType.CONFIRMATION); alert.setContentText(message); return alert; } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/view/LeftDbTreeCell.java ================================================ package com.zzg.mybatis.generator.view; import com.zzg.mybatis.generator.model.DatabaseConfig; import javafx.beans.InvalidationListener; import javafx.beans.Observable; import javafx.beans.WeakInvalidationListener; import javafx.scene.control.TreeCell; import javafx.scene.control.TreeItem; import javafx.scene.layout.HBox; import java.lang.ref.WeakReference; /** * Created by Owen on 6/14/16. */ public class LeftDbTreeCell extends TreeCell { private HBox hbox; private WeakReference> treeItemRef; private InvalidationListener treeItemGraphicListener = observable -> { updateDisplay(getItem(), isEmpty()); }; private InvalidationListener treeItemListener = new InvalidationListener() { @Override public void invalidated(Observable observable) { TreeItem oldTreeItem = treeItemRef == null ? null : treeItemRef.get(); if (oldTreeItem != null) { oldTreeItem.graphicProperty().removeListener(weakTreeItemGraphicListener); } TreeItem newTreeItem = getTreeItem(); if (newTreeItem != null) { newTreeItem.graphicProperty().addListener(weakTreeItemGraphicListener); treeItemRef = new WeakReference>(newTreeItem); } } }; private WeakInvalidationListener weakTreeItemGraphicListener = new WeakInvalidationListener(treeItemGraphicListener); private WeakInvalidationListener weakTreeItemListener = new WeakInvalidationListener(treeItemListener); public LeftDbTreeCell() { treeItemProperty().addListener(weakTreeItemListener); if (getTreeItem() != null) { getTreeItem().graphicProperty().addListener(weakTreeItemGraphicListener); } } void updateDisplay(DatabaseConfig item, boolean empty) { if (item == null || empty) { hbox = null; setText(null); setGraphic(null); } else { // update the graphic if one is set in the TreeItem TreeItem treeItem = getTreeItem(); if (treeItem != null && treeItem.getGraphic() != null) { hbox = null; setText(item.toString()); setGraphic(treeItem.getGraphic()); } else { hbox = null; setText(item.getName()); setGraphic(null); } } } @Override public void updateItem(DatabaseConfig item, boolean empty) { super.updateItem(item, empty); updateDisplay(item, empty); } } ================================================ FILE: src/main/java/com/zzg/mybatis/generator/view/UIProgressCallback.java ================================================ package com.zzg.mybatis.generator.view; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.scene.control.Alert; import org.mybatis.generator.api.ProgressCallback; /** * Created by Owen on 6/21/16. */ public class UIProgressCallback extends Alert implements ProgressCallback { private StringProperty progressText = new SimpleStringProperty(); public UIProgressCallback(AlertType alertType) { super(alertType); this.contentTextProperty().bindBidirectional(progressText); } @Override public void introspectionStarted(int totalTasks) { progressText.setValue("开始代码检查"); } @Override public void generationStarted(int totalTasks) { progressText.setValue("开始代码生成"); } @Override public void saveStarted(int totalTasks) { progressText.setValue("开始保存生成的文件"); } @Override public void startTask(String taskName) { progressText.setValue("代码生成任务开始"); } @Override public void done() { progressText.setValue("代码生成完成"); } @Override public void checkCancel() throws InterruptedException { } } ================================================ FILE: src/main/resources/fxml/MainUI.fxml ================================================

================================================ FILE: src/main/resources/fxml/basicConnection.fxml ================================================ ================================================ FILE: src/main/resources/fxml/generatorConfigs.fxml ================================================ ================================================ FILE: src/main/resources/fxml/newConnection.fxml ================================================ ================================================ FILE: src/main/resources/fxml/selectTableColumn.fxml ================================================ ================================================ FILE: src/main/resources/fxml/tableColumnConfigs.fxml ================================================ ================================================ FILE: src/main/resources/logback.xml ================================================ [%level] [%date{HH:mm:ss.SSS}] [%thread] [%mdc] %logger.%method:%line --> %message%n DEBUG logs/mybatis-generator.%d{yyyy-MM-dd}.%i.log.zip 7 500MB [%level] [%date{HH:mm:ss.SSS}] [%thread] [%mdc] %logger.%method:%line --> %message%n DEBUG ================================================ FILE: src/main/resources/style.css ================================================ * { -fx-font-size: 12px; } .button { -fx-font-size: 14px; } .tool-bar .button { -fx-border-width: 0px; } .btn { -fx-border-width: 1px; -fx-border-color: transparent; -fx-border-radius: 4px; } .btn-primary { -fx-background-color: #378bfa; -fx-text-fill: white; } .btn-primary:hover { -fx-background-color: #579efa; } .btn-default { -fx-text-fill: #333; -fx-background-color: #fff; -fx-border-color: #ccc; } .btn-default:hover { -fx-background-color: #e6e6e6; -fx-border-color: #adadad; } .btn-success:hover { -fx-text-fill: #fff; -fx-background-color: #449d44; -fx-border-color: #398439; } .btn-success { -fx-text-fill: #fff; -fx-background-color: #5cb85c; -fx-border-color: #4cae4c; } .consoleTextArea { -fx-stroke: white; -fx-fill: black; -fx-background-color: black; } .consoleTextArea:focused { } ================================================ FILE: src/test/java/com/zzg/mybatis/generator/util/ConfigHelperTest.java ================================================ package com.zzg.mybatis.generator.util; import org.junit.Assert; import org.junit.Test; import java.util.List; /** * Created by zouzhigang on 2016/9/18. */ public class ConfigHelperTest { @Test public void testFindConnectorLibPath_Oracle() { String path = ConfigHelper.findConnectorLibPath("Oracle"); Assert.assertTrue(path.contains("ojdbc")); } @Test public void testFindConnectorLibPath_Mysql() { String path = ConfigHelper.findConnectorLibPath("MySQL"); Assert.assertTrue(path.contains("mysql-connector")); } @Test public void testFindConnectorLibPath_PostgreSQL() { String path = ConfigHelper.findConnectorLibPath("PostgreSQL"); Assert.assertTrue(path.contains("postgresql")); } @Test public void testGetAllJDBCDriverJarPaths() { List jarFilePaths = ConfigHelper.getAllJDBCDriverJarPaths(); Assert.assertTrue(jarFilePaths != null && jarFilePaths.size() > 0); } } ================================================ FILE: src/test/java/com/zzg/mybatis/generator/util/StringUtilTest.java ================================================ package com.zzg.mybatis.generator.util; import org.junit.Assert; import org.junit.Test; /** * Created by Owen on 6/18/16. */ public class StringUtilTest { @Test public void testDbStringToCamelStyle() { String result = MyStringUtils.dbStringToCamelStyle("person_address"); Assert.assertEquals("PersonAddress", result); } @Test public void testDbStringToCamelStyle_case2() { String result = MyStringUtils.dbStringToCamelStyle("person_address_name"); Assert.assertEquals("PersonAddressName", result); } @Test public void testDbStringToCamelStyle_case3() { String result = MyStringUtils.dbStringToCamelStyle("person_db_name"); Assert.assertEquals("PersonDbName", result); } @Test public void testDbStringToCamelStyle_case4() { String result = MyStringUtils.dbStringToCamelStyle("person_jobs_"); Assert.assertEquals("PersonJobs", result); } @Test public void testDbStringToCamelStyle_case5() { String result = MyStringUtils.dbStringToCamelStyle("a"); Assert.assertEquals("A", result); } }