diff --git a/mybatis-flex-codegen/pom.xml b/mybatis-flex-codegen/pom.xml index cfbc47a1..accfaa61 100644 --- a/mybatis-flex-codegen/pom.xml +++ b/mybatis-flex-codegen/pom.xml @@ -16,4 +16,78 @@ 8 + + + + org.mybatis + mybatis + + + + + com.mybatis-flex + mybatis-flex-core + 1.0.3 + + + + + + com.jfinal + enjoy + 5.0.3 + + + + + mysql + mysql-connector-java + 8.0.32 + compile + true + + + + + com.zaxxer + HikariCP + 4.0.3 + compile + true + + + + + junit + junit + test + + + + + + + + src/main/java + + + **/*.tpl + + false + + + + src/main/resources + + **/* + + + + *.properties + + + + + + \ No newline at end of file diff --git a/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/Generator.java b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/Generator.java new file mode 100644 index 00000000..cc848a78 --- /dev/null +++ b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/Generator.java @@ -0,0 +1,189 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.codegen; + +import com.mybatisflex.codegen.config.GlobalConfig; +import com.mybatisflex.codegen.dialect.IDialect; +import com.mybatisflex.codegen.entity.Column; +import com.mybatisflex.codegen.entity.Table; +import com.mybatisflex.codegen.template.ITemplate; + +import javax.sql.DataSource; +import java.io.File; +import java.sql.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Generator { + + protected DataSource dataSource; + protected GlobalConfig globalConfig; + protected IDialect dialect = IDialect.MYSQL; + + protected Connection conn = null; + protected DatabaseMetaData dbMeta = null; + + + public Generator(DataSource dataSource, GlobalConfig globalConfig) { + this.dataSource = dataSource; + this.globalConfig = globalConfig; + } + + + public Generator(DataSource dataSource, GlobalConfig globalConfig, IDialect dialect) { + this.dataSource = dataSource; + this.globalConfig = globalConfig; + this.dialect = dialect; + } + + + public void generate() { + try { + conn = dataSource.getConnection(); + dbMeta = conn.getMetaData(); + + List tables = buildTables(); + + ITemplate templateEngine = globalConfig.getTemplateEngine(); + for (Table table : tables) { + + String entityPackagePath = globalConfig.getEntityPackage().replace(".", "/"); + File entityJavaFile = new File(globalConfig.getSourceDir(), entityPackagePath + "/" + table.buildEntityClassName() + ".java"); + if (!entityJavaFile.getParentFile().exists()) { + if (!entityJavaFile.getParentFile().mkdirs()) { + throw new IllegalStateException("Can not mkdirs by dir: " + entityJavaFile.getParentFile()); + } + } + + templateEngine.generateEntity(globalConfig, table, entityJavaFile); + + + if (globalConfig.isMapperGenerateEnable()) { + String mapperPackagePath = globalConfig.getMapperPackage().replace(".", "/"); + File mapperJavaFile = new File(globalConfig.getSourceDir(), mapperPackagePath + "/" + table.buildEntityClassName() + "Mapper.java"); + if (!mapperJavaFile.getParentFile().exists()) { + if (!mapperJavaFile.getParentFile().mkdirs()) { + throw new IllegalStateException("Can not mkdirs by dir: " + mapperJavaFile.getParentFile()); + } + } + templateEngine.generateMapper(globalConfig, table, mapperJavaFile); + } + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + + protected void buildPrimaryKey(Table table) throws SQLException { + try (ResultSet rs = dbMeta.getPrimaryKeys(conn.getCatalog(), null, table.getName())) { + while (rs.next()) { + String primaryKey = rs.getString("COLUMN_NAME"); + table.addPrimaryKey(primaryKey); + } + } + } + + + private void buildTableColumns(Table table) throws SQLException { + Map columnRemarks = buildColumnRemarks(table); + + String sql = dialect.forBuildColumns(table.getName()); + try (Statement stm = conn.createStatement(); ResultSet rs = stm.executeQuery(sql)) { + + ResultSetMetaData columnMetaData = rs.getMetaData(); + int columnCount = columnMetaData.getColumnCount(); + + for (int i = 1; i <= columnCount; i++) { + Column column = new Column(); + column.setName(columnMetaData.getColumnName(i)); + column.setPropertyType(columnMetaData.getColumnClassName(i)); + column.setAutoIncrement(columnMetaData.isAutoIncrement(i)); + + //主键 + if (table.getPrimaryKeys() != null && table.getPrimaryKeys().contains(column.getName())) { + column.setPrimaryKey(true); + } + + //注释 + column.setRemarks(columnRemarks.get(column.getName())); + + column.setColumnConfig(globalConfig.getColumnConfig(table.getName(), column.getName())); + table.addColumn(column); + } + } + } + + + private Map buildColumnRemarks(Table table) throws SQLException { + Map columnRemarks = new HashMap<>(); + ResultSet colRs = null; + try { + colRs = dbMeta.getColumns(conn.getCatalog(), null, table.getName(), null); + while (colRs.next()) { + columnRemarks.put(colRs.getString("COLUMN_NAME"), colRs.getString("REMARKS")); + } + } catch (Exception e) { + System.err.println("无法获取字段的备注内容:" + e.getMessage()); + } finally { + if (colRs != null) { + colRs.close(); + } + } + return columnRemarks; + } + + + private List
buildTables() throws SQLException { + List
tables = new ArrayList<>(); + try (ResultSet rs = getTablesResultSet()) { + while (rs.next()) { + String tableName = rs.getString("TABLE_NAME"); + if (!globalConfig.isSupportGenerate(tableName)) { + continue; + } + + Table table = new Table(); + table.setGlobalConfig(globalConfig); + table.setTableConfig(globalConfig.getTableConfig(tableName)); + + table.setName(tableName); + + String remarks = rs.getString("REMARKS"); + table.setRemarks(remarks); + + + buildPrimaryKey(table); + buildTableColumns(table); + + tables.add(table); + } + } + return tables; + } + + + protected ResultSet getTablesResultSet() throws SQLException { + if (globalConfig.isGenerateForView()) { + return dialect.getTablesResultSet(dbMeta, conn, new String[]{"TABLE", "VIEW"}); + } else { + return dialect.getTablesResultSet(dbMeta, conn, new String[]{"TABLE"}); + } + } +} diff --git a/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/config/ColumnConfig.java b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/config/ColumnConfig.java new file mode 100644 index 00000000..b90a00eb --- /dev/null +++ b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/config/ColumnConfig.java @@ -0,0 +1,149 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.codegen.config; + +import com.mybatisflex.annotation.KeyType; +import org.apache.ibatis.type.JdbcType; +import org.apache.ibatis.type.TypeHandler; + +import java.io.Serializable; + +public class ColumnConfig implements Serializable { + + private String columnName; + + private String onInsertValue; + private String onUpdateValue; + + private Boolean isLarge; + private Boolean isLogicDelete; + private Boolean version; + + private JdbcType jdbcType; + private Class typeHandler; + + private String mask; + + private boolean isPrimaryKey = false; + private KeyType keyType; + private String keyValue; + private Boolean keyBefore; + + + public String getColumnName() { + return columnName; + } + + public void setColumnName(String columnName) { + this.columnName = columnName; + } + + public String getOnInsertValue() { + return onInsertValue; + } + + public void setOnInsertValue(String onInsertValue) { + this.onInsertValue = onInsertValue; + } + + public String getOnUpdateValue() { + return onUpdateValue; + } + + public void setOnUpdateValue(String onUpdateValue) { + this.onUpdateValue = onUpdateValue; + } + + public Boolean getLarge() { + return isLarge; + } + + public void setLarge(Boolean large) { + isLarge = large; + } + + public Boolean getLogicDelete() { + return isLogicDelete; + } + + public void setLogicDelete(Boolean logicDelete) { + isLogicDelete = logicDelete; + } + + public Boolean getVersion() { + return version; + } + + public void setVersion(Boolean version) { + this.version = version; + } + + public JdbcType getJdbcType() { + return jdbcType; + } + + public void setJdbcType(JdbcType jdbcType) { + this.jdbcType = jdbcType; + } + + public Class getTypeHandler() { + return typeHandler; + } + + public void setTypeHandler(Class typeHandler) { + this.typeHandler = typeHandler; + } + + public String getMask() { + return mask; + } + + public void setMask(String mask) { + this.mask = mask; + } + + public boolean isPrimaryKey() { + return isPrimaryKey; + } + + public void setPrimaryKey(boolean primaryKey) { + isPrimaryKey = primaryKey; + } + + public KeyType getKeyType() { + return keyType; + } + + public void setKeyType(KeyType keyType) { + this.keyType = keyType; + } + + public String getKeyValue() { + return keyValue; + } + + public void setKeyValue(String keyValue) { + this.keyValue = keyValue; + } + + public Boolean getKeyBefore() { + return keyBefore; + } + + public void setKeyBefore(Boolean keyBefore) { + this.keyBefore = keyBefore; + } +} diff --git a/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/config/GlobalConfig.java b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/config/GlobalConfig.java new file mode 100644 index 00000000..37074b31 --- /dev/null +++ b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/config/GlobalConfig.java @@ -0,0 +1,288 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.codegen.config; + +import com.mybatisflex.codegen.template.EnjoyTemplate; +import com.mybatisflex.codegen.template.ITemplate; +import com.mybatisflex.core.util.StringUtil; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class GlobalConfig { + + private String sourceDir; + + private String entityPackage; + + private Boolean entityWithLombok = false; + + //是否生成 mapper 文件 + private boolean mapperGenerateEnable = false; + + private String mapperPackage; + + private String tablePrefix; + + private String logicDeleteColumn; + + private String versionColumn; + + //是否支持生成视图映射 + private boolean generateForView = false; + + private Map tableConfigMap; + + private Map defaultColumnConfigMap; + + private Set generateTables; + + private Set unGenerateTables; + + protected ITemplate templateEngine; + + + public String getSourceDir() { + if (sourceDir == null || sourceDir.trim().length() == 0) { + return System.getProperty("user.dir") + "/src/main/java"; + } + return sourceDir; + } + + public void setSourceDir(String sourceDir) { + this.sourceDir = sourceDir; + } + + public String getEntityPackage() { + if (StringUtil.isBlank(entityPackage)) { + throw new IllegalStateException("entityPackage can not be null or blank in GlobalConfig."); + } + return entityPackage; + } + + public void setEntityPackage(String entityPackage) { + this.entityPackage = entityPackage.trim(); + } + + public Boolean getEntityWithLombok() { + return entityWithLombok; + } + + public void setEntityWithLombok(Boolean entityWithLombok) { + this.entityWithLombok = entityWithLombok; + } + + public boolean isMapperGenerateEnable() { + return mapperGenerateEnable; + } + + public void setMapperGenerateEnable(boolean mapperGenerateEnable) { + this.mapperGenerateEnable = mapperGenerateEnable; + } + + public String getMapperPackage() { + if (StringUtil.isBlank(mapperPackage)) { + throw new IllegalStateException("mapperPackage can not be null or blank in GlobalConfig."); + } + return mapperPackage; + } + + public void setMapperPackage(String mapperPackage) { + this.mapperPackage = mapperPackage; + } + + public String getTablePrefix() { + return tablePrefix; + } + + public void setTablePrefix(String tablePrefix) { + this.tablePrefix = tablePrefix; + } + + public String getLogicDeleteColumn() { + return logicDeleteColumn; + } + + public void setLogicDeleteColumn(String logicDeleteColumn) { + this.logicDeleteColumn = logicDeleteColumn; + } + + public String getVersionColumn() { + return versionColumn; + } + + public void setVersionColumn(String versionColumn) { + this.versionColumn = versionColumn; + } + + public Map getTableConfigMap() { + return tableConfigMap; + } + + public void setTableConfigMap(Map tableConfigMap) { + this.tableConfigMap = tableConfigMap; + } + + public void addTableConfig(TableConfig tableConfig) { + if (tableConfigMap == null) { + tableConfigMap = new HashMap<>(); + } + tableConfigMap.put(tableConfig.getTableName(), tableConfig); + } + + public TableConfig getTableConfig(String tableName) { + return tableConfigMap == null ? null : tableConfigMap.get(tableName); + } + + public Map getDefaultColumnConfigMap() { + return defaultColumnConfigMap; + } + + public void setDefaultColumnConfigMap(Map defaultColumnConfigMap) { + this.defaultColumnConfigMap = defaultColumnConfigMap; + } + + + public void addColumnConfig(ColumnConfig columnConfig) { + if (defaultColumnConfigMap == null) { + defaultColumnConfigMap = new HashMap<>(); + } + defaultColumnConfigMap.put(columnConfig.getColumnName(), columnConfig); + } + + public void addColumnConfig(String tableName, ColumnConfig columnConfig) { + TableConfig tableConfig = getTableConfig(tableName); + if (tableConfig == null) { + tableConfig = new TableConfig(); + tableConfig.setTableName(tableName); + addTableConfig(tableConfig); + } + + tableConfig.addColumnConfig(columnConfig); + } + + + public ColumnConfig getColumnConfig(String tableName, String columnName) { + ColumnConfig columnConfig = null; + + TableConfig tableConfig = getTableConfig(tableName); + if (tableConfig != null) { + columnConfig = tableConfig.getColumnConfig(columnName); + } + + if (columnConfig == null && defaultColumnConfigMap != null) { + columnConfig = defaultColumnConfigMap.get(columnName); + } + + if (columnConfig == null) { + columnConfig = new ColumnConfig(); + } + + //全局配置的逻辑删除 + if (columnName.equals(logicDeleteColumn) && columnConfig.getLogicDelete() == null) { + columnConfig.setLogicDelete(true); + } + + //全部配置的乐观锁版本 + if (columnName.equals(versionColumn) && columnConfig.getVersion() == null) { + columnConfig.setVersion(true); + } + + + return columnConfig; + } + + public boolean isGenerateForView() { + return generateForView; + } + + public void setGenerateForView(boolean generateForView) { + this.generateForView = generateForView; + } + + public Set getGenerateTables() { + return generateTables; + } + + public void setGenerateTables(Set generateTables) { + this.generateTables = generateTables; + } + + public void addGenerateTable(String... tables) { + if (generateTables == null) { + generateTables = new HashSet<>(); + } + + for (String table : tables) { + if (table != null && table.trim().length() > 0) { + generateTables.add(table.trim()); + } + } + } + + public Set getUnGenerateTables() { + return unGenerateTables; + } + + public void setUnGenerateTables(Set unGenerateTables) { + this.unGenerateTables = unGenerateTables; + } + + + public void addUnGenerateTable(String... tables) { + if (unGenerateTables == null) { + unGenerateTables = new HashSet<>(); + } + + for (String table : tables) { + if (table != null && table.trim().length() > 0) { + unGenerateTables.add(table.trim()); + } + } + } + + public boolean isSupportGenerate(String table) { + if (unGenerateTables != null && unGenerateTables.contains(table)) { + return false; + } + + //不配置指定比表名的情况下,支持所有表 + if (generateTables == null || generateTables.isEmpty()) { + return true; + } + + for (String generateTable : generateTables) { + if (generateTable.equals(table)) { + return true; + } + } + + return false; + } + + public ITemplate getTemplateEngine() { + if (templateEngine == null) { + templateEngine = new EnjoyTemplate(); + } + return templateEngine; + } + + public void setTemplateEngine(ITemplate templateEngine) { + this.templateEngine = templateEngine; + } +} diff --git a/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/config/TableConfig.java b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/config/TableConfig.java new file mode 100644 index 00000000..b5ac59e9 --- /dev/null +++ b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/config/TableConfig.java @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.codegen.config; + +import java.util.HashMap; +import java.util.Map; + +public class TableConfig { + + private String tableName; + + /** + * 数据库的 schema + */ + private String schema; + + /** + * 默认为 驼峰属性 转换为 下划线字段 + */ + private Boolean camelToUnderline; + + + private Map columnConfigMap; + + + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } + + public String getSchema() { + return schema; + } + + public void setSchema(String schema) { + this.schema = schema; + } + + public Boolean getCamelToUnderline() { + return camelToUnderline; + } + + public void setCamelToUnderline(Boolean camelToUnderline) { + this.camelToUnderline = camelToUnderline; + } + + public Map getColumnConfigMap() { + return columnConfigMap; + } + + public void setColumnConfigMap(Map columnConfigMap) { + this.columnConfigMap = columnConfigMap; + } + + public void addColumnConfig(ColumnConfig columnConfig){ + if (columnConfigMap == null){ + columnConfigMap = new HashMap<>(); + } + columnConfigMap.put(columnConfig.getColumnName(), columnConfig); + } + + public ColumnConfig getColumnConfig(String columnName){ + return columnConfigMap == null ? null: columnConfigMap.get(columnName); + } +} diff --git a/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/dialect/IDialect.java b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/dialect/IDialect.java new file mode 100644 index 00000000..b43d740b --- /dev/null +++ b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/dialect/IDialect.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.codegen.dialect; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; + +public interface IDialect { + + IDialect MYSQL = new IDialect() { + @Override + public String forBuildColumns(String tableName) { + return "SELECT * FROM `" + tableName + "` WHERE 1 = 2"; + } + + @Override + public ResultSet getTablesResultSet(DatabaseMetaData dbMeta, Connection conn, String[] types) throws SQLException { + return dbMeta.getTables(conn.getCatalog(), null, null, types); + } + }; + + + + IDialect ORACLE = new IDialect() { + @Override + public String forBuildColumns(String tableName) { + return "SELECT * FROM \"" +tableName+ "\" WHERE rownum < 1"; + } + + @Override + public ResultSet getTablesResultSet(DatabaseMetaData dbMeta, Connection conn, String[] types) throws SQLException { + return dbMeta.getTables(conn.getCatalog(), dbMeta.getUserName(), null, types); + } + }; + + + + + String forBuildColumns(String tableName); + + ResultSet getTablesResultSet(DatabaseMetaData dbMeta, Connection conn, String[] types) throws SQLException; +} diff --git a/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/entity/Column.java b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/entity/Column.java new file mode 100644 index 00000000..096a1450 --- /dev/null +++ b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/entity/Column.java @@ -0,0 +1,260 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.codegen.entity; + +import com.mybatisflex.annotation.ColumnMask; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.codegen.config.ColumnConfig; +import com.mybatisflex.core.util.StringUtil; + +import java.util.ArrayList; +import java.util.List; + +public class Column { + + private String name; + private String property; + private String propertyType; + + private String remarks; + + private boolean isPrimaryKey = false; + private Boolean isAutoIncrement; + + private ColumnConfig columnConfig; + + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + this.property = buildPropertyName(); + } + + public String getProperty() { + return property; + } + + public void setProperty(String property) { + this.property = property; + } + + public String getPropertyType() { + return propertyType; + } + + public String getPropertySimpleType() { + return propertyType.substring(propertyType.lastIndexOf(".") + 1); + } + + public void setPropertyType(String propertyType) { + this.propertyType = propertyType; + } + + public String getRemarks() { + return remarks; + } + + public void setRemarks(String remarks) { + this.remarks = remarks; + } + + public boolean isPrimaryKey() { + return isPrimaryKey; + } + + public void setPrimaryKey(boolean primaryKey) { + isPrimaryKey = primaryKey; + } + + public Boolean getAutoIncrement() { + return isAutoIncrement; + } + + public void setAutoIncrement(Boolean autoIncrement) { + isAutoIncrement = autoIncrement; + } + + public ColumnConfig getColumnConfig() { + return columnConfig; + } + + public void setColumnConfig(ColumnConfig columnConfig) { + this.columnConfig = columnConfig; + } + + public String buildGetter() { + return "get" + StringUtil.firstCharToUpperCase(property); + } + + public String buildSetter() { + return "set" + StringUtil.firstCharToUpperCase(property); + } + + public String buildPropertyName() { + String entityJavaFileName = name; + return StringUtil.firstCharToLowerCase(StringUtil.underlineToCamel(entityJavaFileName)); + } + + public String buildAnnotations() { + StringBuilder annotations = new StringBuilder(); + + //@Id 的注解 + if (isPrimaryKey || columnConfig.isPrimaryKey()) { + annotations.append("@Id("); + + boolean needComma = false; + if (isAutoIncrement) { + annotations.append("keyType=KeyType.Auto"); + needComma = true; + } else if (columnConfig.getKeyType() != null) { + annotations.append("keyType=KeyType." + columnConfig.getKeyType().name()); + needComma = true; + } + + if (columnConfig.getKeyValue() != null) { + addComma(annotations, needComma); + annotations.append("value=\"" + columnConfig.getKeyValue() + "\""); + needComma = true; + } + + if (columnConfig.getKeyBefore() != null) { + addComma(annotations, needComma); + annotations.append("before=" + columnConfig.getKeyBefore()); + } + + annotations.append(")"); + } + + //@Column 注解 + if (columnConfig.getOnInsertValue() != null + || columnConfig.getOnUpdateValue() != null + || columnConfig.getLarge() != null + || columnConfig.getLogicDelete() != null + || columnConfig.getVersion() != null + || columnConfig.getJdbcType() != null + || columnConfig.getTypeHandler() != null + ) { + annotations.append("@Column("); + boolean needComma = false; + if (columnConfig.getOnInsertValue() != null) { + annotations.append("onInsertValue=\"" + columnConfig.getOnInsertValue() + "\""); + needComma = true; + } + if (columnConfig.getOnUpdateValue() != null) { + addComma(annotations, needComma); + annotations.append("onUpdateValue=\"" + columnConfig.getOnUpdateValue() + "\""); + needComma = true; + } + if (columnConfig.getLarge() != null) { + addComma(annotations, needComma); + annotations.append("isLarge=" + columnConfig.getLarge()); + needComma = true; + } + if (columnConfig.getLogicDelete() != null) { + addComma(annotations, needComma); + annotations.append("isLogicDelete=" + columnConfig.getLogicDelete()); + needComma = true; + } + if (columnConfig.getVersion() != null) { + addComma(annotations, needComma); + annotations.append("version=" + columnConfig.getVersion()); + needComma = true; + } + if (columnConfig.getJdbcType() != null) { + addComma(annotations, needComma); + annotations.append("jdbcType=JdbcType." + columnConfig.getJdbcType().name()); + needComma = true; + } + if (columnConfig.getTypeHandler() != null) { + addComma(annotations, needComma); + annotations.append("typeHandler=" + columnConfig.getTypeHandler().getSimpleName() + ".class"); + } + annotations.append(")"); + } + + //@ColumnMask 注解 + if (columnConfig.getMask() != null) { + annotations.append("@ColumnMask(\"" + columnConfig.getMask() + "\")"); + } + + return annotations.toString(); + } + + private void addComma(StringBuilder annotations, boolean needComma) { + if (needComma) { + annotations.append(", "); + } + } + + public List getImportClasses() { + List importClasses = new ArrayList<>(); + + //lang 包不需要显式导入 + if (!propertyType.startsWith("java.lang.")) { + importClasses.add(propertyType); + } + + + if (isPrimaryKey || (columnConfig != null && columnConfig.isPrimaryKey())) { + importClasses.add(Id.class.getName()); + if (isAutoIncrement || (columnConfig != null && columnConfig.getKeyType() != null)) { + importClasses.add(KeyType.class.getName()); + } + } + + if (columnConfig != null) { + if (columnConfig.getMask() != null) { + importClasses.add(ColumnMask.class.getName()); + } + + if (columnConfig.getJdbcType() != null) { + importClasses.add("org.apache.ibatis.type.JdbcType"); + } + + if (columnConfig.getTypeHandler() != null) { + importClasses.add(columnConfig.getTypeHandler().getName()); + } + + if (columnConfig.getOnInsertValue() != null + || columnConfig.getOnUpdateValue() != null + || columnConfig.getLarge() != null + || columnConfig.getLogicDelete() != null + || columnConfig.getVersion() != null + || columnConfig.getJdbcType() != null + || columnConfig.getTypeHandler() != null + ) { + importClasses.add(com.mybatisflex.annotation.Column.class.getName()); + } + } + + return importClasses; + } + + + @Override + public String toString() { + return "Column{" + + "name='" + name + '\'' + + ", className='" + propertyType + '\'' + + ", remarks='" + remarks + '\'' + + ", isAutoIncrement=" + isAutoIncrement + + '}'; + } +} diff --git a/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/entity/Table.java b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/entity/Table.java new file mode 100644 index 00000000..fb6ee25b --- /dev/null +++ b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/entity/Table.java @@ -0,0 +1,149 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.codegen.entity; + +import com.mybatisflex.codegen.config.GlobalConfig; +import com.mybatisflex.codegen.config.TableConfig; +import com.mybatisflex.core.util.StringUtil; + +import java.util.*; +import java.util.stream.Collectors; + +public class Table { + + private String name; + private String remarks; + private Set primaryKeys; + private List columns = new ArrayList<>(); + + private GlobalConfig globalConfig; + private TableConfig tableConfig; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getRemarks() { + return remarks; + } + + public void setRemarks(String remarks) { + this.remarks = remarks; + } + + + public Set getPrimaryKeys() { + return primaryKeys; + } + + public void setPrimaryKeys(Set primaryKeys) { + this.primaryKeys = primaryKeys; + } + + public void addPrimaryKey(String primaryKey) { + if (primaryKeys == null) { + primaryKeys = new LinkedHashSet<>(); + } + primaryKeys.add(primaryKey); + } + + public List getColumns() { + return columns; + } + + public void setColumns(List columns) { + this.columns = columns; + } + + public void addColumn(Column column) { + columns.add(column); + } + + public GlobalConfig getGlobalConfig() { + return globalConfig; + } + + public void setGlobalConfig(GlobalConfig globalConfig) { + this.globalConfig = globalConfig; + } + + public TableConfig getTableConfig() { + return tableConfig; + } + + public void setTableConfig(TableConfig tableConfig) { + this.tableConfig = tableConfig; + } + + public List buildImports() { + Set imports = new HashSet<>(); + imports.add(com.mybatisflex.annotation.Table.class.getName()); + for (Column column : columns) { + imports.addAll(column.getImportClasses()); + } + return imports.stream().sorted(Comparator.naturalOrder()).collect(Collectors.toList()); + } + + + /** + * 构建 entity 的 Class 名称 + * + * @return className + */ + public String buildEntityClassName() { + String entityJavaFileName = name; + String tablePrefix = globalConfig.getTablePrefix(); + if (tablePrefix != null && name.startsWith(tablePrefix)) { + entityJavaFileName = name.substring(tablePrefix.length()); + } + return StringUtil.firstCharToUpperCase(StringUtil.underlineToCamel(entityJavaFileName)); + } + + /** + * 构建 @Table(...) 注解 + */ + public String buildTableAnnotation() { + StringBuilder tableAnnotation = new StringBuilder("@Table("); + tableAnnotation.append("value=\"").append(name).append("\""); + + if (tableConfig != null) { + if (tableConfig.getSchema() != null) { + tableAnnotation.append(", schema=\"" + tableConfig.getSchema() + "\""); + } + if (tableConfig.getCamelToUnderline() != null) { + tableAnnotation.append(", camelToUnderline=\"" + tableConfig.getCamelToUnderline() + "\""); + } + } + return tableAnnotation.append(")").toString(); + } + + + @Override + public String toString() { + return "Table{" + + "name='" + name + '\'' + + ", remarks='" + remarks + '\'' + + ", primaryKeys='" + primaryKeys + '\'' + + ", columns=" + columns + + '}'; + } + + +} diff --git a/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/template/EnjoyTemplate.java b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/template/EnjoyTemplate.java new file mode 100644 index 00000000..d5132845 --- /dev/null +++ b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/template/EnjoyTemplate.java @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.codegen.template; + +import com.jfinal.template.Engine; +import com.mybatisflex.codegen.config.GlobalConfig; +import com.mybatisflex.codegen.entity.Table; +import com.mybatisflex.core.util.StringUtil; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.HashMap; +import java.util.Map; + +public class EnjoyTemplate implements ITemplate { + + private Engine engine; + + public EnjoyTemplate() { + engine = Engine.create("mybatis-flex", engine -> { + engine.setToClassPathSourceFactory(); + engine.addSharedMethod(StringUtil.class); + }); + } + + @Override + public void generateEntity(GlobalConfig globalConfig, Table table, File entityJavaFile) throws Exception { + Map params = new HashMap<>(); + params.put("globalConfig", globalConfig); + params.put("table", table); + + + FileOutputStream fileOutputStream = new FileOutputStream(entityJavaFile); + engine.getTemplate("/templates/enjoy/entity.tpl").render(params, fileOutputStream); + } + + + @Override + public void generateMapper(GlobalConfig globalConfig, Table table, File mapperJavaFile) throws Exception { + Map params = new HashMap<>(); + params.put("globalConfig", globalConfig); + params.put("table", table); + + + FileOutputStream fileOutputStream = new FileOutputStream(mapperJavaFile); + engine.getTemplate("/templates/enjoy/mapper.tpl").render(params, fileOutputStream); + } +} diff --git a/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/template/ITemplate.java b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/template/ITemplate.java new file mode 100644 index 00000000..aea7e3c6 --- /dev/null +++ b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/template/ITemplate.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.codegen.template; + +import com.mybatisflex.codegen.config.GlobalConfig; +import com.mybatisflex.codegen.entity.Table; + +import java.io.File; + +public interface ITemplate { + + void generateEntity(GlobalConfig globalConfig, Table table, File entityJavaFile) throws Exception ; + + void generateMapper(GlobalConfig globalConfig, Table table, File mapperJavaFile) throws Exception ; +} diff --git a/mybatis-flex-codegen/src/main/resources/templates/enjoy/entity.tpl b/mybatis-flex-codegen/src/main/resources/templates/enjoy/entity.tpl new file mode 100644 index 00000000..c0e1c522 --- /dev/null +++ b/mybatis-flex-codegen/src/main/resources/templates/enjoy/entity.tpl @@ -0,0 +1,26 @@ +package #(globalConfig.entityPackage); + +#for(importClass:table.buildImports()) +import #(importClass); +#end + + +#(table.buildTableAnnotation()) +public class #(table.buildEntityClassName()) { + +#for(column: table.columns) #(column.buildAnnotations()) + private #(column.propertySimpleType) #(column.property); + +#end + + #for(column: table.columns) + public #(column.propertySimpleType) #(column.buildGetter())() { + return #(column.property); + } + + public void #(column.buildSetter())(#(column.propertySimpleType) #(column.property)) { + this.#(column.property) = #(column.property); + } + + #end +} diff --git a/mybatis-flex-codegen/src/main/resources/templates/enjoy/mapper.tpl b/mybatis-flex-codegen/src/main/resources/templates/enjoy/mapper.tpl new file mode 100644 index 00000000..c445097b --- /dev/null +++ b/mybatis-flex-codegen/src/main/resources/templates/enjoy/mapper.tpl @@ -0,0 +1,8 @@ +package #(globalConfig.mapperPackage); + +import com.mybatisflex.core.BaseMapper; +import #(globalConfig.entityPackage).#(table.buildEntityClassName()); + +public interface #(table.buildEntityClassName())Mapper extends BaseMapper<#(table.buildEntityClassName())> { + +} diff --git a/mybatis-flex-codegen/src/test/java/com/mybatisflex/codegen/test/GeneratorTest.java b/mybatis-flex-codegen/src/test/java/com/mybatisflex/codegen/test/GeneratorTest.java new file mode 100644 index 00000000..b51ae2ca --- /dev/null +++ b/mybatis-flex-codegen/src/test/java/com/mybatisflex/codegen/test/GeneratorTest.java @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.codegen.test; + +import com.mybatisflex.codegen.Generator; +import com.mybatisflex.codegen.config.ColumnConfig; +import com.mybatisflex.codegen.config.GlobalConfig; +import com.zaxxer.hikari.HikariDataSource; +import org.junit.Test; + +public class GeneratorTest { + + + @Test + public void testGenerator() { + //配置数据源 + HikariDataSource dataSource = new HikariDataSource(); + dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/jbootadmin?characterEncoding=utf-8"); + dataSource.setUsername("root"); + dataSource.setPassword("123456"); + + + GlobalConfig globalConfig = new GlobalConfig(); + + //设置只生成哪些表 + globalConfig.addGenerateTable("account", "account_session"); + + //设置 entity 的包名 + globalConfig.setEntityPackage("com.test.test"); + + //是否生成 mapper 文件,默认为 false + globalConfig.setMapperGenerateEnable(true); + + //设置 mapper 文件的包名 + globalConfig.setMapperPackage("com.test.mapper"); + + //可以单独配置某个列的数据 + ColumnConfig columnConfig = new ColumnConfig(); + columnConfig.setColumnName("tenant_id"); + columnConfig.setLarge(true); + columnConfig.setVersion(true); + globalConfig.addColumnConfig("account",columnConfig); + + + //通过 datasource 和 globalConfig 创建代码生成器 + Generator generator = new Generator(dataSource, globalConfig); + + //开始生成代码 + generator.generate(); + } +}