├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src └── main ├── java └── com │ └── greedystar │ └── generator │ ├── application │ └── Main.java │ ├── convertor │ ├── DefaultConvertor.java │ └── TypeConvertor.java │ ├── db │ ├── ConnectionUtil.java │ └── DataBaseFactory.java │ ├── entity │ ├── ColumnInfo.java │ ├── Configuration.java │ ├── Constant.java │ ├── IdStrategy.java │ └── Mode.java │ ├── invoker │ ├── Many2ManyInvoker.java │ ├── Many2OneInvoker.java │ ├── One2ManyInvoker.java │ ├── SingleInvoker.java │ └── base │ │ ├── AbstractBuilder.java │ │ ├── AbstractInvoker.java │ │ └── Invoker.java │ ├── task │ ├── ControllerTask.java │ ├── DaoTask.java │ ├── EntityTask.java │ ├── InterfaceTask.java │ ├── MapperTask.java │ ├── ServiceTask.java │ └── base │ │ └── AbstractTask.java │ └── utils │ ├── ConfigUtil.java │ ├── ConvertorUtil.java │ ├── FileUtil.java │ ├── ForEachUtil.java │ ├── FreemarkerConfigUtil.java │ ├── IOUtils.java │ ├── StringUtil.java │ └── TaskQueue.java └── resources └── ftls ├── Controller.ftl ├── Dao.ftl ├── Entity.ftl ├── Interface.ftl ├── Mapper.ftl └── Service.ftl /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | out/ 3 | META-INF/ 4 | !**/src/main/** 5 | !**/src/test/** 6 | 7 | ### IntelliJ IDEA ### 8 | .idea 9 | *.iws 10 | *.iml 11 | *.ipr 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # 欢迎来到 Generator 3 | 4 | Generator 是一款基于数据库表生成Java代码的工具,代码模板使用当前主流Java框架: **Spring, SpringMVC, Mybatis(Mybatis-Plus、JPA)** 组织,能够减少繁琐的重复性工作,让开发人员更专注于技术和性能,提高工作效率和编码热情。 5 | 6 | 你可以使用Generator: 7 | > * 根据数据库业务表生成实体类 8 | > * 生成包含简单的增、删、查、改操作的Mapper文件 9 | > * 生成Controller、Service、Dao代码 10 | 11 | ### Release note: 12 | * v1.0.0 框架基本功能,支持连接本地MySql数据库 13 | * v1.0.1 修复默认模板文件中存在的错误 14 | * v1.1.0 支持连接远程MySql、Oracle、SqlServer数据库(可配置) 15 | * v1.2.0 添加列名到属性名的映射规则;代码生成任务多线程;可配置生成策略等 16 | * v1.2.1 Service层添加接口和实现类的支持 17 | * v1.3.0 添加实体的类注释和属性注释,自动创建代码生成目录,可自定义类型转换器,解决生成文件冲突 18 | * v1.4.0 单表模式支持JPA和Mybatis-Plus,可自定义类名和文件名,支持Lombok和Swagger,添加代码配置方式,支持将MyBatis映射文件放于source目录下,调整代码生成策略(支持单表、一对多、多对一、多对多),可配置主键生成策略(数据库自增、UUID),可配置文件覆盖策略 19 | * v1.4.1 修复配置DO实体类别名时文件名错误的问题 20 | 21 | 详细 Release note :[GreedyStar/generator/Releases](https://github.com/GreedyStar/generator/releases) 22 | 23 | ### 具体请参考使用手册 : [Wiki-Generator](https://github.com/GreedyStar/generator/wiki) 24 | 25 | ## 致谢 26 | 27 | 感谢以下人员对本仓库提出的建议,我们期待本工具能够为更多的开发者提供便利。 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.greedystar 8 | generator 9 | 1.4.1 10 | 11 | 12 | org.sonatype.oss 13 | oss-parent 14 | 7 15 | 16 | 17 | 18 | 19 | The Apache Software License, Version 2.0 20 | http://www.apache.org/licenses/LICENSE-2.0.txt 21 | repo 22 | 23 | 24 | 25 | master 26 | git@github.com:GreedyStar/generator.git 27 | scm:git:git@github.com:GreedyStar/generator.git 28 | scm:git:git@github.com:GreedyStar/generator.git 29 | 30 | 31 | 32 | GreedyStar 33 | greedystar@163.com 34 | GreedyStar 35 | 36 | 37 | 38 | 39 | UTF-8 40 | 1.8 41 | 1.8 42 | 43 | 44 | 45 | 46 | org.freemarker 47 | freemarker 48 | 2.3.23 49 | 50 | 51 | 52 | org.yaml 53 | snakeyaml 54 | 1.19 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/application/Main.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.application; 2 | 3 | import com.greedystar.generator.invoker.Many2ManyInvoker; 4 | import com.greedystar.generator.invoker.Many2OneInvoker; 5 | import com.greedystar.generator.invoker.One2ManyInvoker; 6 | import com.greedystar.generator.invoker.SingleInvoker; 7 | import com.greedystar.generator.invoker.base.Invoker; 8 | 9 | /** 10 | * @author GreedyStar 11 | * @since 2018/9/5 12 | */ 13 | public class Main { 14 | 15 | public static void main(String[] args) { 16 | 17 | } 18 | 19 | public static void many2many() { 20 | Invoker invoker = new Many2ManyInvoker.Builder() 21 | .setTableName("user") 22 | .setClassName("User") 23 | .setParentTableName("role") 24 | .setParentClassName("Role") 25 | .setRelationTableName("user_role") 26 | .setForeignKey("user_id") 27 | .setParentForeignKey("role_id") 28 | .build(); 29 | invoker.execute(); 30 | } 31 | 32 | public static void many2one() { 33 | Invoker one2many = new Many2OneInvoker.Builder() 34 | .setTableName("user") 35 | .setClassName("User") 36 | .setParentTableName("office") 37 | .setParentClassName("Office") 38 | .setForeignKey("office_id") 39 | .build(); 40 | one2many.execute(); 41 | } 42 | 43 | public static void one2many() { 44 | Invoker invoker = new One2ManyInvoker.Builder() 45 | .setTableName("user") 46 | .setClassName("User") 47 | .setParentTableName("article") 48 | .setParentClassName("Article") 49 | .setParentForeignKey("user_id") 50 | .build(); 51 | invoker.execute(); 52 | } 53 | 54 | public static void single() { 55 | Invoker invoker = new SingleInvoker.Builder() 56 | .setTableName("user") 57 | .setClassName("User") 58 | .build(); 59 | invoker.execute(); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/convertor/DefaultConvertor.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.convertor; 2 | 3 | import java.sql.JDBCType; 4 | 5 | /** 6 | * @author GreedyStar 7 | * @since 2019/6/2 8 | */ 9 | public class DefaultConvertor implements TypeConvertor { 10 | 11 | /** 12 | * 将JDBC类型转换为Java类型 13 | * 14 | * @param type JDBC类型名 15 | */ 16 | @Override 17 | public String convertType(JDBCType type) { 18 | StringBuilder sb = new StringBuilder(); 19 | switch (type) { 20 | case BIT: 21 | case BOOLEAN: 22 | sb.append("Boolean"); 23 | break; 24 | case TINYINT: 25 | case SMALLINT: 26 | case INTEGER: 27 | sb.append("Integer"); 28 | break; 29 | case BIGINT: 30 | sb.append("Long"); 31 | break; 32 | case REAL: 33 | sb.append("Float"); 34 | break; 35 | case FLOAT: 36 | case DOUBLE: 37 | sb.append("Double"); 38 | break; 39 | case DECIMAL: 40 | case NUMERIC: 41 | sb.append("BigDecimal"); 42 | break; 43 | case VARCHAR: 44 | case CHAR: 45 | case NCHAR: 46 | case NVARCHAR: 47 | case LONGVARCHAR: 48 | case LONGNVARCHAR: 49 | sb.append("String"); 50 | break; 51 | case DATE: 52 | case TIME: 53 | case TIMESTAMP: 54 | sb.append("Date"); 55 | break; 56 | case CLOB: 57 | case NCLOB: 58 | case BLOB: 59 | case BINARY: 60 | case VARBINARY: 61 | case LONGVARBINARY: 62 | sb.append("byte[]"); 63 | break; 64 | default: 65 | sb.append("Object"); 66 | 67 | } 68 | return sb.toString(); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/convertor/TypeConvertor.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.convertor; 2 | 3 | import java.sql.JDBCType; 4 | 5 | /** 6 | * @author GreedyStar 7 | * @since 2019/6/2 8 | */ 9 | public interface TypeConvertor { 10 | 11 | /** 12 | * 将JDBC类型转换为Java类型 13 | * 14 | * @param type JDBC类型名 15 | * @return Java类型名 16 | */ 17 | String convertType(JDBCType type); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/db/ConnectionUtil.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.db; 2 | 3 | 4 | import com.greedystar.generator.entity.ColumnInfo; 5 | import com.greedystar.generator.utils.ConfigUtil; 6 | import com.greedystar.generator.utils.StringUtil; 7 | 8 | import java.sql.*; 9 | import java.util.ArrayList; 10 | import java.util.HashMap; 11 | import java.util.List; 12 | import java.util.Properties; 13 | 14 | /** 15 | * 数据库连接工具类 16 | * 17 | * @author GreedyStar 18 | * @since 2018/4/19 19 | */ 20 | public class ConnectionUtil { 21 | /** 22 | * 数据库连接 23 | */ 24 | private Connection connection; 25 | 26 | /** 27 | * 初始化数据库连接 28 | * 29 | * @return 连接是否建立成功 30 | */ 31 | public boolean initConnection() { 32 | try { 33 | Class.forName(DataBaseFactory.getDriver(ConfigUtil.getConfiguration().getDb().getUrl())); 34 | String url = ConfigUtil.getConfiguration().getDb().getUrl(); 35 | String username = ConfigUtil.getConfiguration().getDb().getUsername(); 36 | String password = ConfigUtil.getConfiguration().getDb().getPassword(); 37 | Properties properties = new Properties(); 38 | properties.put("user", username); 39 | properties.put("password", password == null ? "" : password); 40 | properties.setProperty("remarks", "true"); 41 | properties.setProperty("useInformationSchema", "true"); 42 | properties.setProperty("nullCatalogMeansCurrent", "true"); 43 | connection = DriverManager.getConnection(url, properties); 44 | return true; 45 | } catch (ClassNotFoundException e) { 46 | e.printStackTrace(); 47 | } catch (SQLException e) { 48 | e.printStackTrace(); 49 | } 50 | return false; 51 | } 52 | 53 | /** 54 | * 获取表结构数据 55 | * 56 | * @param tableName 表名 57 | * @return 包含表结构数据的列表 58 | * @throws Exception Exception 59 | */ 60 | public List getMetaData(String tableName) throws Exception { 61 | if (!initConnection()) { 62 | throw new Exception("Failed to connect to database at url:" + ConfigUtil.getConfiguration().getDb().getUrl()); 63 | } 64 | // 获取主键 65 | String primaryKey = getPrimaryKey(tableName); 66 | // 获取表注释 67 | String tableRemark = getTableRemark(tableName); 68 | // 获取列信息 69 | List columnInfos = getColumnInfos(tableName, primaryKey, tableRemark); 70 | closeConnection(); 71 | return columnInfos; 72 | } 73 | 74 | /** 75 | * 获取主键 76 | * 77 | * @param tableName 表名 78 | * @return 主键名称 79 | * @throws SQLException SQLException 80 | */ 81 | private String getPrimaryKey(String tableName) throws SQLException { 82 | // 获取主键 83 | ResultSet keyResultSet = connection.getMetaData().getPrimaryKeys(DataBaseFactory.getCatalog(connection), 84 | DataBaseFactory.getSchema(connection), tableName); 85 | String primaryKey = null; 86 | if (keyResultSet.next()) { 87 | primaryKey = keyResultSet.getObject(4).toString(); 88 | } 89 | keyResultSet.close(); 90 | return primaryKey; 91 | } 92 | 93 | /** 94 | * 获取表注释 95 | * 96 | * @param tableName 表名 97 | * @return 表注释 98 | * @throws SQLException SQLException 99 | */ 100 | private String getTableRemark(String tableName) throws SQLException { 101 | // 获取表注释 102 | String tableRemark = null; 103 | if (connection.getMetaData().getURL().contains("sqlserver")) { // SQLServer 104 | tableRemark = parseSqlServerTableRemarks(tableName); 105 | } else { // Oracle & MySQL 106 | ResultSet tableResultSet = connection.getMetaData().getTables(DataBaseFactory.getCatalog(connection), 107 | DataBaseFactory.getSchema(connection), tableName, new String[]{"TABLE"}); 108 | if (tableResultSet.next()) { 109 | tableRemark = StringUtil.isEmpty(tableResultSet.getString("REMARKS")) ? 110 | "Unknown Table" : tableResultSet.getString("REMARKS"); 111 | } 112 | tableResultSet.close(); 113 | } 114 | return tableRemark; 115 | } 116 | 117 | /** 118 | * 获取列信息 119 | * 120 | * @param tableName 表名 121 | * @param primaryKey 主键列名 122 | * @param tableRemark 表注释 123 | * @return 列信息 124 | * @throws Exception Exception 125 | */ 126 | private List getColumnInfos(String tableName, String primaryKey, String tableRemark) throws Exception { 127 | // 获取列信息 128 | List columnInfos = new ArrayList<>(); 129 | ResultSet columnResultSet = connection.getMetaData().getColumns(DataBaseFactory.getCatalog(connection), 130 | DataBaseFactory.getSchema(connection), tableName, "%"); 131 | while (columnResultSet.next()) { 132 | boolean isPrimaryKey; 133 | if (columnResultSet.getString("COLUMN_NAME").equals(primaryKey)) { 134 | isPrimaryKey = true; 135 | } else { 136 | isPrimaryKey = false; 137 | } 138 | ColumnInfo info = new ColumnInfo(columnResultSet.getString("COLUMN_NAME"), columnResultSet.getInt("DATA_TYPE"), 139 | StringUtil.isEmpty(columnResultSet.getString("REMARKS")) ? "Unknown" : columnResultSet.getString("REMARKS"), 140 | tableRemark, isPrimaryKey); 141 | columnInfos.add(info); 142 | } 143 | columnResultSet.close(); 144 | if (columnInfos.size() == 0) { 145 | closeConnection(); 146 | throw new Exception("Can not find column information from table:" + tableName); 147 | } 148 | // SQLServer需要单独处理列REMARKS 149 | if (connection.getMetaData().getURL().contains("sqlserver")) { 150 | parseSqlServerColumnRemarks(tableName, columnInfos); 151 | } 152 | return columnInfos; 153 | } 154 | 155 | /** 156 | * 主动查询SqlServer指定表的注释 157 | * 158 | * @param tableName 表名 159 | * @return 表注释 160 | * @throws SQLException SQLException 161 | */ 162 | private String parseSqlServerTableRemarks(String tableName) throws SQLException { 163 | String tableRemarks = null; 164 | String sql = "SELECT CAST(ISNULL(p.value, '') AS nvarchar(25)) AS REMARKS FROM sys.tables t " + 165 | "LEFT JOIN sys.extended_properties p ON p.major_id=t.object_id AND p.minor_id=0 AND p.class=1 " + 166 | "WHERE t.name = ?"; 167 | PreparedStatement preparedStatement = connection.prepareStatement(sql); 168 | preparedStatement.setString(1, tableName); 169 | ResultSet resultSet = preparedStatement.executeQuery(); 170 | while (resultSet.next()) { 171 | tableRemarks = StringUtil.isEmpty(resultSet.getString("REMARKS")) ? "Unknown Table" : resultSet.getString("REMARKS"); 172 | } 173 | resultSet.close(); 174 | preparedStatement.close(); 175 | return tableRemarks; 176 | } 177 | 178 | /** 179 | * 主动查询SqlServer指定表的数据列的注释 180 | * 181 | * @param tableName 表名 182 | * @throws SQLException SQLException 183 | */ 184 | private void parseSqlServerColumnRemarks(String tableName, List columnInfos) throws SQLException { 185 | HashMap map = new HashMap<>(); 186 | String sql = "SELECT c.name AS COLUMN_NAME, CAST(ISNULL(p.value, '') AS nvarchar(25)) AS REMARKS " + 187 | "FROM sys.tables t " + 188 | "INNER JOIN sys.columns c ON c.object_id = t.object_id " + 189 | "LEFT JOIN sys.extended_properties p ON p.major_id = c.object_id AND p.minor_id = c.column_id " + 190 | "WHERE t.name = ?"; 191 | PreparedStatement preparedStatement = connection.prepareStatement(sql); 192 | preparedStatement.setString(1, tableName); 193 | ResultSet resultSet = preparedStatement.executeQuery(); 194 | while (resultSet.next()) { 195 | map.put(resultSet.getString("COLUMN_NAME"), StringUtil.isEmpty(resultSet.getString("REMARKS")) ? 196 | "Unknown" : resultSet.getString("REMARKS")); 197 | } 198 | for (ColumnInfo columnInfo : columnInfos) { 199 | columnInfo.setRemarks(map.get(columnInfo.getColumnName())); 200 | } 201 | resultSet.close(); 202 | preparedStatement.close(); 203 | } 204 | 205 | /** 206 | * 关闭数据库连接 207 | * @throws SQLException SQLException 208 | */ 209 | public void closeConnection() throws SQLException { 210 | if (!connection.isClosed()) { 211 | connection.close(); 212 | } 213 | } 214 | 215 | } 216 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/db/DataBaseFactory.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.db; 2 | 3 | import java.sql.Connection; 4 | import java.sql.SQLException; 5 | 6 | /** 7 | * 数据库驱动工厂类 8 | * 9 | * @author GreedyStar 10 | * @since 2018-10-24 11 | */ 12 | public class DataBaseFactory { 13 | private final static String DRIVER_MYSQL_5 = "com.mysql.jdbc.Driver"; 14 | private final static String DRIVER_MYSQL_UPER = "com.mysql.cj.jdbc.Driver"; 15 | private final static String DRIVER_ORACLE = "oracle.jdbc.driver.OracleDriver"; 16 | private final static String DRIVER_SQLSERVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver"; 17 | 18 | /** 19 | * 根据数据库连接url获取数据库驱动 20 | * 21 | * @param url 数据库url 22 | * @return 驱动类名 23 | */ 24 | public static String getDriver(String url) { 25 | if (url.contains("mysql")) { 26 | if (url.contains("serverTimezone")) { 27 | return DRIVER_MYSQL_UPER; 28 | } else { 29 | return DRIVER_MYSQL_5; 30 | } 31 | } 32 | if (url.contains("oracle")) { 33 | return DRIVER_ORACLE; 34 | } 35 | if (url.contains("sqlserver")) { 36 | return DRIVER_SQLSERVER; 37 | } 38 | return null; 39 | } 40 | 41 | /** 42 | * 获取catalog 43 | * 44 | * @param connection 数据库连接 45 | * @return catalog 46 | * @throws SQLException SQLException 47 | */ 48 | public static String getCatalog(Connection connection) throws SQLException { 49 | String url = connection.getMetaData().getURL(); 50 | if (url.contains("mysql")) { 51 | return null; 52 | } else if (url.contains("oracle")) { 53 | return null; 54 | } else if (url.contains("sqlserver")) { 55 | return url.substring(url.lastIndexOf("=") + 1); 56 | } 57 | return null; 58 | } 59 | 60 | /** 61 | * 获取schema 62 | * 63 | * @param connection 数据库连接 64 | * @return schema 65 | * @throws SQLException SQLException 66 | */ 67 | public static String getSchema(Connection connection) throws SQLException { 68 | String url = connection.getMetaData().getURL(); 69 | if (url.contains("mysql")) { 70 | if (url.contains("?")) { 71 | url = url.replace("jdbc:mysql://", ""); 72 | return url.substring(url.indexOf("/") + 1, url.lastIndexOf("?")); 73 | } else { 74 | return url.substring(url.lastIndexOf("/") + 1); 75 | } 76 | } else if (url.contains("oracle")) { 77 | return connection.getMetaData().getUserName(); 78 | } else if (url.contains("sqlserver")) { 79 | return connection.getSchema(); 80 | } 81 | return null; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/entity/ColumnInfo.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.entity; 2 | 3 | import com.greedystar.generator.utils.ConvertorUtil; 4 | import com.greedystar.generator.utils.StringUtil; 5 | 6 | import java.io.Serializable; 7 | import java.sql.JDBCType; 8 | 9 | /** 10 | * 数据列实体 11 | * 12 | * @author GreedyStar 13 | * @since 2018/4/19 14 | */ 15 | public class ColumnInfo implements Serializable { 16 | /** 17 | * 列名 18 | */ 19 | private String columnName; 20 | /** 21 | * 列名 -- 属性名 22 | */ 23 | private String propertyName; 24 | /** 25 | * 数据列类型 26 | */ 27 | private JDBCType columnType; 28 | /** 29 | * 数据列类型 -- Java类型 30 | */ 31 | private String propertyType; 32 | /** 33 | * 列备注 34 | */ 35 | private String remarks; 36 | /** 37 | * 表备注 38 | */ 39 | private String tableRemarks; 40 | /** 41 | * 是否主键 42 | */ 43 | private boolean isPrimaryKey; 44 | 45 | public ColumnInfo(String columnName, int columnType, String remarks, String tableRemarks, boolean isPrimaryKey) { 46 | this.columnName = columnName; 47 | this.propertyName = StringUtil.columnName2PropertyName(columnName); 48 | this.columnType = JDBCType.valueOf(columnType); 49 | this.propertyType = ConvertorUtil.parseTypeFormSqlType(JDBCType.valueOf(columnType)); 50 | this.remarks = remarks; 51 | this.tableRemarks = tableRemarks; 52 | this.isPrimaryKey = isPrimaryKey; 53 | } 54 | 55 | public String getColumnName() { 56 | return columnName; 57 | } 58 | 59 | public void setColumnName(String columnName) { 60 | this.columnName = columnName; 61 | } 62 | 63 | public String getPropertyName() { 64 | return propertyName; 65 | } 66 | 67 | public void setPropertyName(String propertyName) { 68 | this.propertyName = propertyName; 69 | } 70 | 71 | public JDBCType getColumnType() { 72 | return columnType; 73 | } 74 | 75 | public void setColumnType(JDBCType columnType) { 76 | this.columnType = columnType; 77 | } 78 | 79 | public String getPropertyType() { 80 | return propertyType; 81 | } 82 | 83 | public void setPropertyType(String propertyType) { 84 | this.propertyType = propertyType; 85 | } 86 | 87 | public String getRemarks() { 88 | return remarks; 89 | } 90 | 91 | public void setRemarks(String remarks) { 92 | this.remarks = remarks; 93 | } 94 | 95 | public String getTableRemarks() { 96 | return tableRemarks; 97 | } 98 | 99 | public void setTableRemarks(String tableRemarks) { 100 | this.tableRemarks = tableRemarks; 101 | } 102 | 103 | public boolean isPrimaryKey() { 104 | return isPrimaryKey; 105 | } 106 | 107 | public void setPrimaryKey(boolean primaryKey) { 108 | isPrimaryKey = primaryKey; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/entity/Configuration.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.entity; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Generator 配置类 7 | * 8 | * @author GreedyStar 9 | * @since 2018/9/7 10 | */ 11 | public class Configuration implements Serializable { 12 | /** 13 | * 代码作者 14 | */ 15 | private String author; 16 | /** 17 | * 顶级包名 18 | */ 19 | private String packageName; 20 | /** 21 | * 类型转换器全限定类名 22 | */ 23 | private String convertor; 24 | /** 25 | * 启用lombok 26 | */ 27 | private boolean lombokEnable; 28 | /** 29 | * 是否将mybatis的xml映射文件放在源文件目录下 30 | */ 31 | private boolean mapperUnderSource; 32 | /** 33 | * 启用swagger 34 | */ 35 | private boolean swaggerEnable; 36 | /** 37 | * mybatis-plus模式 38 | */ 39 | private boolean mybatisPlusEnable; 40 | /** 41 | * jpa模式 42 | */ 43 | private boolean jpaEnable; 44 | /** 45 | * 文件覆盖 46 | */ 47 | private boolean fileOverride; 48 | /** 49 | * id策略(auto:数据库自增,uuid:生成uuid) 50 | */ 51 | private IdStrategy idStrategy; 52 | /** 53 | * 代码生成路径 54 | */ 55 | private Path path; 56 | /** 57 | * 数据库配置 58 | */ 59 | private Db db; 60 | /** 61 | * 代码文件后缀 62 | */ 63 | private Name name; 64 | 65 | public String getAuthor() { 66 | return author; 67 | } 68 | 69 | public void setAuthor(String author) { 70 | this.author = author; 71 | } 72 | 73 | public String getPackageName() { 74 | return packageName; 75 | } 76 | 77 | public void setPackageName(String packageName) { 78 | this.packageName = packageName; 79 | } 80 | 81 | public String getConvertor() { 82 | return convertor; 83 | } 84 | 85 | public void setConvertor(String convertor) { 86 | this.convertor = convertor; 87 | } 88 | 89 | public boolean isLombokEnable() { 90 | return lombokEnable; 91 | } 92 | 93 | public void setLombokEnable(boolean lombokEnable) { 94 | this.lombokEnable = lombokEnable; 95 | } 96 | 97 | public boolean isMapperUnderSource() { 98 | return mapperUnderSource; 99 | } 100 | 101 | public void setMapperUnderSource(boolean mapperUnderSource) { 102 | this.mapperUnderSource = mapperUnderSource; 103 | } 104 | 105 | public boolean isSwaggerEnable() { 106 | return swaggerEnable; 107 | } 108 | 109 | public void setSwaggerEnable(boolean swaggerEnable) { 110 | this.swaggerEnable = swaggerEnable; 111 | } 112 | 113 | public boolean isMybatisPlusEnable() { 114 | return mybatisPlusEnable; 115 | } 116 | 117 | public void setMybatisPlusEnable(boolean mybatisPlusEnable) { 118 | this.mybatisPlusEnable = mybatisPlusEnable; 119 | } 120 | 121 | public boolean isJpaEnable() { 122 | return jpaEnable; 123 | } 124 | 125 | public void setJpaEnable(boolean jpaEnable) { 126 | this.jpaEnable = jpaEnable; 127 | } 128 | 129 | public boolean isFileOverride() { 130 | return fileOverride; 131 | } 132 | 133 | public void setFileOverride(boolean fileOverride) { 134 | this.fileOverride = fileOverride; 135 | } 136 | 137 | public IdStrategy getIdStrategy() { 138 | return idStrategy; 139 | } 140 | 141 | public void setIdStrategy(IdStrategy idStrategy) { 142 | this.idStrategy = idStrategy; 143 | } 144 | 145 | public Path getPath() { 146 | return path; 147 | } 148 | 149 | public void setPath(Path path) { 150 | this.path = path; 151 | } 152 | 153 | public Db getDb() { 154 | return db; 155 | } 156 | 157 | public void setDb(Db db) { 158 | this.db = db; 159 | } 160 | 161 | public Name getName() { 162 | return name; 163 | } 164 | 165 | public void setName(Name name) { 166 | this.name = name; 167 | } 168 | 169 | /** 170 | * 数据库配置 171 | */ 172 | public static class Db { 173 | /** 174 | * 数据库URL 175 | */ 176 | private String url; 177 | /** 178 | * 数据库用户名 179 | */ 180 | private String username; 181 | /** 182 | * 数据库密码 183 | */ 184 | private String password; 185 | 186 | public Db() { 187 | } 188 | 189 | public Db(String url, String username, String password) { 190 | this.url = url; 191 | this.username = username; 192 | this.password = password; 193 | } 194 | 195 | public String getUrl() { 196 | return url; 197 | } 198 | 199 | public void setUrl(String url) { 200 | this.url = url; 201 | } 202 | 203 | public String getUsername() { 204 | return username; 205 | } 206 | 207 | public void setUsername(String username) { 208 | this.username = username; 209 | } 210 | 211 | public String getPassword() { 212 | return password; 213 | } 214 | 215 | public void setPassword(String password) { 216 | this.password = password; 217 | } 218 | } 219 | 220 | /** 221 | * 代码路径配置 222 | */ 223 | public static class Path { 224 | /** 225 | * Controller代码包路径 226 | */ 227 | private String controller = ""; 228 | /** 229 | * Service或ServiceImpl代码包路径 230 | */ 231 | private String service = ""; 232 | /** 233 | * Service接口代码包路径 234 | */ 235 | private String interf = ""; 236 | /** 237 | * Dao代码包路径 238 | */ 239 | private String dao = ""; 240 | /** 241 | * Entity代码包路径 242 | */ 243 | private String entity = ""; 244 | /** 245 | * Mapper映射文件路径 246 | */ 247 | private String mapper = ""; 248 | 249 | public Path() { 250 | } 251 | 252 | public Path(String controller, String service, String interf, String dao, String entity, String mapper) { 253 | this.controller = controller; 254 | this.service = service; 255 | this.interf = interf; 256 | this.dao = dao; 257 | this.entity = entity; 258 | this.mapper = mapper; 259 | } 260 | 261 | public String getController() { 262 | return controller; 263 | } 264 | 265 | public void setController(String controller) { 266 | this.controller = controller; 267 | } 268 | 269 | public String getService() { 270 | return service; 271 | } 272 | 273 | public void setService(String service) { 274 | this.service = service; 275 | } 276 | 277 | public String getInterf() { 278 | return interf; 279 | } 280 | 281 | public void setInterf(String interf) { 282 | this.interf = interf; 283 | } 284 | 285 | public String getDao() { 286 | return dao; 287 | } 288 | 289 | public void setDao(String dao) { 290 | this.dao = dao; 291 | } 292 | 293 | public String getEntity() { 294 | return entity; 295 | } 296 | 297 | public void setEntity(String entity) { 298 | this.entity = entity; 299 | } 300 | 301 | public String getMapper() { 302 | return mapper; 303 | } 304 | 305 | public void setMapper(String mapper) { 306 | this.mapper = mapper; 307 | } 308 | 309 | } 310 | 311 | /** 312 | * 类名配置 313 | */ 314 | public static class Name { 315 | /** 316 | * Controller类的类名,默认为 $sController 317 | */ 318 | private String controller = Constant.PLACEHOLDER + "Controller"; 319 | /** 320 | * Service类或ServiceImpl类的类名,默认为$sService或$sServiceImpl 321 | */ 322 | private String service = Constant.PLACEHOLDER + "Service"; 323 | /** 324 | * Service接口类的类名,默认为$sService 325 | */ 326 | private String interf = Constant.PLACEHOLDER + "Service"; 327 | /** 328 | * Dao类的类名,默认为$sDao 329 | */ 330 | private String dao = Constant.PLACEHOLDER + "Dao"; 331 | /** 332 | * Entity类的类名,默认为$s 333 | */ 334 | private String entity = Constant.PLACEHOLDER; 335 | /** 336 | * Mapper映射文件的文件名,默认$sMapper 337 | */ 338 | private String mapper = Constant.PLACEHOLDER + "Mapper"; 339 | 340 | public Name() { 341 | } 342 | 343 | public Name(String controller, String service, String dao, String entity, String mapper) { 344 | this.controller = controller; 345 | this.service = service; 346 | this.dao = dao; 347 | this.entity = entity; 348 | this.mapper = mapper; 349 | } 350 | 351 | public String getController() { 352 | return controller; 353 | } 354 | 355 | public void setController(String controller) { 356 | this.controller = controller; 357 | } 358 | 359 | public String getService() { 360 | return service; 361 | } 362 | 363 | public void setService(String service) { 364 | this.service = service; 365 | } 366 | 367 | public String getInterf() { 368 | return interf; 369 | } 370 | 371 | public void setInterf(String interf) { 372 | this.interf = interf; 373 | } 374 | 375 | public String getDao() { 376 | return dao; 377 | } 378 | 379 | public void setDao(String dao) { 380 | this.dao = dao; 381 | } 382 | 383 | public String getEntity() { 384 | return entity; 385 | } 386 | 387 | public void setEntity(String entity) { 388 | this.entity = entity; 389 | } 390 | 391 | public String getMapper() { 392 | return mapper; 393 | } 394 | 395 | public void setMapper(String mapper) { 396 | this.mapper = mapper; 397 | } 398 | 399 | } 400 | 401 | } 402 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/entity/Constant.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.entity; 2 | 3 | /** 4 | * 常量 5 | * 6 | * @author GreedyStar 7 | * @since 2020/6/28 8 | */ 9 | public class Constant { 10 | /** 11 | * 空格 * 4 12 | */ 13 | public final static String SPACE_4 = " "; 14 | /** 15 | * 空格 * 8 16 | */ 17 | public final static String SPACE_8 = " "; 18 | /** 19 | * 空格 * 12 20 | */ 21 | public final static String SPACE_12 = " "; 22 | /** 23 | * 文件名占位符 24 | */ 25 | public final static String PLACEHOLDER = "$s"; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/entity/IdStrategy.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.entity; 2 | 3 | /** 4 | * @author GreedyStar 5 | * @since 2020/10/15 6 | */ 7 | public enum IdStrategy { 8 | AUTO, 9 | UUID; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/entity/Mode.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.entity; 2 | 3 | /** 4 | * Entity任务模式 5 | * 6 | * @author GreedyStar 7 | * @since 2020/8/1 8 | */ 9 | public enum Mode { 10 | /** 11 | * 主表模式 12 | */ 13 | ENTITY_MAIN, 14 | /** 15 | * 父表模式 16 | */ 17 | ENTITY_PARENT; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/invoker/Many2ManyInvoker.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.invoker; 2 | 3 | import com.greedystar.generator.invoker.base.AbstractBuilder; 4 | import com.greedystar.generator.invoker.base.AbstractInvoker; 5 | import com.greedystar.generator.utils.ConfigUtil; 6 | import com.greedystar.generator.utils.StringUtil; 7 | 8 | /** 9 | * @author GreedyStar 10 | * @since 2018/9/5 11 | */ 12 | public class Many2ManyInvoker extends AbstractInvoker { 13 | 14 | private Many2ManyInvoker() { 15 | 16 | } 17 | 18 | @Override 19 | protected void queryMetaData() throws Exception { 20 | tableInfos = connectionUtil.getMetaData(tableName); 21 | parentTableInfos = connectionUtil.getMetaData(parentTableName); 22 | } 23 | 24 | @Override 25 | protected void initTasks() { 26 | taskQueue.initMany2ManyTasks(this); 27 | } 28 | 29 | public static class Builder extends AbstractBuilder { 30 | 31 | public Builder() { 32 | invoker = new Many2ManyInvoker(); 33 | } 34 | 35 | public Builder setTableName(String tableName) { 36 | invoker.setTableName(tableName); 37 | return this; 38 | } 39 | 40 | public Builder setClassName(String className) { 41 | invoker.setClassName(className); 42 | return this; 43 | } 44 | 45 | public Builder setParentTableName(String parentTableName) { 46 | invoker.setParentTableName(parentTableName); 47 | return this; 48 | } 49 | 50 | public Builder setParentClassName(String parentClassName) { 51 | invoker.setParentClassName(parentClassName); 52 | return this; 53 | } 54 | 55 | public Builder setForeignKey(String foreignKey) { 56 | invoker.setForeignKey(foreignKey); 57 | return this; 58 | } 59 | 60 | public Builder setRelationTableName(String relationTableName) { 61 | invoker.setRelationalTableName(relationTableName); 62 | return this; 63 | } 64 | 65 | public Builder setParentForeignKey(String parentForeignKey) { 66 | invoker.setParentForeignKey(parentForeignKey); 67 | return this; 68 | } 69 | 70 | @Override 71 | public void checkBeforeBuild() throws Exception { 72 | if (ConfigUtil.getConfiguration().isMybatisPlusEnable() || ConfigUtil.getConfiguration().isJpaEnable()) { 73 | throw new Exception("JPA mode and Mybatis-Plus mode only supported in SingleInvoker."); 74 | } 75 | if (StringUtil.isEmpty(invoker.getTableName())) { 76 | throw new Exception("Table name can't be null."); 77 | } 78 | if (StringUtil.isEmpty(invoker.getParentTableName())) { 79 | throw new Exception("Parent table name can't be null."); 80 | } 81 | if (StringUtil.isEmpty(invoker.getRelationalTableName())) { 82 | throw new Exception("Relational table name can't be null."); 83 | } 84 | if (StringUtil.isEmpty(invoker.getForeignKey())) { 85 | throw new Exception("Foreign key can't be null."); 86 | } 87 | if (StringUtil.isEmpty(invoker.getParentForeignKey())) { 88 | throw new Exception("Parent foreign key can't be null."); 89 | } 90 | if (StringUtil.isEmpty(invoker.getClassName())) { 91 | invoker.setClassName(StringUtil.tableName2ClassName(invoker.getTableName())); 92 | } 93 | if (StringUtil.isEmpty(invoker.getParentClassName())) { 94 | invoker.setParentClassName(StringUtil.tableName2ClassName(invoker.getParentTableName())); 95 | } 96 | } 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/invoker/Many2OneInvoker.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.invoker; 2 | 3 | import com.greedystar.generator.invoker.base.AbstractBuilder; 4 | import com.greedystar.generator.invoker.base.AbstractInvoker; 5 | import com.greedystar.generator.utils.ConfigUtil; 6 | import com.greedystar.generator.utils.StringUtil; 7 | 8 | /** 9 | * @author GreedyStar 10 | * @since 2020/7/31 11 | */ 12 | public class Many2OneInvoker extends AbstractInvoker { 13 | 14 | private Many2OneInvoker() { 15 | 16 | } 17 | 18 | @Override 19 | protected void queryMetaData() throws Exception { 20 | tableInfos = connectionUtil.getMetaData(tableName); 21 | parentTableInfos = connectionUtil.getMetaData(parentTableName); 22 | } 23 | 24 | @Override 25 | protected void initTasks() { 26 | taskQueue.initMany2OneTasks(this); 27 | } 28 | 29 | public static class Builder extends AbstractBuilder { 30 | 31 | public Builder() { 32 | invoker = new Many2OneInvoker(); 33 | } 34 | 35 | public Builder setTableName(String tableName) { 36 | invoker.setTableName(tableName); 37 | return this; 38 | } 39 | 40 | public Builder setClassName(String className) { 41 | invoker.setClassName(className); 42 | return this; 43 | } 44 | 45 | public Builder setParentTableName(String parentTableName) { 46 | invoker.setParentTableName(parentTableName); 47 | return this; 48 | } 49 | 50 | public Builder setParentClassName(String parentClassName) { 51 | invoker.setParentClassName(parentClassName); 52 | return this; 53 | } 54 | 55 | public Builder setForeignKey(String foreignKey) { 56 | invoker.setForeignKey(foreignKey); 57 | return this; 58 | } 59 | 60 | @Override 61 | public void checkBeforeBuild() throws Exception { 62 | if (ConfigUtil.getConfiguration().isMybatisPlusEnable() || ConfigUtil.getConfiguration().isJpaEnable()) { 63 | throw new Exception("JPA mode and Mybatis-Plus mode only supported in SingleInvoker."); 64 | } 65 | if (StringUtil.isEmpty(invoker.getTableName())) { 66 | throw new Exception("Table name can't be null."); 67 | } 68 | if (StringUtil.isEmpty(invoker.getParentTableName())) { 69 | throw new Exception("Parent table name can't be null."); 70 | } 71 | if (StringUtil.isEmpty(invoker.getForeignKey())) { 72 | throw new Exception("Foreign key can't be null."); 73 | } 74 | if (StringUtil.isEmpty(invoker.getClassName())) { 75 | invoker.setClassName(StringUtil.tableName2ClassName(invoker.getTableName())); 76 | } 77 | if (StringUtil.isEmpty(invoker.getParentClassName())) { 78 | invoker.setParentClassName(StringUtil.tableName2ClassName(invoker.getParentTableName())); 79 | } 80 | } 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/invoker/One2ManyInvoker.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.invoker; 2 | 3 | import com.greedystar.generator.invoker.base.AbstractBuilder; 4 | import com.greedystar.generator.invoker.base.AbstractInvoker; 5 | import com.greedystar.generator.utils.ConfigUtil; 6 | import com.greedystar.generator.utils.StringUtil; 7 | 8 | /** 9 | * @author GreedyStar 10 | * @since 2018/9/5 11 | */ 12 | public class One2ManyInvoker extends AbstractInvoker { 13 | 14 | private One2ManyInvoker() { 15 | 16 | } 17 | 18 | @Override 19 | protected void queryMetaData() throws Exception { 20 | tableInfos = connectionUtil.getMetaData(tableName); 21 | parentTableInfos = connectionUtil.getMetaData(parentTableName); 22 | } 23 | 24 | @Override 25 | protected void initTasks() { 26 | taskQueue.initOne2ManyTasks(this); 27 | } 28 | 29 | public static class Builder extends AbstractBuilder { 30 | 31 | public Builder() { 32 | invoker = new One2ManyInvoker(); 33 | } 34 | 35 | public Builder setTableName(String tableName) { 36 | invoker.setTableName(tableName); 37 | return this; 38 | } 39 | 40 | public Builder setClassName(String className) { 41 | invoker.setClassName(className); 42 | return this; 43 | } 44 | 45 | public Builder setParentTableName(String parentTableName) { 46 | invoker.setParentTableName(parentTableName); 47 | return this; 48 | } 49 | 50 | public Builder setParentClassName(String parentClassName) { 51 | invoker.setParentClassName(parentClassName); 52 | return this; 53 | } 54 | 55 | public Builder setParentForeignKey(String parentForeignKey) { 56 | invoker.setParentForeignKey(parentForeignKey); 57 | return this; 58 | } 59 | 60 | @Override 61 | public void checkBeforeBuild() throws Exception { 62 | if (ConfigUtil.getConfiguration().isMybatisPlusEnable() || ConfigUtil.getConfiguration().isJpaEnable()) { 63 | throw new Exception("JPA mode and Mybatis-Plus mode only supported in SingleInvoker."); 64 | } 65 | if (StringUtil.isEmpty(invoker.getTableName())) { 66 | throw new Exception("Table name can't be null."); 67 | } 68 | if (StringUtil.isEmpty(invoker.getParentTableName())) { 69 | throw new Exception("Parent table name can't be null."); 70 | } 71 | if (StringUtil.isEmpty(invoker.getParentForeignKey())) { 72 | throw new Exception("Parent foreign key can't be null."); 73 | } 74 | if (StringUtil.isEmpty(invoker.getClassName())) { 75 | invoker.setClassName(StringUtil.tableName2ClassName(invoker.getTableName())); 76 | } 77 | if (StringUtil.isEmpty(invoker.getParentClassName())) { 78 | invoker.setParentClassName(StringUtil.tableName2ClassName(invoker.getParentTableName())); 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/invoker/SingleInvoker.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.invoker; 2 | 3 | import com.greedystar.generator.invoker.base.AbstractBuilder; 4 | import com.greedystar.generator.invoker.base.AbstractInvoker; 5 | import com.greedystar.generator.utils.StringUtil; 6 | 7 | /** 8 | * @author GreedyStar 9 | * @since 2018/9/5 10 | */ 11 | public class SingleInvoker extends AbstractInvoker { 12 | 13 | private SingleInvoker() { 14 | 15 | } 16 | 17 | @Override 18 | protected void queryMetaData() throws Exception { 19 | tableInfos = connectionUtil.getMetaData(tableName); 20 | } 21 | 22 | @Override 23 | protected void initTasks() { 24 | taskQueue.initSingleTasks(this); 25 | } 26 | 27 | public static class Builder extends AbstractBuilder { 28 | 29 | public Builder() { 30 | invoker = new SingleInvoker(); 31 | } 32 | 33 | public Builder setTableName(String tableName) { 34 | invoker.setTableName(tableName); 35 | return this; 36 | } 37 | 38 | public Builder setClassName(String className) { 39 | invoker.setClassName(className); 40 | return this; 41 | } 42 | 43 | @Override 44 | public void checkBeforeBuild() throws Exception { 45 | if (StringUtil.isEmpty(invoker.getTableName())) { 46 | throw new Exception("Table name can't be null."); 47 | } 48 | if (StringUtil.isEmpty(invoker.getClassName())) { 49 | invoker.setClassName(StringUtil.tableName2ClassName(invoker.getTableName())); 50 | } 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/invoker/base/AbstractBuilder.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.invoker.base; 2 | 3 | /** 4 | * @author GreedyStar 5 | * @since 2018/9/5 6 | */ 7 | public abstract class AbstractBuilder { 8 | protected AbstractInvoker invoker; 9 | 10 | public Invoker build() { 11 | if (!isParamtersValid()) { 12 | return null; 13 | } 14 | return invoker; 15 | } 16 | 17 | private boolean isParamtersValid() { 18 | try { 19 | checkBeforeBuild(); 20 | } catch (Exception e) { 21 | e.printStackTrace(); 22 | return false; 23 | } 24 | return true; 25 | } 26 | 27 | /** 28 | * 在创建invoker对象前进行一些检查,由子类去实现 29 | * 30 | * @throws Exception 检查失败则抛出异常 31 | */ 32 | protected abstract void checkBeforeBuild() throws Exception; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/invoker/base/AbstractInvoker.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.invoker.base; 2 | 3 | import com.greedystar.generator.db.ConnectionUtil; 4 | import com.greedystar.generator.entity.ColumnInfo; 5 | import com.greedystar.generator.task.base.AbstractTask; 6 | import com.greedystar.generator.utils.TaskQueue; 7 | import freemarker.template.TemplateException; 8 | 9 | import java.io.IOException; 10 | import java.util.List; 11 | import java.util.concurrent.ExecutorService; 12 | import java.util.concurrent.Executors; 13 | 14 | /** 15 | * @author GreedyStar 16 | * @since 2018/9/5 17 | */ 18 | public abstract class AbstractInvoker implements Invoker { 19 | /** 20 | * 主表名 21 | */ 22 | protected String tableName; 23 | /** 24 | * 主类名 25 | */ 26 | protected String className; 27 | /** 28 | * 父表名 29 | */ 30 | protected String parentTableName; 31 | /** 32 | * 父类名 33 | */ 34 | protected String parentClassName; 35 | /** 36 | * 外键列名 37 | */ 38 | protected String foreignKey; 39 | /** 40 | * 关系表名 41 | */ 42 | protected String relationalTableName; 43 | /** 44 | * 父表外键列名 45 | */ 46 | protected String parentForeignKey; 47 | /** 48 | * 主表元数据 49 | */ 50 | protected List tableInfos; 51 | /** 52 | * 父表元数据 53 | */ 54 | protected List parentTableInfos; 55 | /** 56 | * 数据库连接工具 57 | */ 58 | protected ConnectionUtil connectionUtil = new ConnectionUtil(); 59 | /** 60 | * 任务队列 61 | */ 62 | protected TaskQueue taskQueue = new TaskQueue(); 63 | /** 64 | * 线程池 65 | */ 66 | private ExecutorService executorPool = Executors.newFixedThreadPool(6); 67 | 68 | /** 69 | * 获取表元数据,模板方法,由子类实现 70 | * 71 | * @throws Exception 获取元数据失败则抛出异常 72 | */ 73 | protected abstract void queryMetaData() throws Exception; 74 | 75 | /** 76 | * 初始化代码生成任务,模板方法,由子类实现 77 | */ 78 | protected abstract void initTasks(); 79 | 80 | /** 81 | * 开始生成代码 82 | */ 83 | @Override 84 | public void execute() { 85 | try { 86 | queryMetaData(); 87 | initTasks(); 88 | while (!taskQueue.isEmpty()) { 89 | AbstractTask task = taskQueue.poll(); 90 | executorPool.execute(() -> { 91 | try { 92 | task.run(); 93 | } catch (IOException e) { 94 | e.printStackTrace(); 95 | } catch (TemplateException e) { 96 | e.printStackTrace(); 97 | } 98 | }); 99 | } 100 | executorPool.shutdown(); 101 | } catch (Exception e) { 102 | e.printStackTrace(); 103 | } 104 | } 105 | 106 | public void setTableName(String tableName) { 107 | this.tableName = tableName; 108 | } 109 | 110 | public void setClassName(String className) { 111 | this.className = className; 112 | } 113 | 114 | public void setParentTableName(String parentTableName) { 115 | this.parentTableName = parentTableName; 116 | } 117 | 118 | public void setParentClassName(String parentClassName) { 119 | this.parentClassName = parentClassName; 120 | } 121 | 122 | public void setForeignKey(String foreignKey) { 123 | this.foreignKey = foreignKey; 124 | } 125 | 126 | public void setRelationalTableName(String relationalTableName) { 127 | this.relationalTableName = relationalTableName; 128 | } 129 | 130 | public void setParentForeignKey(String parentForeignKey) { 131 | this.parentForeignKey = parentForeignKey; 132 | } 133 | 134 | public String getTableName() { 135 | return tableName; 136 | } 137 | 138 | public String getClassName() { 139 | return className; 140 | } 141 | 142 | public String getParentTableName() { 143 | return parentTableName; 144 | } 145 | 146 | public String getParentClassName() { 147 | return parentClassName; 148 | } 149 | 150 | public String getForeignKey() { 151 | return foreignKey; 152 | } 153 | 154 | public String getRelationalTableName() { 155 | return relationalTableName; 156 | } 157 | 158 | public String getParentForeignKey() { 159 | return parentForeignKey; 160 | } 161 | 162 | public List getTableInfos() { 163 | return tableInfos; 164 | } 165 | 166 | public void setTableInfos(List tableInfos) { 167 | this.tableInfos = tableInfos; 168 | } 169 | 170 | public List getParentTableInfos() { 171 | return parentTableInfos; 172 | } 173 | 174 | public void setParentTableInfos(List parentTableInfos) { 175 | this.parentTableInfos = parentTableInfos; 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/invoker/base/Invoker.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.invoker.base; 2 | 3 | /** 4 | * @author GreedyStar 5 | * @since 2018-09-10 6 | */ 7 | public interface Invoker { 8 | 9 | public void execute(); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/task/ControllerTask.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.task; 2 | 3 | import com.greedystar.generator.entity.ColumnInfo; 4 | import com.greedystar.generator.entity.Constant; 5 | import com.greedystar.generator.invoker.base.AbstractInvoker; 6 | import com.greedystar.generator.task.base.AbstractTask; 7 | import com.greedystar.generator.utils.*; 8 | import freemarker.template.TemplateException; 9 | 10 | import java.io.IOException; 11 | import java.util.HashMap; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | /** 16 | * @author GreedyStar 17 | * @since 2018/4/20 18 | */ 19 | public class ControllerTask extends AbstractTask { 20 | 21 | public ControllerTask(AbstractInvoker invoker) { 22 | this.invoker = invoker; 23 | } 24 | 25 | @Override 26 | public void run() throws IOException, TemplateException { 27 | // 构造Controller填充数据 28 | Map controllerData = new HashMap<>(); 29 | controllerData.put("Configuration", ConfigUtil.getConfiguration()); 30 | String serviceClassName; 31 | String serviceImport; 32 | if (StringUtil.isEmpty(ConfigUtil.getConfiguration().getPath().getInterf())) { 33 | serviceClassName = ConfigUtil.getConfiguration().getName().getService().replace(Constant.PLACEHOLDER, invoker.getClassName()); 34 | serviceImport = String.format("import %s.%s.%s;", ConfigUtil.getConfiguration().getPackageName(), 35 | ConfigUtil.getConfiguration().getPath().getService(), serviceClassName); 36 | } else { 37 | serviceClassName = ConfigUtil.getConfiguration().getName().getInterf().replace(Constant.PLACEHOLDER, invoker.getClassName()); 38 | serviceImport = String.format("import %s.%s.%s;", ConfigUtil.getConfiguration().getPackageName(), 39 | ConfigUtil.getConfiguration().getPath().getInterf(), serviceClassName); 40 | } 41 | controllerData.put("ServiceImport", serviceImport); 42 | controllerData.put("ServiceClassName", serviceClassName); 43 | controllerData.put("ServiceEntityName", StringUtil.firstToLowerCase(serviceClassName)); 44 | controllerData.put("ControllerClassName", ConfigUtil.getConfiguration().getName().getController() 45 | .replace(Constant.PLACEHOLDER, invoker.getClassName())); 46 | controllerData.put("ClassName", ConfigUtil.getConfiguration().getName().getEntity() 47 | .replace(Constant.PLACEHOLDER, invoker.getClassName())); 48 | controllerData.put("EntityName", StringUtil.firstToLowerCase(invoker.getClassName())); 49 | controllerData.put("pkType", getPrimaryKeyType(invoker.getTableInfos())); 50 | String filePath = FileUtil.getSourcePath() + StringUtil.package2Path(ConfigUtil.getConfiguration().getPackageName()) + 51 | StringUtil.package2Path(ConfigUtil.getConfiguration().getPath().getController()); 52 | String fileName = ConfigUtil.getConfiguration().getName().getController().replace(Constant.PLACEHOLDER, invoker.getClassName()) + ".java"; 53 | // 生成Controller文件 54 | FileUtil.generateToJava(FreemarkerConfigUtil.TYPE_CONTROLLER, controllerData, filePath, fileName); 55 | } 56 | 57 | /** 58 | * 获取主键列对应的属性类型 59 | * 60 | * @param columnInfos 61 | * @return 62 | */ 63 | private String getPrimaryKeyType(List columnInfos) { 64 | if (!ConfigUtil.getConfiguration().isJpaEnable()) { 65 | return "Serializable"; 66 | } 67 | for (ColumnInfo info : columnInfos) { 68 | if (info.isPrimaryKey()) { 69 | return info.getPropertyType(); 70 | } 71 | } 72 | return "Serializable"; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/task/DaoTask.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.task; 2 | 3 | import com.greedystar.generator.entity.Constant; 4 | import com.greedystar.generator.invoker.base.AbstractInvoker; 5 | import com.greedystar.generator.task.base.AbstractTask; 6 | import com.greedystar.generator.utils.*; 7 | import freemarker.template.TemplateException; 8 | 9 | import java.io.IOException; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | /** 14 | * @author GreedyStar 15 | * @since 2018/4/20 16 | */ 17 | public class DaoTask extends AbstractTask { 18 | 19 | public DaoTask(AbstractInvoker invoker) { 20 | this.invoker = invoker; 21 | } 22 | 23 | @Override 24 | public void run() throws IOException, TemplateException { 25 | // 构造Dao填充数据 26 | Map daoData = new HashMap<>(); 27 | daoData.put("Configuration", ConfigUtil.getConfiguration()); 28 | daoData.put("ClassName", ConfigUtil.getConfiguration().getName().getEntity().replace(Constant.PLACEHOLDER, invoker.getClassName())); 29 | daoData.put("EntityName", StringUtil.firstToLowerCase(invoker.getClassName())); 30 | daoData.put("DaoClassName", ConfigUtil.getConfiguration().getName().getDao().replace(Constant.PLACEHOLDER, invoker.getClassName())); 31 | String filePath = FileUtil.getSourcePath() + StringUtil.package2Path(ConfigUtil.getConfiguration().getPackageName()) 32 | + StringUtil.package2Path(ConfigUtil.getConfiguration().getPath().getDao()); 33 | String fileName = ConfigUtil.getConfiguration().getName().getDao().replace(Constant.PLACEHOLDER, invoker.getClassName()) + ".java"; 34 | // 生成dao文件 35 | FileUtil.generateToJava(FreemarkerConfigUtil.TYPE_DAO, daoData, filePath, fileName); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/task/EntityTask.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.task; 2 | 3 | import com.greedystar.generator.entity.ColumnInfo; 4 | import com.greedystar.generator.entity.Constant; 5 | import com.greedystar.generator.entity.IdStrategy; 6 | import com.greedystar.generator.entity.Mode; 7 | import com.greedystar.generator.invoker.base.AbstractInvoker; 8 | import com.greedystar.generator.task.base.AbstractTask; 9 | import com.greedystar.generator.utils.*; 10 | import freemarker.template.TemplateException; 11 | 12 | import java.io.IOException; 13 | import java.util.HashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | /** 18 | * @author GreedyStar 19 | * @since 2018/4/20 20 | */ 21 | public class EntityTask extends AbstractTask { 22 | /** 23 | * 业务表元数据 24 | */ 25 | private List tableInfos; 26 | /** 27 | * 任务模式 28 | */ 29 | private Mode mode; 30 | 31 | public EntityTask(Mode mode, AbstractInvoker invoker) { 32 | this.mode = mode; 33 | this.invoker = invoker; 34 | if (Mode.ENTITY_MAIN.equals(mode)) { 35 | this.tableInfos = invoker.getTableInfos(); 36 | } else if (Mode.ENTITY_PARENT.equals(mode)) { 37 | this.tableInfos = invoker.getParentTableInfos(); 38 | } 39 | } 40 | 41 | @Override 42 | public void run() throws IOException, TemplateException { 43 | // 构造Entity填充数据 44 | String className = null; 45 | String remarks = null; 46 | if (Mode.ENTITY_MAIN.equals(mode)) { 47 | className = ConfigUtil.getConfiguration().getName().getEntity().replace(Constant.PLACEHOLDER, invoker.getClassName()); 48 | remarks = invoker.getTableInfos().get(0).getTableRemarks(); 49 | } else if (Mode.ENTITY_PARENT.equals(mode)) { 50 | className = ConfigUtil.getConfiguration().getName().getEntity().replace(Constant.PLACEHOLDER, invoker.getParentClassName()); 51 | remarks = invoker.getParentTableInfos().get(0).getTableRemarks(); 52 | } 53 | Map entityData = new HashMap<>(); 54 | entityData.put("Configuration", ConfigUtil.getConfiguration()); 55 | entityData.put("TableName", invoker.getTableName()); 56 | entityData.put("ClassName", className); 57 | entityData.put("Remarks", remarks); 58 | entityData.put("Properties", entityProperties(invoker)); 59 | entityData.put("Methods", entityMethods(invoker)); 60 | String filePath = FileUtil.getSourcePath() + StringUtil.package2Path(ConfigUtil.getConfiguration().getPackageName()) 61 | + StringUtil.package2Path(ConfigUtil.getConfiguration().getPath().getEntity()); 62 | String fileName = className + ".java"; 63 | // 生成Entity文件 64 | FileUtil.generateToJava(FreemarkerConfigUtil.TYPE_ENTITY, entityData, filePath, fileName); 65 | } 66 | 67 | /** 68 | * 生成实体类属性字段 69 | * 70 | * @param invoker 执行器 71 | * @return 属性代码段 72 | */ 73 | public String entityProperties(AbstractInvoker invoker) { 74 | StringBuilder sb = new StringBuilder(); 75 | tableInfos.forEach(ForEachUtil.withIndex((info, index) -> { 76 | if (info.getColumnName().equals(invoker.getForeignKey())) { 77 | return; 78 | } 79 | sb.append(index == 0 ? "" : Constant.SPACE_4); 80 | generateRemarks(sb, info); 81 | generateORMAnnotation(sb, info); 82 | sb.append(Constant.SPACE_4).append(String.format("private %s %s;\n", info.getPropertyType(), info.getPropertyName())); 83 | sb.append("\n"); 84 | })); 85 | // 生成父表实体类时,直接截断后续生成依赖关系的代码 86 | if (Mode.ENTITY_PARENT.equals(mode)) { 87 | return sb.toString(); 88 | } 89 | if (!StringUtil.isEmpty(invoker.getRelationalTableName()) || !StringUtil.isEmpty(invoker.getParentForeignKey())) { 90 | // 多对多 or 一对多 91 | sb.append(Constant.SPACE_4).append(String.format("private List<%s> %ss;\n", invoker.getParentClassName(), 92 | StringUtil.firstToLowerCase(invoker.getParentClassName()))); 93 | sb.append("\n"); 94 | } else if (!StringUtil.isEmpty(invoker.getForeignKey())) { 95 | // 多对一 96 | sb.append(Constant.SPACE_4).append(String.format("private %s %s;\n", invoker.getParentClassName(), 97 | StringUtil.firstToLowerCase(invoker.getParentClassName()))); 98 | sb.append("\n"); 99 | } 100 | return sb.toString(); 101 | } 102 | 103 | /** 104 | * 生成实体类存取方法 105 | * 106 | * @param invoker 执行器 107 | * @return 方法代码段 108 | */ 109 | public String entityMethods(AbstractInvoker invoker) { 110 | if (ConfigUtil.getConfiguration().isLombokEnable()) { 111 | return ""; 112 | } 113 | StringBuilder sb = new StringBuilder(); 114 | tableInfos.forEach(ForEachUtil.withIndex((info, index) -> { 115 | if (info.getColumnName().equals(invoker.getForeignKey())) { 116 | return; 117 | } 118 | String setter = String.format("public void set%s (%s %s) { this.%s = %s; } \n\n", StringUtil.firstToUpperCase(info.getPropertyName()), 119 | info.getPropertyType(), info.getPropertyName(), info.getPropertyName(), info.getPropertyName()); 120 | sb.append(index == 0 ? "" : Constant.SPACE_4).append(setter); 121 | String getter; 122 | if (info.getPropertyType().equals("boolean")) { 123 | getter = String.format("public %s is%s () { return this.%s; } \n\n", info.getPropertyType(), 124 | StringUtil.firstToUpperCase(info.getPropertyName()), info.getPropertyName()); 125 | } else { 126 | getter = String.format("public %s get%s () { return this.%s; } \n\n", info.getPropertyType(), 127 | StringUtil.firstToUpperCase(info.getPropertyName()), info.getPropertyName()); 128 | } 129 | sb.append(Constant.SPACE_4).append(getter); 130 | })); 131 | // 生成父表实体类时,直接截断后续生成依赖关系的代码 132 | if (Mode.ENTITY_PARENT.equals(mode)) { 133 | return sb.toString(); 134 | } 135 | if (!StringUtil.isEmpty(invoker.getRelationalTableName()) || !StringUtil.isEmpty(invoker.getParentForeignKey())) { 136 | // 多对多 137 | String setter = String.format("public void set%ss (List<%s> %ss) { this.%ss = %ss; }\n\n", invoker.getParentClassName(), 138 | invoker.getParentClassName(), StringUtil.firstToLowerCase(invoker.getParentClassName()), 139 | StringUtil.firstToLowerCase(invoker.getParentClassName()), StringUtil.firstToLowerCase(invoker.getParentClassName())); 140 | sb.append(Constant.SPACE_4).append(setter); 141 | String getter = String.format("public List<%s> get%ss () { return this.%ss; }\n\n", invoker.getParentClassName(), 142 | invoker.getParentClassName(), StringUtil.firstToLowerCase(invoker.getParentClassName())); 143 | sb.append(Constant.SPACE_4).append(getter); 144 | } else if (!StringUtil.isEmpty(invoker.getForeignKey())) { 145 | // 多对一 146 | String setter = String.format("public void set%s (%s %s) { this.%s = %s; }\n\n", invoker.getParentClassName(), 147 | invoker.getParentClassName(), StringUtil.firstToLowerCase(invoker.getParentClassName()), 148 | StringUtil.firstToLowerCase(invoker.getParentClassName()), StringUtil.firstToLowerCase(invoker.getParentClassName())); 149 | sb.append(Constant.SPACE_4).append(setter); 150 | String getter = String.format("public %s get%s () { return this.%s; }\n\n", invoker.getParentClassName(), invoker.getParentClassName(), 151 | StringUtil.firstToLowerCase(invoker.getParentClassName())); 152 | sb.append(Constant.SPACE_4).append(getter); 153 | } 154 | return sb.toString(); 155 | } 156 | 157 | /** 158 | * 为实体属性生成注释 159 | * 160 | * @param sb StringBuilder对象 161 | * @param info 列属性 162 | */ 163 | public void generateRemarks(StringBuilder sb, ColumnInfo info) { 164 | sb.append("/**").append("\n"); 165 | sb.append(Constant.SPACE_4).append(" * ").append(info.getRemarks()).append("\n"); 166 | sb.append(Constant.SPACE_4).append(" */").append("\n"); 167 | } 168 | 169 | /** 170 | * 为实体属性生成swagger注解 171 | * 我们不建议在entity(do)中使用swagger注解,在dto和vo中使用swagger注解更为优雅 172 | * 173 | * @param sb StringBuilder对象 174 | * @param info 列属性 175 | */ 176 | public void generateSwaggerAnnotation(StringBuilder sb, ColumnInfo info) { 177 | if (!ConfigUtil.getConfiguration().isSwaggerEnable()) { 178 | return; 179 | } 180 | sb.append(String.format("@ApiModelProperty(value = \"%s\", dataType = \"%s\")", 181 | info.getRemarks(), info.getPropertyType())); 182 | sb.append("\n"); 183 | } 184 | 185 | /** 186 | * 为实体属性生成Orm框架(jpa/mybatis-plus)注解 187 | * 188 | * @param sb StringBuilder对象 189 | * @param info 列属性 190 | */ 191 | public void generateORMAnnotation(StringBuilder sb, ColumnInfo info) { 192 | if (ConfigUtil.getConfiguration().isMybatisPlusEnable()) { 193 | if (info.isPrimaryKey()) { 194 | if (ConfigUtil.getConfiguration().getIdStrategy() == null || ConfigUtil.getConfiguration().getIdStrategy() == IdStrategy.AUTO) { 195 | sb.append(Constant.SPACE_4).append(String.format("@TableId(value = \"%s\", type = IdType.AUTO)\n", info.getColumnName())); 196 | } else if (ConfigUtil.getConfiguration().getIdStrategy() == IdStrategy.UUID) { 197 | sb.append(Constant.SPACE_4).append(String.format("@TableId(value = \"%s\", type = IdType.ASSIGN_UUID)\n", info.getColumnName())); 198 | } 199 | } else { 200 | sb.append(Constant.SPACE_4).append(String.format("@TableField(value = \"%s\")\n", info.getColumnName())); 201 | } 202 | } else if (ConfigUtil.getConfiguration().isJpaEnable()) { 203 | if (info.isPrimaryKey()) { 204 | if (ConfigUtil.getConfiguration().getIdStrategy() == null || ConfigUtil.getConfiguration().getIdStrategy() == IdStrategy.AUTO) { 205 | sb.append(Constant.SPACE_4).append("@Id\n"); 206 | sb.append(Constant.SPACE_4).append("@GeneratedValue(strategy = GenerationType.IDENTITY)\n"); 207 | } else if (ConfigUtil.getConfiguration().getIdStrategy() == IdStrategy.UUID) { 208 | sb.append(Constant.SPACE_4).append("@Id\n"); 209 | sb.append(Constant.SPACE_4).append("@GeneratedValue(generator = \"uuidGenerator\")\n"); 210 | sb.append(Constant.SPACE_4).append("@GenericGenerator(name = \"uuidGenerator\", strategy = \"uuid\")\n"); 211 | } 212 | } 213 | sb.append(Constant.SPACE_4).append(String.format("@Column(name = \"%s\")\n", info.getColumnName())); 214 | } 215 | } 216 | 217 | } 218 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/task/InterfaceTask.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.task; 2 | 3 | import com.greedystar.generator.entity.Constant; 4 | import com.greedystar.generator.invoker.base.AbstractInvoker; 5 | import com.greedystar.generator.task.base.AbstractTask; 6 | import com.greedystar.generator.utils.*; 7 | import freemarker.template.TemplateException; 8 | 9 | import java.io.IOException; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | /** 14 | * @author GreedyStar 15 | * @since 2019/1/24 16 | */ 17 | public class InterfaceTask extends AbstractTask { 18 | 19 | public InterfaceTask(AbstractInvoker invoker) { 20 | this.invoker = invoker; 21 | } 22 | 23 | @Override 24 | public void run() throws IOException, TemplateException { 25 | // 构造Service接口填充数据 26 | Map interfaceData = new HashMap<>(); 27 | interfaceData.put("Configuration", ConfigUtil.getConfiguration()); 28 | interfaceData.put("ClassName", ConfigUtil.getConfiguration().getName().getEntity().replace(Constant.PLACEHOLDER, 29 | invoker.getClassName())); 30 | interfaceData.put("EntityName", StringUtil.firstToLowerCase(invoker.getClassName())); 31 | interfaceData.put("InterfaceClassName", ConfigUtil.getConfiguration().getName().getInterf() 32 | .replace(Constant.PLACEHOLDER, invoker.getClassName())); 33 | String filePath = FileUtil.getSourcePath() + StringUtil.package2Path(ConfigUtil.getConfiguration().getPackageName()) 34 | + StringUtil.package2Path(ConfigUtil.getConfiguration().getPath().getInterf()); 35 | String fileName = ConfigUtil.getConfiguration().getName().getInterf().replace(Constant.PLACEHOLDER, invoker.getClassName()) + ".java"; 36 | // 生成Service接口文件 37 | FileUtil.generateToJava(FreemarkerConfigUtil.TYPE_INTERFACE, interfaceData, filePath, fileName); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/task/MapperTask.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.task; 2 | 3 | import com.greedystar.generator.entity.ColumnInfo; 4 | import com.greedystar.generator.entity.Constant; 5 | import com.greedystar.generator.invoker.base.AbstractInvoker; 6 | import com.greedystar.generator.task.base.AbstractTask; 7 | import com.greedystar.generator.utils.*; 8 | import freemarker.template.TemplateException; 9 | 10 | import java.io.IOException; 11 | import java.util.HashMap; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | /** 16 | * @author GreedyStar 17 | * @since 2018/4/20 18 | */ 19 | public class MapperTask extends AbstractTask { 20 | 21 | public MapperTask(AbstractInvoker invoker) { 22 | this.invoker = invoker; 23 | } 24 | 25 | @Override 26 | public void run() throws IOException, TemplateException { 27 | // 构造Mapper填充数据 28 | Map mapperData = new HashMap<>(); 29 | mapperData.put("Configuration", ConfigUtil.getConfiguration()); 30 | mapperData.put("ClassName", ConfigUtil.getConfiguration().getName().getEntity() 31 | .replace(Constant.PLACEHOLDER, invoker.getClassName())); 32 | mapperData.put("EntityName", StringUtil.firstToLowerCase(invoker.getClassName())); 33 | mapperData.put("DaoClassName", ConfigUtil.getConfiguration().getName().getDao() 34 | .replace(Constant.PLACEHOLDER, invoker.getClassName())); 35 | mapperData.put("TableName", invoker.getTableName()); 36 | mapperData.put("PrimaryKey", getPrimaryKeyColumnInfo(invoker.getTableInfos()).getColumnName()); 37 | mapperData.put("WhereId", "#{" + getPrimaryKeyColumnInfo(invoker.getTableInfos()).getPropertyName() + "}"); 38 | mapperData.put("PrimaryColumn", getPrimaryKeyColumnInfo(invoker.getTableInfos())); 39 | mapperData.put("InsertProperties", insertProperties()); 40 | mapperData.put("ColumnMap", columnMap()); 41 | mapperData.put("ResultMap", resultMap()); 42 | mapperData.put("InsertBatchValues", insertBatchValues()); 43 | mapperData.put("InsertValues", insertValues()); 44 | mapperData.put("UpdateProperties", updateProperties()); 45 | mapperData.put("Joins", joins()); 46 | if (!StringUtil.isEmpty(invoker.getRelationalTableName())) { 47 | // 多对多 48 | mapperData.put("Association", ""); 49 | mapperData.put("Collection", collection()); 50 | } else if (!StringUtil.isEmpty(invoker.getParentForeignKey())) { 51 | // 多对一 52 | mapperData.put("Association", ""); 53 | mapperData.put("Collection", collection()); 54 | } else if (!StringUtil.isEmpty(invoker.getForeignKey())) { 55 | // 一对多 56 | mapperData.put("Association", association()); 57 | mapperData.put("Collection", ""); 58 | } else { 59 | // 单表 60 | mapperData.put("Association", ""); 61 | mapperData.put("Collection", ""); 62 | } 63 | String filePath; 64 | if (ConfigUtil.getConfiguration().isMapperUnderSource()) { 65 | // mapper-under-source = true,表示将Mapper映射文件放在源文件目录下 66 | filePath = FileUtil.getSourcePath() + StringUtil.package2Path(ConfigUtil.getConfiguration().getPackageName()) 67 | + StringUtil.package2Path(ConfigUtil.getConfiguration().getPath().getMapper()); 68 | } else { 69 | // 默认情况下,将Mapper映射文件放在resources下 70 | filePath = FileUtil.getResourcePath() + StringUtil.package2Path(ConfigUtil.getConfiguration().getPath().getMapper()); 71 | } 72 | String fileName = ConfigUtil.getConfiguration().getName().getMapper().replace(Constant.PLACEHOLDER, invoker.getClassName()) + ".xml"; 73 | // 生成Mapper文件 74 | FileUtil.generateToJava(FreemarkerConfigUtil.TYPE_MAPPER, mapperData, filePath, fileName); 75 | } 76 | 77 | /** 78 | * 获取主键列 79 | * 80 | * @param list 81 | * @return 82 | */ 83 | private ColumnInfo getPrimaryKeyColumnInfo(List list) { 84 | for (ColumnInfo columnInfo : list) { 85 | if (columnInfo.isPrimaryKey()) { 86 | return columnInfo; 87 | } 88 | } 89 | return null; 90 | } 91 | 92 | /** 93 | * 生成columnMap 94 | * 95 | * @return ColumnMap代码段 96 | */ 97 | public String columnMap() { 98 | StringBuilder sb = new StringBuilder(); 99 | invoker.getTableInfos().forEach(ForEachUtil.withIndex((info, index) -> { 100 | if (info.getColumnName().equals(invoker.getForeignKey())) { 101 | return; 102 | } 103 | sb.append(index == 0 ? "" : Constant.SPACE_8); 104 | sb.append(String.format("`%s`.`%s`,\n", invoker.getTableName(), info.getColumnName())); 105 | })); 106 | if (invoker.getParentTableInfos() != null) { 107 | invoker.getParentTableInfos().forEach(ForEachUtil.withIndex((info, index) -> { 108 | sb.append(Constant.SPACE_8); 109 | if (!StringUtil.isEmpty(invoker.getRelationalTableName()) || !StringUtil.isEmpty(invoker.getParentForeignKey())) { 110 | sb.append(String.format("`%s`.`%s` AS `%ss.%s`,\n", invoker.getParentTableName(), info.getColumnName(), 111 | StringUtil.firstToLowerCase(invoker.getParentClassName()), info.getColumnName())); 112 | } else { 113 | sb.append(String.format("`%s`.`%s` AS `%s.%s`,\n", invoker.getParentTableName(), info.getColumnName(), 114 | StringUtil.firstToLowerCase(invoker.getParentClassName()), info.getColumnName())); 115 | } 116 | })); 117 | } 118 | return sb.toString().substring(0, sb.toString().length() - 2); 119 | } 120 | 121 | /** 122 | * 生成resultMap 123 | * 124 | * @return ResultMap代码段 125 | */ 126 | public String resultMap() { 127 | StringBuilder sb = new StringBuilder(); 128 | invoker.getTableInfos().forEach(ForEachUtil.withIndex((info, index) -> { 129 | if (info.getColumnName().equals(invoker.getForeignKey())) { 130 | return; 131 | } 132 | sb.append(index == 0 ? "" : Constant.SPACE_8); 133 | if (info.isPrimaryKey()) { 134 | sb.append(String.format("\n", info.getColumnName(), info.getPropertyName())); 135 | } else { 136 | sb.append(String.format("\n", info.getColumnName(), info.getPropertyName())); 137 | } 138 | })); 139 | return sb.toString(); 140 | } 141 | 142 | /** 143 | * 生成association 144 | * 145 | * @return association代码段 146 | */ 147 | public String association() { 148 | StringBuilder sb = new StringBuilder(); 149 | sb.append(String.format("\n", StringUtil.firstToLowerCase(invoker.getParentClassName()), 150 | ConfigUtil.getConfiguration().getPackageName() + "." + ConfigUtil.getConfiguration().getPath().getEntity(), 151 | invoker.getParentClassName())); 152 | invoker.getParentTableInfos().forEach(ForEachUtil.withIndex((info, index) -> { 153 | if (info.isPrimaryKey()) { 154 | sb.append(Constant.SPACE_12).append(String.format("\n", 155 | StringUtil.firstToLowerCase(invoker.getParentClassName()), info.getColumnName(), info.getPropertyName())); 156 | } else { 157 | sb.append(Constant.SPACE_12).append(String.format("\n", 158 | StringUtil.firstToLowerCase(invoker.getParentClassName()), info.getColumnName(), info.getPropertyName())); 159 | } 160 | })); 161 | sb.append(Constant.SPACE_8).append(""); 162 | return sb.toString(); 163 | } 164 | 165 | /** 166 | * 生成collection 167 | * 168 | * @return collection代码段 169 | */ 170 | public String collection() { 171 | StringBuilder sb = new StringBuilder(); 172 | sb.append(String.format("\n ", StringUtil.firstToLowerCase(invoker.getParentClassName()), 173 | ConfigUtil.getConfiguration().getPackageName() + "." + ConfigUtil.getConfiguration().getPath().getEntity(), 174 | invoker.getParentClassName())); 175 | invoker.getParentTableInfos().forEach(ForEachUtil.withIndex((info, index) -> { 176 | if (info.isPrimaryKey()) { 177 | sb.append(Constant.SPACE_12).append(String.format("\n", 178 | StringUtil.firstToLowerCase(invoker.getParentClassName()), info.getColumnName(), info.getPropertyName())); 179 | } else { 180 | sb.append(Constant.SPACE_12).append(String.format("\n", 181 | StringUtil.firstToLowerCase(invoker.getParentClassName()), info.getColumnName(), info.getPropertyName())); 182 | } 183 | })); 184 | sb.append(Constant.SPACE_8).append(""); 185 | return sb.toString(); 186 | } 187 | 188 | /** 189 | * 生成insertProperties 190 | * 191 | * @return insertProperties代码段 192 | */ 193 | public String insertProperties() { 194 | StringBuilder sb = new StringBuilder(); 195 | invoker.getTableInfos().forEach(ForEachUtil.withIndex((info, index) -> { 196 | sb.append(index == 0 ? "" : Constant.SPACE_12); 197 | sb.append(String.format("`%s`,\n", info.getColumnName())); 198 | })); 199 | return sb.toString().substring(0, sb.toString().length() - 2); 200 | } 201 | 202 | /** 203 | * 生成insertValues 204 | * 205 | * @return insertValues代码段 206 | */ 207 | public String insertValues() { 208 | StringBuilder sb = new StringBuilder(); 209 | invoker.getTableInfos().forEach(ForEachUtil.withIndex((info, index) -> { 210 | sb.append(index == 0 ? "" : Constant.SPACE_12); 211 | if (StringUtil.isEmpty(invoker.getRelationalTableName()) && !StringUtil.isEmpty(invoker.getForeignKey())) { 212 | if (info.getColumnName().equals(invoker.getForeignKey())) { 213 | sb.append(String.format("#{%s.%s},\n", StringUtil.firstToLowerCase(invoker.getParentClassName()), 214 | getPrimaryKeyColumnInfo(invoker.getParentTableInfos()).getPropertyName())); 215 | } else { 216 | sb.append(String.format("#{%s},\n", info.getPropertyName())); 217 | } 218 | } else { 219 | sb.append(String.format("#{%s},\n", info.getPropertyName())); 220 | } 221 | })); 222 | return sb.toString().substring(0, sb.toString().length() - 2); 223 | } 224 | 225 | /** 226 | * 生成insertBatchValues 227 | * 228 | * @return insertBatchValues代码段 229 | */ 230 | public String insertBatchValues() { 231 | StringBuilder sb = new StringBuilder(); 232 | invoker.getTableInfos().forEach(ForEachUtil.withIndex((info, index) -> { 233 | sb.append(index == 0 ? "" : Constant.SPACE_12); 234 | if (StringUtil.isEmpty(invoker.getRelationalTableName()) && !StringUtil.isEmpty(invoker.getForeignKey())) { 235 | if (info.getColumnName().equals(invoker.getForeignKey())) { 236 | sb.append(String.format("#{%s.%s.%s},\n", StringUtil.firstToLowerCase(invoker.getClassName()), 237 | StringUtil.firstToLowerCase(invoker.getParentClassName()), 238 | getPrimaryKeyColumnInfo(invoker.getParentTableInfos()).getPropertyName())); 239 | } else { 240 | sb.append(String.format("#{%s.%s},\n", StringUtil.firstToLowerCase(invoker.getClassName()), info.getPropertyName())); 241 | } 242 | } else { 243 | sb.append(String.format("#{%s.%s},\n", StringUtil.firstToLowerCase(invoker.getClassName()), info.getPropertyName())); 244 | } 245 | })); 246 | return sb.toString().substring(0, sb.toString().length() - 2); 247 | } 248 | 249 | /** 250 | * 生成updateProperties 251 | * 252 | * @return updateProperties代码段 253 | */ 254 | public String updateProperties() { 255 | StringBuilder sb = new StringBuilder(); 256 | invoker.getTableInfos().forEach(ForEachUtil.withIndex((info, index) -> { 257 | sb.append(index == 0 ? "" : Constant.SPACE_8); 258 | if (StringUtil.isEmpty(invoker.getRelationalTableName()) && !StringUtil.isEmpty(invoker.getForeignKey())) { 259 | if (info.getColumnName().equals(invoker.getForeignKey())) { 260 | sb.append(String.format("`%s` = #{%s.%s},\n", info.getColumnName(), 261 | StringUtil.firstToLowerCase(invoker.getParentClassName()), 262 | getPrimaryKeyColumnInfo(invoker.getParentTableInfos()).getPropertyName())); 263 | } else { 264 | sb.append(String.format("`%s` = #{%s},\n", info.getColumnName(), info.getPropertyName())); 265 | } 266 | } else { 267 | sb.append(String.format("`%s` = #{%s},\n", info.getColumnName(), info.getPropertyName())); 268 | } 269 | })); 270 | return sb.toString().substring(0, sb.toString().length() - 2); 271 | } 272 | 273 | /** 274 | * 生成joins代码段 275 | * 276 | * @return joins代码段 277 | */ 278 | public String joins() { 279 | StringBuilder sb = new StringBuilder(); 280 | if (!StringUtil.isEmpty(invoker.getRelationalTableName())) { 281 | // 多对多 282 | sb.append(String.format("LEFT JOIN `%s` ON `%s`.`%s` = `%s`.`%s`", invoker.getRelationalTableName(), 283 | invoker.getRelationalTableName(), invoker.getForeignKey(), invoker.getTableName(), 284 | getPrimaryKeyColumnInfo(invoker.getTableInfos()).getColumnName())); 285 | sb.append("\n").append(Constant.SPACE_8); 286 | sb.append(String.format("LEFT JOIN `%s` ON `%s`.`%s` = `%s`.`%s`", invoker.getParentTableName(), 287 | invoker.getParentTableName(), getPrimaryKeyColumnInfo(invoker.getParentTableInfos()).getColumnName(), 288 | invoker.getRelationalTableName(), invoker.getParentForeignKey())); 289 | } else if (!StringUtil.isEmpty(invoker.getParentForeignKey())) { 290 | // 一对多 291 | sb.append(String.format("LEFT JOIN `%s` ON `%s`.`%s` = `%s`.`%s`", invoker.getParentTableName(), 292 | invoker.getParentTableName(), invoker.getParentForeignKey(), invoker.getTableName(), 293 | getPrimaryKeyColumnInfo(invoker.getTableInfos()).getColumnName())); 294 | } else if (!StringUtil.isEmpty(invoker.getForeignKey())) { 295 | // 多对一 296 | sb.append(String.format("LEFT JOIN `%s` ON `%s`.%s = `%s`.`%s`", invoker.getParentTableName(), 297 | invoker.getParentTableName(), getPrimaryKeyColumnInfo(invoker.getParentTableInfos()).getColumnName(), 298 | invoker.getTableName(), invoker.getForeignKey())); 299 | } 300 | return sb.toString(); 301 | } 302 | 303 | } 304 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/task/ServiceTask.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.task; 2 | 3 | import com.greedystar.generator.entity.Constant; 4 | import com.greedystar.generator.invoker.base.AbstractInvoker; 5 | import com.greedystar.generator.task.base.AbstractTask; 6 | import com.greedystar.generator.utils.*; 7 | import freemarker.template.TemplateException; 8 | 9 | import java.io.IOException; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | /** 14 | * @author GreedyStar 15 | * @since 2018/4/20 16 | */ 17 | public class ServiceTask extends AbstractTask { 18 | 19 | public ServiceTask(AbstractInvoker invoker) { 20 | this.invoker = invoker; 21 | } 22 | 23 | @Override 24 | public void run() throws IOException, TemplateException { 25 | // 构造Service填充数据 26 | Map serviceData = new HashMap<>(); 27 | serviceData.put("Configuration", ConfigUtil.getConfiguration()); 28 | serviceData.put("ClassName", ConfigUtil.getConfiguration().getName().getEntity().replace(Constant.PLACEHOLDER, invoker.getClassName())); 29 | serviceData.put("EntityName", StringUtil.firstToLowerCase(invoker.getClassName())); 30 | serviceData.put("DaoClassName", ConfigUtil.getConfiguration().getName().getDao().replace(Constant.PLACEHOLDER, invoker.getClassName())); 31 | serviceData.put("DaoEntityName", StringUtil.firstToLowerCase(ConfigUtil.getConfiguration().getName().getDao() 32 | .replace(Constant.PLACEHOLDER, invoker.getClassName()))); 33 | String filePath = FileUtil.getSourcePath() + StringUtil.package2Path(ConfigUtil.getConfiguration().getPackageName()) 34 | + StringUtil.package2Path(ConfigUtil.getConfiguration().getPath().getService()); 35 | String fileName; 36 | /* 37 | * 根据用户是否配置了path节点下的interf属性来判断是否采用接口+实现类的方式 38 | */ 39 | String serviceClassName = ConfigUtil.getConfiguration().getName().getService().replace(Constant.PLACEHOLDER, invoker.getClassName()); 40 | if (StringUtil.isEmpty(ConfigUtil.getConfiguration().getPath().getInterf())) { 41 | serviceData.put("ServiceClassName", serviceClassName); 42 | serviceData.put("Implements", ""); 43 | serviceData.put("InterfaceImport", ""); 44 | serviceData.put("Override", ""); 45 | fileName = ConfigUtil.getConfiguration().getName().getService().replace(Constant.PLACEHOLDER, invoker.getClassName()) + ".java"; 46 | } else { 47 | // Service接口实现类默认由Impl结尾 48 | serviceClassName = serviceClassName.contains("Impl") ? serviceClassName : serviceClassName + "Impl"; 49 | serviceData.put("ServiceClassName", serviceClassName); 50 | serviceData.put("Implements", "implements " + ConfigUtil.getConfiguration().getName().getInterf() 51 | .replace(Constant.PLACEHOLDER, invoker.getClassName())); 52 | serviceData.put("InterfaceImport", "import " + ConfigUtil.getConfiguration().getPackageName() + "." 53 | + ConfigUtil.getConfiguration().getPath().getInterf() + "." 54 | + ConfigUtil.getConfiguration().getName().getInterf().replace(Constant.PLACEHOLDER, invoker.getClassName()) + ";"); 55 | serviceData.put("Override", "\n @Override"); 56 | fileName = serviceClassName + ".java"; 57 | } 58 | // 生成Service文件 59 | FileUtil.generateToJava(FreemarkerConfigUtil.TYPE_SERVICE, serviceData, filePath, fileName); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/task/base/AbstractTask.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.task.base; 2 | 3 | import com.greedystar.generator.invoker.base.AbstractInvoker; 4 | import freemarker.template.TemplateException; 5 | 6 | import java.io.IOException; 7 | import java.io.Serializable; 8 | 9 | /** 10 | * @author GreedyStar 11 | * @since 2018/4/20 12 | */ 13 | public abstract class AbstractTask implements Serializable { 14 | protected AbstractInvoker invoker; 15 | 16 | public AbstractTask() { 17 | } 18 | 19 | /** 20 | * 执行任务 21 | * 22 | * @throws IOException 文件读写异常 23 | * @throws TemplateException 模板异常 24 | */ 25 | public abstract void run() throws IOException, TemplateException; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/utils/ConfigUtil.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.utils; 2 | 3 | import com.greedystar.generator.entity.Configuration; 4 | import com.greedystar.generator.entity.Constant; 5 | import org.yaml.snakeyaml.Yaml; 6 | 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.net.URL; 10 | 11 | /** 12 | * 代码生成器的配置工具 13 | * 14 | * @author GreedyStar 15 | * @since 2018/9/7 16 | */ 17 | public class ConfigUtil { 18 | /** 19 | * 代码生成器的配置信息 20 | */ 21 | private static volatile Configuration configuration; 22 | 23 | /** 24 | * 获取配置信息 25 | * 26 | * @return 配置对象 27 | */ 28 | public static Configuration getConfiguration() { 29 | // ConfigUtil.getConfiguration()会在生成代码之前调用(获取业务表元数据),这里为null通常表示用户通过generator.yaml进行配置, 30 | if (null == ConfigUtil.configuration) { 31 | synchronized (ConfigUtil.class) { 32 | if (null == ConfigUtil.configuration) { 33 | readConfigurationFromFile(); // 从配置文件中读取配置信息 34 | } 35 | } 36 | } 37 | return ConfigUtil.configuration; 38 | } 39 | 40 | /** 41 | * 设置配置信息,提供给用户的外部配置接口,使用该接口则不会再到generator.yaml下读取配置 42 | * 43 | * @param configuration 配置对象 44 | */ 45 | public static void setConfiguration(Configuration configuration) { 46 | ConfigUtil.configuration = configuration; 47 | checkConfiguration(); 48 | } 49 | 50 | /** 51 | * 通过generator.yaml读取配置 52 | */ 53 | private static void readConfigurationFromFile() { 54 | try { 55 | URL url = ConfigUtil.class.getClassLoader().getResource("generator.yaml"); 56 | if (null == url || url.getPath().contains("jar")) { 57 | System.err.println("Can not find file named 'generator.yaml' under resources path, please make sure that you have defined that file."); 58 | System.exit(0); 59 | } else { 60 | String configStr = StringUtil.line2Camel(IOUtils.toString((InputStream) url.getContent())); 61 | InputStream inputStream = IOUtils.toInputStream(configStr); 62 | Yaml yaml = new Yaml(); 63 | ConfigUtil.setConfiguration(yaml.loadAs(inputStream, Configuration.class)); 64 | } 65 | } catch (IOException e) { 66 | e.printStackTrace(); 67 | System.exit(0); 68 | } 69 | } 70 | 71 | /** 72 | * 检查配置信息,用户可通过geneartor.yaml进行配置,或通过代码手动进行配置 73 | */ 74 | private static void checkConfiguration() { 75 | try { 76 | // 用户未配置类名后缀,那么添加一个默认的空对象,这里是为了保证在用户不配置name属性时,程序能够取得默认值 77 | if (null == ConfigUtil.configuration.getName()) { 78 | Configuration.Name nameConfig = new Configuration.Name(); 79 | if (ConfigUtil.configuration.isJpaEnable()) { 80 | nameConfig.setDao(Constant.PLACEHOLDER + "Repository"); 81 | } else if (ConfigUtil.configuration.isMybatisPlusEnable()) { 82 | nameConfig.setDao(Constant.PLACEHOLDER + "Mapper"); 83 | } 84 | ConfigUtil.configuration.setName(nameConfig); 85 | } 86 | // 检查db属性 87 | if (null == ConfigUtil.configuration.getDb()) { 88 | throw new Exception("Can not find configuration attribute named 'db', please make sure that you have configured that attribute."); 89 | } 90 | // 检查path属性 91 | if (null == ConfigUtil.configuration.getPath()) { 92 | throw new Exception("Can not find configuration attribute named 'path', please make sure that you have configured that attribute."); 93 | } 94 | // 检查db属性是否配置 95 | if (StringUtil.isEmpty(ConfigUtil.configuration.getDb().getUrl()) || StringUtil.isEmpty(ConfigUtil.configuration.getDb().getUsername())) { 96 | throw new Exception("Please configure the correct db connection parameters, i.e. url, username and password."); 97 | } 98 | // 检查顶级包名是否配置 99 | if (StringUtil.isEmpty(ConfigUtil.configuration.getPackageName())) { 100 | throw new Exception("Please configure the correct attribute named 'package-name' or 'packageName'."); 101 | } 102 | // 检查是否同时启用了jpa和mybatis-plus模式 103 | if (ConfigUtil.configuration.isMybatisPlusEnable() && ConfigUtil.configuration.isJpaEnable()) { 104 | throw new Exception("Can not enable JPA mode and MyBatis-Plus mode at the same time."); 105 | } else if (ConfigUtil.configuration.isMybatisPlusEnable() || ConfigUtil.configuration.isJpaEnable()) { 106 | // 禁止生成mapper.xml 107 | ConfigUtil.configuration.getPath().setMapper(null); 108 | } 109 | } catch (Exception e) { 110 | e.printStackTrace(); 111 | System.exit(0); 112 | } 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/utils/ConvertorUtil.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.utils; 2 | 3 | import com.greedystar.generator.convertor.DefaultConvertor; 4 | import com.greedystar.generator.convertor.TypeConvertor; 5 | 6 | import java.sql.JDBCType; 7 | 8 | /** 9 | * 类型转换器工具类 10 | * 11 | * @author GreedyStar 12 | * @since 2018/4/19 13 | */ 14 | public class ConvertorUtil { 15 | /** 16 | * 类型转换器 17 | */ 18 | private volatile static TypeConvertor convertor; 19 | 20 | /** 21 | * 将数据库数据类型转换为Java数据类型 22 | * 23 | * @param type jdbc类型 24 | * @return java类型 25 | */ 26 | public static String parseTypeFormSqlType(JDBCType type) { 27 | /* 28 | * 用户配置了错误的TypeConvertor会导致convertor为null 29 | * 在生成多表关系代码时,会有两个EntityTask并发执行,防止创建多个实例,采用double-check的单例模式 30 | */ 31 | if (convertor == null) { 32 | synchronized (ConvertorUtil.class) { 33 | if (convertor == null) { 34 | convertor = newInstance(); 35 | } 36 | } 37 | } 38 | return convertor.convertType(type); 39 | } 40 | 41 | private static TypeConvertor newInstance() { 42 | TypeConvertor convertor; 43 | String convertorClass = ConfigUtil.getConfiguration().getConvertor(); 44 | if (StringUtil.isEmpty(convertorClass)) { // 用户未配置类型转换器,使用默认转换器 45 | convertor = new DefaultConvertor(); 46 | } else { 47 | // 加载用户定义的类型转换器 48 | try { 49 | Class clazz = Class.forName(ConfigUtil.getConfiguration().getConvertor()); 50 | convertor = (TypeConvertor) clazz.newInstance(); 51 | } catch (Exception e) { 52 | System.err.println(String.format("Can not find %s, DefaultConvertor will be used.", convertorClass)); 53 | convertor = new DefaultConvertor(); 54 | } 55 | } 56 | return convertor; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/utils/FileUtil.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.utils; 2 | 3 | import freemarker.template.Template; 4 | import freemarker.template.TemplateException; 5 | 6 | import java.io.*; 7 | 8 | /** 9 | * @author GreedyStar 10 | * @since 2018/4/19 11 | */ 12 | public class FileUtil { 13 | 14 | /** 15 | * @param type 使用模板类型 16 | * @param data 填充数据 17 | * @param filePath 输出文件 18 | * @param fileName 文件名 19 | * @throws IOException 文件读写异常 20 | * @throws TemplateException 模板异常 21 | */ 22 | public static void generateToJava(int type, Object data, String filePath, String fileName) throws IOException, TemplateException { 23 | String path = filePath + fileName; // 待生成的代码文件路径 24 | // 已存在的文件不予覆盖 25 | File file = new File(path); 26 | if (file.exists() && !ConfigUtil.getConfiguration().isFileOverride()) { 27 | path += ".generated"; 28 | System.err.printf("%s already exit. Generating %s \n", fileName, path); 29 | } else { 30 | System.out.printf("Generating %s \n", path); 31 | } 32 | // 代码生成路径目录不存在则自动创建 33 | if (!file.getParentFile().exists()) { 34 | file.getParentFile().mkdirs(); 35 | } 36 | Template tpl = getTemplate(type); // 获取模板文件 37 | // 填充数据 38 | StringWriter writer = new StringWriter(); 39 | tpl.process(data, writer); 40 | writer.flush(); 41 | // 写入文件 42 | FileOutputStream fos = new FileOutputStream(path); 43 | OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8"); 44 | BufferedWriter bw = new BufferedWriter(osw, 1024); 45 | tpl.process(data, bw); 46 | writer.close(); 47 | bw.close(); 48 | } 49 | 50 | /** 51 | * 获取模板 52 | * 53 | * @param type 模板类型 54 | * @return 55 | * @throws IOException 56 | */ 57 | private static Template getTemplate(int type) throws IOException { 58 | switch (type) { 59 | case FreemarkerConfigUtil.TYPE_ENTITY: 60 | return FreemarkerConfigUtil.getInstance().getTemplate("Entity.ftl"); 61 | case FreemarkerConfigUtil.TYPE_DAO: 62 | return FreemarkerConfigUtil.getInstance().getTemplate("Dao.ftl"); 63 | case FreemarkerConfigUtil.TYPE_SERVICE: 64 | return FreemarkerConfigUtil.getInstance().getTemplate("Service.ftl"); 65 | case FreemarkerConfigUtil.TYPE_CONTROLLER: 66 | return FreemarkerConfigUtil.getInstance().getTemplate("Controller.ftl"); 67 | case FreemarkerConfigUtil.TYPE_MAPPER: 68 | return FreemarkerConfigUtil.getInstance().getTemplate("Mapper.ftl"); 69 | case FreemarkerConfigUtil.TYPE_INTERFACE: 70 | return FreemarkerConfigUtil.getInstance().getTemplate("Interface.ftl"); 71 | default: 72 | return null; 73 | } 74 | } 75 | 76 | /** 77 | * 获取项目主目录 78 | * 79 | * @return 项目根路径 80 | */ 81 | private static String getBasicProjectPath() { 82 | StringBuilder sb = new StringBuilder(); 83 | String path = FileUtil.class.getClassLoader().getResource("").getPath().replace("/", File.separator); 84 | if (path.contains("target")) { 85 | sb.append(path, 0, path.indexOf("target")); 86 | } else if (path.contains("build")) { 87 | sb.append(path, 0, path.indexOf("build")); 88 | } 89 | sb.append("src").append(File.separator).append("main").append(File.separator); 90 | return sb.toString(); 91 | } 92 | 93 | /** 94 | * 获取源码路径 95 | * 96 | * @return 源码路径 97 | */ 98 | public static String getSourcePath() { 99 | StringBuilder sb = new StringBuilder(); 100 | sb.append(getBasicProjectPath()).append("java").append(File.separator); 101 | return sb.toString(); 102 | } 103 | 104 | /** 105 | * 获取资源文件路径 106 | * 107 | * @return 资源路径 108 | */ 109 | public static String getResourcePath() { 110 | StringBuilder sb = new StringBuilder(); 111 | sb.append(getBasicProjectPath()).append("resources").append(File.separator); 112 | return sb.toString(); 113 | } 114 | 115 | public static void main(String[] args) { 116 | System.out.println(getResourcePath()); 117 | System.out.println(getSourcePath()); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/utils/ForEachUtil.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.utils; 2 | 3 | import java.util.function.BiConsumer; 4 | import java.util.function.Consumer; 5 | 6 | /** 7 | * @author GreedyStar 8 | * @since 2020/8/1 9 | */ 10 | public class ForEachUtil { 11 | 12 | /** 13 | * 带索引的foreach工具 14 | * 15 | * @param consumer consumer 16 | * @param 泛型 17 | * @return consumer 18 | */ 19 | public static Consumer withIndex(BiConsumer consumer) { 20 | Index index = new Index(); 21 | return t -> { 22 | int i = index.value++; 23 | consumer.accept(t, i); 24 | }; 25 | } 26 | 27 | private static class Index { 28 | int value; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/utils/FreemarkerConfigUtil.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.utils; 2 | 3 | import freemarker.template.Configuration; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.util.Locale; 8 | 9 | /** 10 | * @author GreedyStar 11 | * @since 2018/4/19 12 | */ 13 | public class FreemarkerConfigUtil { 14 | /** 15 | * 模板路径 16 | */ 17 | private static String path = new File(FreemarkerConfigUtil.class.getClassLoader().getResource("ftls").getFile()).getPath(); 18 | /** 19 | * freemarker配置 20 | */ 21 | private static volatile Configuration configuration; 22 | public final static int TYPE_ENTITY = 0; 23 | public final static int TYPE_DAO = 1; 24 | public final static int TYPE_SERVICE = 2; 25 | public final static int TYPE_CONTROLLER = 3; 26 | public final static int TYPE_MAPPER = 4; 27 | public final static int TYPE_INTERFACE = 5; 28 | 29 | public static Configuration getInstance() { 30 | if (null == configuration) { 31 | synchronized (FreemarkerConfigUtil.class) { 32 | if (null == configuration) { 33 | configuration = new Configuration(Configuration.VERSION_2_3_23); 34 | try { 35 | if (path.contains("jar")) { 36 | configuration.setClassForTemplateLoading(FreemarkerConfigUtil.class, "/ftls"); 37 | } else { 38 | configuration.setDirectoryForTemplateLoading(new File(path)); 39 | } 40 | } catch (IOException e) { 41 | e.printStackTrace(); 42 | } 43 | configuration.setEncoding(Locale.CHINA, "utf-8"); 44 | } 45 | } 46 | } 47 | return configuration; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/utils/IOUtils.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.utils; 2 | 3 | import java.io.*; 4 | import java.nio.charset.StandardCharsets; 5 | import java.sql.SQLException; 6 | 7 | /** 8 | * @author GreedyStar 9 | * @since 2021-4-27 10 | */ 11 | public class IOUtils { 12 | 13 | /** 14 | * 输入流转字符串 15 | * 16 | * @param inputStream 输入流 17 | * @return 转换后的字符串 18 | * @throws IOException IOException 19 | */ 20 | public static String toString(InputStream inputStream) throws IOException { 21 | StringBuilder sb = new StringBuilder(); 22 | String line; 23 | BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); 24 | while ((line = br.readLine()) != null) { 25 | sb.append(line); 26 | } 27 | return sb.toString(); 28 | } 29 | 30 | /** 31 | * 字符串转输入流 32 | * 33 | * @param string 字符串 34 | * @return 转换后的输入流 35 | */ 36 | public static InputStream toInputStream(String string) { 37 | return new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8)); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/utils/StringUtil.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.utils; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * @author GreedyStar 7 | * @since 2018-09-10 8 | */ 9 | public class StringUtil { 10 | 11 | /** 12 | * 判断字符串是否为空 13 | * 14 | * @param string 待检测字符串 15 | * @return 是否为空 16 | */ 17 | public static boolean isEmpty(String string) { 18 | if (string == null || string.trim().equals("")) { 19 | return true; 20 | } else { 21 | return false; 22 | } 23 | } 24 | 25 | /** 26 | * 首字母大写 27 | * 28 | * @param string 待处理字符串 29 | * @return 处理后字符串 30 | */ 31 | public static String firstToUpperCase(String string) { 32 | StringBuilder sb = new StringBuilder(); 33 | sb.append(string.substring(0, 1).toUpperCase()).append(string.substring(1)); 34 | return sb.toString(); 35 | } 36 | 37 | 38 | /** 39 | * 首字母小写 40 | * 41 | * @param string 待处理字符串 42 | * @return 处理后字符串 43 | */ 44 | public static String firstToLowerCase(String string) { 45 | StringBuilder sb = new StringBuilder(); 46 | sb.append(string.substring(0, 1).toLowerCase()).append(string.substring(1)); 47 | return sb.toString(); 48 | } 49 | 50 | /** 51 | * 数据库列名转换为实体的属性名 52 | * 53 | * @param columnName 列名 54 | * @return 转换后的实体属性名 55 | */ 56 | public static String columnName2PropertyName(String columnName) { 57 | if (isEmpty(columnName)) { 58 | return ""; 59 | } 60 | if (!columnName.contains("_")) { // 列名中不包含 “_” 61 | if (isAllUpperCase(columnName)) { 62 | return columnName.toLowerCase(); 63 | } 64 | return columnName; 65 | } 66 | StringBuilder sb = new StringBuilder(); 67 | String[] str = columnName.toLowerCase().split("_"); 68 | sb.append(str[0]); 69 | for (int i = 1; i < str.length; i++) { 70 | sb.append(firstToUpperCase(str[i])); 71 | } 72 | return sb.toString(); 73 | } 74 | 75 | /** 76 | * 以驼峰命名法生成类名,用于未指定类名时自动生成类名,如sys_user自动生成类名SysUser 77 | * 78 | * @param tableName 表名 79 | * @return 驼峰命名类名 80 | */ 81 | public static String tableName2ClassName(String tableName) { 82 | String[] nameStrs = tableName.split("_"); 83 | StringBuilder sb = new StringBuilder(); 84 | for (String string : nameStrs) { 85 | sb.append(string.substring(0, 1).toUpperCase()).append(string.substring(1)); 86 | } 87 | return sb.toString(); 88 | } 89 | 90 | /** 91 | * 给定字符串除特定符号外的字符是否全部大写 92 | * 93 | * @param string 待检测字符串 94 | * @return 是否全大写 95 | */ 96 | public static boolean isAllUpperCase(String string) { 97 | for (Character c : string.replace("_", "").toCharArray()) { 98 | if (!Character.isUpperCase(c)) { 99 | return false; 100 | } 101 | } 102 | return true; 103 | } 104 | 105 | /** 106 | * 包名转换为文件系统路径 107 | * 108 | * @param packageName 包名 109 | * @return 文件系统路径 110 | */ 111 | public static String package2Path(String packageName) { 112 | if (StringUtil.isEmpty(packageName)) { 113 | return ""; 114 | } 115 | StringBuilder sb = new StringBuilder(); 116 | String[] packages = packageName.split("\\."); 117 | for (String str : packages) { 118 | sb.append(str).append(File.separator); 119 | } 120 | return sb.toString(); 121 | } 122 | 123 | /** 124 | * 短横线转驼峰 125 | * 126 | * @param str 待转换字符串 127 | * @return 驼峰命名字符串 128 | */ 129 | public static String line2Camel(String str) { 130 | return str.replace("package-name", "packageName") 131 | .replace("lombok-enable", "lombokEnable") 132 | .replace("mapper-under-source", "mapperUnderSource") 133 | .replace("swagger-enable", "swaggerEnable") 134 | .replace("mybatis-plus-enable", "mybatisPlusEnable") 135 | .replace("jpa-enable", "jpaEnable") 136 | .replace("id-strategy", "idStrategy") 137 | .replace("file-override", "fileOverride"); 138 | } 139 | 140 | } 141 | -------------------------------------------------------------------------------- /src/main/java/com/greedystar/generator/utils/TaskQueue.java: -------------------------------------------------------------------------------- 1 | package com.greedystar.generator.utils; 2 | 3 | import com.greedystar.generator.entity.Mode; 4 | import com.greedystar.generator.invoker.base.AbstractInvoker; 5 | import com.greedystar.generator.task.*; 6 | import com.greedystar.generator.task.base.AbstractTask; 7 | 8 | import java.util.LinkedList; 9 | 10 | /** 11 | * @author GreedyStar 12 | * @since 2018-11-27 13 | */ 14 | public class TaskQueue { 15 | 16 | /** 17 | * 任务队列 18 | */ 19 | private LinkedList taskQueue = new LinkedList<>(); 20 | 21 | /** 22 | * 初始化共性任务,包括Controller、ServiceImpl、Service、Dao、Mapper任务 23 | * 24 | * @param invoker 执行器 25 | */ 26 | private void initCommonTasks(AbstractInvoker invoker) { 27 | if (!StringUtil.isEmpty(ConfigUtil.getConfiguration().getPath().getController())) { 28 | taskQueue.add(new ControllerTask(invoker)); 29 | } 30 | if (!StringUtil.isEmpty(ConfigUtil.getConfiguration().getPath().getService())) { 31 | taskQueue.add(new ServiceTask(invoker)); 32 | } 33 | if (!StringUtil.isEmpty(ConfigUtil.getConfiguration().getPath().getInterf())) { 34 | taskQueue.add(new InterfaceTask(invoker)); 35 | } 36 | if (!StringUtil.isEmpty(ConfigUtil.getConfiguration().getPath().getDao())) { 37 | taskQueue.add(new DaoTask(invoker)); 38 | } 39 | if (!StringUtil.isEmpty(ConfigUtil.getConfiguration().getPath().getMapper())) { 40 | taskQueue.add(new MapperTask(invoker)); 41 | } 42 | } 43 | 44 | /** 45 | * 初始化单表生成任务,包括Entity、Mapper任务 46 | * 47 | * @param invoker 执行器 48 | */ 49 | public void initSingleTasks(AbstractInvoker invoker) { 50 | initCommonTasks(invoker); 51 | if (!StringUtil.isEmpty(ConfigUtil.getConfiguration().getPath().getEntity())) { 52 | taskQueue.add(new EntityTask(Mode.ENTITY_MAIN, invoker)); 53 | } 54 | } 55 | 56 | /** 57 | * 初始化单表生成任务,包括Entity、Mapper任务 58 | * 59 | * @param invoker 执行器 60 | */ 61 | public void initMany2OneTasks(AbstractInvoker invoker) { 62 | initCommonTasks(invoker); 63 | if (!StringUtil.isEmpty(ConfigUtil.getConfiguration().getPath().getEntity())) { 64 | taskQueue.add(new EntityTask(Mode.ENTITY_MAIN, invoker)); 65 | taskQueue.add(new EntityTask(Mode.ENTITY_PARENT, invoker)); 66 | } 67 | } 68 | 69 | /** 70 | * 初始化单表生成任务,包括Entity、Mapper任务 71 | * 72 | * @param invoker 执行器 73 | */ 74 | public void initOne2ManyTasks(AbstractInvoker invoker) { 75 | initCommonTasks(invoker); 76 | if (!StringUtil.isEmpty(ConfigUtil.getConfiguration().getPath().getEntity())) { 77 | taskQueue.add(new EntityTask(Mode.ENTITY_MAIN, invoker)); 78 | taskQueue.add(new EntityTask(Mode.ENTITY_PARENT, invoker)); 79 | } 80 | } 81 | 82 | /** 83 | * 初始化单表生成任务,包括Entity、Mapper任务 84 | * 85 | * @param invoker 执行器 86 | */ 87 | public void initMany2ManyTasks(AbstractInvoker invoker) { 88 | initCommonTasks(invoker); 89 | if (!StringUtil.isEmpty(ConfigUtil.getConfiguration().getPath().getEntity())) { 90 | taskQueue.add(new EntityTask(Mode.ENTITY_MAIN, invoker)); 91 | taskQueue.add(new EntityTask(Mode.ENTITY_PARENT, invoker)); 92 | } 93 | } 94 | 95 | /** 96 | * 任务队列是否为空 97 | * 98 | * @return 是否为空 99 | */ 100 | public boolean isEmpty() { 101 | return taskQueue.isEmpty(); 102 | } 103 | 104 | /** 105 | * 取出一个任务 106 | * 107 | * @return 任务 108 | */ 109 | public AbstractTask poll() { 110 | return taskQueue.poll(); 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /src/main/resources/ftls/Controller.ftl: -------------------------------------------------------------------------------- 1 | package ${Configuration.packageName}.${Configuration.path.controller}; 2 | 3 | import ${Configuration.packageName}.${Configuration.path.entity}.${ClassName}; 4 | ${ServiceImport} 5 | <#if Configuration.swaggerEnable> 6 | import io.swagger.annotations.Api; 7 | import io.swagger.annotations.ApiOperation; 8 | 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | import java.io.Serializable; 13 | import java.util.HashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | /** 18 | * @author ${Configuration.author} 19 | * @date ${.now?date} 20 | */ 21 | <#if Configuration.swaggerEnable> 22 | @Api(value = "/${EntityName}", tags = "${EntityName}管理接口") 23 | 24 | @RestController 25 | @RequestMapping(value = "/${EntityName}") 26 | public class ${ControllerClassName} { 27 | @Autowired 28 | private ${ServiceClassName} ${ServiceEntityName}; 29 | 30 | <#if Configuration.swaggerEnable> 31 | @ApiOperation(value = "查询${EntityName}列表", httpMethod = "GET") 32 | 33 | @GetMapping(value = "") 34 | public Object list() { 35 | <#if Configuration.mybatisPlusEnable><#-- mybatis-plus模式 --> 36 | List<${ClassName}> ${EntityName}s = ${ServiceEntityName}.list(); 37 | <#else><#-- mybatis或jpa模式 --> 38 | List<${ClassName}> ${EntityName}s = ${ServiceEntityName}.findAll(); 39 | 40 | Map result = new HashMap<>(); 41 | result.put("data", ${EntityName}s); 42 | result.put("status", 200); 43 | result.put("message", "OK"); 44 | return result; 45 | } 46 | 47 | <#if Configuration.swaggerEnable> 48 | @ApiOperation(value = "查看${EntityName}详情", httpMethod = "GET") 49 | 50 | @GetMapping(value = "/{id}") 51 | public Object get(@PathVariable("id") ${pkType} id) { 52 | <#if Configuration.mybatisPlusEnable><#-- mybatis-plus模式 --> 53 | ${ClassName} ${EntityName} = ${ServiceEntityName}.getById(id); 54 | <#else><#-- mybatis或jpa模式 --> 55 | ${ClassName} ${EntityName} = ${ServiceEntityName}.get(id); 56 | 57 | Map result = new HashMap<>(); 58 | result.put("data", ${EntityName}); 59 | result.put("status", 200); 60 | result.put("message", "OK"); 61 | return result; 62 | } 63 | 64 | <#if Configuration.swaggerEnable> 65 | @ApiOperation(value = "创建${EntityName}", httpMethod = "POST") 66 | 67 | @PostMapping(value = "") 68 | public Object post(@RequestBody ${ClassName} ${EntityName}) { 69 | Map result = new HashMap<>(); 70 | try { 71 | <#if Configuration.mybatisPlusEnable><#-- mybatis-plus模式 --> 72 | ${ServiceEntityName}.save(${EntityName}); 73 | <#else><#-- mybatis或jpa模式 --> 74 | ${ServiceEntityName}.insert(${EntityName}); 75 | 76 | result.put("status", 200); 77 | result.put("message", "OK"); 78 | } catch (Exception e) { 79 | e.printStackTrace(); 80 | result.put("status", 500); 81 | result.put("message", "ERROR"); 82 | } 83 | return result; 84 | } 85 | 86 | <#if Configuration.swaggerEnable> 87 | @ApiOperation(value = "修改${EntityName}信息", httpMethod = "PUT") 88 | 89 | @PutMapping(value = "") 90 | public Object put(@RequestBody ${ClassName} ${EntityName}) { 91 | Map result = new HashMap<>(); 92 | try { 93 | <#if Configuration.mybatisPlusEnable><#-- mybatis-plus模式 --> 94 | ${ServiceEntityName}.updateById(${EntityName}); 95 | <#else><#-- mybatis或jpa模式 --> 96 | ${ServiceEntityName}.update(${EntityName}); 97 | 98 | result.put("status", 200); 99 | result.put("message", "OK"); 100 | } catch (Exception e) { 101 | e.printStackTrace(); 102 | result.put("status", 500); 103 | result.put("message", "ERROR"); 104 | } 105 | return result; 106 | } 107 | 108 | 109 | <#if Configuration.swaggerEnable> 110 | @ApiOperation(value = "删除${EntityName}", httpMethod = "DELETE") 111 | 112 | @DeleteMapping(value = "") 113 | public Object delete(@RequestBody ${ClassName} ${EntityName}) { 114 | Map result = new HashMap<>(); 115 | try { 116 | <#if Configuration.mybatisPlusEnable><#-- mybatis-plus模式 --> 117 | ${ServiceEntityName}.removeById(${EntityName}.getId()); 118 | <#else><#-- mybatis或jpa模式 --> 119 | ${ServiceEntityName}.delete(${EntityName}); 120 | 121 | result.put("status", 200); 122 | result.put("message", "OK"); 123 | } catch (Exception e) { 124 | e.printStackTrace(); 125 | result.put("status", 500); 126 | result.put("message", "ERROR"); 127 | } 128 | return result; 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /src/main/resources/ftls/Dao.ftl: -------------------------------------------------------------------------------- 1 | package ${Configuration.packageName}.${Configuration.path.dao}; 2 | 3 | import ${Configuration.packageName}.${Configuration.path.entity}.${ClassName}; 4 | <#if Configuration.mybatisPlusEnable> 5 | import org.apache.ibatis.annotations.Mapper; 6 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 7 | <#elseif Configuration.jpaEnable> 8 | import org.springframework.data.jpa.repository.JpaRepository; 9 | import org.springframework.stereotype.Repository; 10 | <#else> 11 | import org.apache.ibatis.annotations.Mapper; 12 | 13 | 14 | import java.io.Serializable; 15 | import java.util.List; 16 | 17 | /** 18 | * @author ${Configuration.author} 19 | * @date ${.now?date} 20 | */ 21 | <#if Configuration.mybatisPlusEnable><#-- mybatis-plus模式 --> 22 | @Mapper 23 | public interface ${DaoClassName} extends BaseMapper<${ClassName}> { 24 | 25 | } 26 | <#elseif Configuration.jpaEnable><#-- jpa模式 --> 27 | @Repository 28 | public interface ${DaoClassName} extends JpaRepository<${ClassName}, Serializable> { 29 | 30 | } 31 | <#else><#-- mybatis模式 --> 32 | @Mapper 33 | public interface ${DaoClassName} { 34 | 35 | ${ClassName} get(Serializable id); 36 | 37 | List<${ClassName}> findAll(); 38 | 39 | int insert(${ClassName} ${EntityName}); 40 | 41 | int insertBatch(List<${ClassName}> ${EntityName}s); 42 | 43 | int update(${ClassName} ${EntityName}); 44 | 45 | int delete(${ClassName} ${EntityName}); 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/resources/ftls/Entity.ftl: -------------------------------------------------------------------------------- 1 | package ${Configuration.packageName}.${Configuration.path.entity}; 2 | 3 | <#if Configuration.lombokEnable> 4 | import lombok.Data; 5 | 6 | <#if Configuration.mybatisPlusEnable> 7 | import com.baomidou.mybatisplus.annotation.*; 8 | <#elseif Configuration.jpaEnable> 9 | import javax.persistence.*; 10 | import org.hibernate.annotations.GenericGenerator; 11 | 12 | import java.io.Serializable; 13 | import java.math.BigDecimal; 14 | import java.util.Date; 15 | import java.util.List; 16 | 17 | /** 18 | * ${Remarks} 19 | * 20 | * @author ${Configuration.author} 21 | * @date ${.now?date} 22 | */ 23 | <#if Configuration.lombokEnable> 24 | @Data 25 | 26 | <#if Configuration.mybatisPlusEnable> 27 | @TableName(value = "${TableName}") 28 | <#elseif Configuration.jpaEnable> 29 | @Entity 30 | @Table(name = "${TableName}") 31 | 32 | public class ${ClassName} implements Serializable { 33 | ${Properties} 34 | 35 | ${Methods} 36 | } -------------------------------------------------------------------------------- /src/main/resources/ftls/Interface.ftl: -------------------------------------------------------------------------------- 1 | package ${Configuration.packageName}.${Configuration.path.interf}; 2 | 3 | import ${Configuration.packageName}.${Configuration.path.entity}.${ClassName}; 4 | <#if Configuration.mybatisPlusEnable> 5 | import com.baomidou.mybatisplus.extension.service.IService; 6 | <#else> 7 | import java.io.Serializable; 8 | 9 | import java.io.Serializable; 10 | import java.util.List; 11 | 12 | /** 13 | * @author ${Configuration.author} 14 | * @date ${.now?date} 15 | */ 16 | <#if Configuration.mybatisPlusEnable><#-- mybatis-plus模式 --> 17 | public interface ${InterfaceClassName} extends IService<${ClassName}> { 18 | 19 | } 20 | <#else><#-- mybatis或jpa模式 --> 21 | public interface ${InterfaceClassName} { 22 | 23 | <#if Configuration.jpaEnable><#-- jpa模式 --> 24 | ${ClassName} get(Serializable id); 25 | 26 | List<${ClassName}> findAll(); 27 | 28 | ${ClassName} insert(${ClassName} ${EntityName}); 29 | 30 | List<${ClassName}> insertBatch(List<${ClassName}> ${EntityName}s); 31 | 32 | ${ClassName} update(${ClassName} ${EntityName}); 33 | 34 | void delete(${ClassName} ${EntityName}); 35 | 36 | <#else><#-- mybatis模式 --> 37 | ${ClassName} get(Serializable id); 38 | 39 | List<${ClassName}> findAll(); 40 | 41 | int insert(${ClassName} ${EntityName}); 42 | 43 | int insertBatch(List<${ClassName}> ${EntityName}s); 44 | 45 | int update(${ClassName} ${EntityName}); 46 | 47 | int delete(${ClassName} ${EntityName}); 48 | 49 | 50 | } 51 | 52 | -------------------------------------------------------------------------------- /src/main/resources/ftls/Mapper.ftl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ${ResultMap} 7 | ${Association} 8 | ${Collection} 9 | 10 | 11 | 12 | ${ColumnMap} 13 | 14 | 15 | 16 | ${Joins} 17 | 18 | 19 | 27 | 28 | 35 | 36 | 37 | INSERT INTO `${TableName}`( 38 | ${InsertProperties} 39 | ) 40 | VALUES ( 41 | ${InsertValues} 42 | ) 43 | 44 | 45 | 46 | INSERT INTO ${TableName}( 47 | ${InsertProperties} 48 | ) 49 | VALUES 50 | 51 | ( 52 | ${InsertBatchValues} 53 | ) 54 | 55 | 56 | 57 | 58 | UPDATE `${TableName}` SET 59 | ${UpdateProperties} 60 | WHERE `${PrimaryColumn.columnName}` = ${r"#{"}${PrimaryColumn.propertyName}${r"}"} 61 | 62 | 63 | 64 | DELETE FROM `${TableName}` 65 | WHERE `${PrimaryColumn.columnName}` = ${r"#{"}${PrimaryColumn.propertyName}${r"}"} 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/main/resources/ftls/Service.ftl: -------------------------------------------------------------------------------- 1 | package ${Configuration.packageName}.${Configuration.path.service}; 2 | 3 | import ${Configuration.packageName}.${Configuration.path.dao}.${DaoClassName}; 4 | import ${Configuration.packageName}.${Configuration.path.entity}.${ClassName}; 5 | ${InterfaceImport} 6 | <#if Configuration.mybatisPlusEnable> 7 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 8 | <#else> 9 | import java.io.Serializable; 10 | 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Service; 13 | 14 | import java.io.Serializable; 15 | import java.util.List; 16 | 17 | /** 18 | * @author ${Configuration.author} 19 | * @date ${.now?date} 20 | */ 21 | @Service 22 | <#if Configuration.mybatisPlusEnable><#-- mybatis-plus模式 --> 23 | public class ${ServiceClassName} extends ServiceImpl<${DaoClassName}, ${ClassName}> ${Implements} { 24 | 25 | } 26 | <#else><#-- mybatis或jpa模式 --> 27 | public class ${ServiceClassName} ${Implements} { 28 | @Autowired 29 | private ${DaoClassName} ${DaoEntityName}; 30 | <#if Configuration.jpaEnable><#-- jpa模式 --> 31 | ${Override} 32 | public ${ClassName} get(Serializable id) { 33 | return ${DaoEntityName}.findById(id).orElse(null); 34 | } 35 | ${Override} 36 | public List<${ClassName}> findAll() { 37 | return ${DaoEntityName}.findAll(); 38 | } 39 | ${Override} 40 | public ${ClassName} insert(${ClassName} ${EntityName}) { 41 | return ${DaoEntityName}.save(${EntityName}); 42 | } 43 | ${Override} 44 | public List<${ClassName}> insertBatch(List<${ClassName}> ${EntityName}s){ 45 | return ${DaoEntityName}.saveAll(${EntityName}s); 46 | } 47 | ${Override} 48 | public ${ClassName} update(${ClassName} ${EntityName}) { 49 | return ${DaoEntityName}.save(${EntityName}); 50 | } 51 | ${Override} 52 | public void delete(${ClassName} ${EntityName}) { 53 | ${DaoEntityName}.delete(${EntityName}); 54 | } 55 | <#else><#-- mybatis模式 --> 56 | ${Override} 57 | public ${ClassName} get(Serializable id) { 58 | return ${DaoEntityName}.get(id); 59 | } 60 | ${Override} 61 | public List<${ClassName}> findAll() { 62 | return ${DaoEntityName}.findAll(); 63 | } 64 | ${Override} 65 | public int insert(${ClassName} ${EntityName}) { 66 | return ${DaoEntityName}.insert(${EntityName}); 67 | } 68 | ${Override} 69 | public int insertBatch(List<${ClassName}> ${EntityName}s) { 70 | return ${DaoEntityName}.insertBatch(${EntityName}s); 71 | } 72 | ${Override} 73 | public int update(${ClassName} ${EntityName}) { 74 | return ${DaoEntityName}.update(${EntityName}); 75 | } 76 | ${Override} 77 | public int delete(${ClassName} ${EntityName}) { 78 | return ${DaoEntityName}.delete(${EntityName}); 79 | } 80 | 81 | } 82 | --------------------------------------------------------------------------------