diff --git a/spring-boot-demo-codegen/README.md b/spring-boot-demo-codegen/README.md index 5452f24..9492327 100644 --- a/spring-boot-demo-codegen/README.md +++ b/spring-boot-demo-codegen/README.md @@ -1,3 +1,416 @@ # spring-boot-demo-codegen -> 此 demo 主要演示了 Spring Boot 使用模板生成代码,并提供前端页面,可生成 Entity/Mapper/Service/Controller 等代码。 \ No newline at end of file +> 此 demo 主要演示了 Spring Boot 使用**模板技术**生成代码,并提供前端页面,可生成 Entity/Mapper/Service/Controller 等代码。 + +## 1. 主要功能 + +1. 使用 `velocity` 代码生成 +2. 暂时支持mysql数据库的代码生成 +3. 提供前端页面展示,并下载代码压缩包 + +> 注意:① Entity里使用lombok,简化代码 ② Mapper 和 Service 层集成 Mybatis-Plus 简化代码 + +## 2. 运行 + +1. 运行 `SpringBootDemoCodegenApplication` 启动项目 +2. 打开浏览器,输入 http://localhost:8080/demo/index.html +3. 输入查询条件,生成代码 + +## 3. 关键代码 + +### 3.1. pom.xml + +```xml + + + 4.0.0 + + spring-boot-demo-codegen + 1.0.0-SNAPSHOT + jar + + spring-boot-demo-codegen + Demo project for Spring Boot + + + com.xkcoding + spring-boot-demo + 1.0.0-SNAPSHOT + + + + UTF-8 + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + + org.springframework.boot + spring-boot-starter-undertow + + + + org.springframework.boot + spring-boot-starter-test + test + + + + com.zaxxer + HikariCP + + + + + org.apache.velocity + velocity + 1.7 + + + + org.apache.commons + commons-text + 1.6 + + + + mysql + mysql-connector-java + + + + cn.hutool + hutool-all + + + + com.google.guava + guava + + + + org.projectlombok + lombok + true + + + + + spring-boot-demo-codegen + + + org.springframework.boot + spring-boot-maven-plugin + + + + + +``` + +### 3.2. 代码生成器配置 + +```properties +#代码生成器,配置信息 +mainPath=com.xkcoding +#包名 +package=com.xkcoding +moduleName=generator +#作者 +author=Yangkai.Shen +#表前缀(类名不会包含表前缀) +tablePrefix=tb_ +#类型转换,配置信息 +tinyint=Integer +smallint=Integer +mediumint=Integer +int=Integer +integer=Integer +bigint=Long +float=Float +double=Double +decimal=BigDecimal +bit=Boolean +char=String +varchar=String +tinytext=String +text=String +mediumtext=String +longtext=String +date=LocalDateTime +datetime=LocalDateTime +timestamp=LocalDateTime +``` + +### 3.3. CodeGenUtil.java + +```java +/** + *

+ * 代码生成器 工具类 + *

+ * + * @package: com.xkcoding.codegen.utils + * @description: 代码生成器 工具类 + * @author: yangkai.shen + * @date: Created in 2019-03-22 09:27 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Slf4j +@UtilityClass +public class CodeGenUtil { + + private final String ENTITY_JAVA_VM = "Entity.java.vm"; + private final String MAPPER_JAVA_VM = "Mapper.java.vm"; + private final String SERVICE_JAVA_VM = "Service.java.vm"; + private final String SERVICE_IMPL_JAVA_VM = "ServiceImpl.java.vm"; + private final String CONTROLLER_JAVA_VM = "Controller.java.vm"; + private final String MAPPER_XML_VM = "Mapper.xml.vm"; + private final String API_JS_VM = "api.js.vm"; + + private List getTemplates() { + List templates = new ArrayList<>(); + templates.add("template/Entity.java.vm"); + templates.add("template/Mapper.java.vm"); + templates.add("template/Mapper.xml.vm"); + templates.add("template/Service.java.vm"); + templates.add("template/ServiceImpl.java.vm"); + templates.add("template/Controller.java.vm"); + + templates.add("template/api.js.vm"); + return templates; + } + + /** + * 生成代码 + */ + public void generatorCode(GenConfig genConfig, Entity table, List columns, ZipOutputStream zip) { + //配置信息 + Props props = getConfig(); + boolean hasBigDecimal = false; + //表信息 + TableEntity tableEntity = new TableEntity(); + tableEntity.setTableName(table.getStr("tableName")); + + if (StrUtil.isNotBlank(genConfig.getComments())) { + tableEntity.setComments(genConfig.getComments()); + } else { + tableEntity.setComments(table.getStr("tableComment")); + } + + String tablePrefix; + if (StrUtil.isNotBlank(genConfig.getTablePrefix())) { + tablePrefix = genConfig.getTablePrefix(); + } else { + tablePrefix = props.getStr("tablePrefix"); + } + + //表名转换成Java类名 + String className = tableToJava(tableEntity.getTableName(), tablePrefix); + tableEntity.setCaseClassName(className); + tableEntity.setLowerClassName(StrUtil.lowerFirst(className)); + + //列信息 + List columnList = Lists.newArrayList(); + for (Entity column : columns) { + ColumnEntity columnEntity = new ColumnEntity(); + columnEntity.setColumnName(column.getStr("columnName")); + columnEntity.setDataType(column.getStr("dataType")); + columnEntity.setComments(column.getStr("columnComment")); + columnEntity.setExtra(column.getStr("extra")); + + //列名转换成Java属性名 + String attrName = columnToJava(columnEntity.getColumnName()); + columnEntity.setCaseAttrName(attrName); + columnEntity.setLowerAttrName(StrUtil.lowerFirst(attrName)); + + //列的数据类型,转换成Java类型 + String attrType = props.getStr(columnEntity.getDataType(), "unknownType"); + columnEntity.setAttrType(attrType); + if (!hasBigDecimal && "BigDecimal".equals(attrType)) { + hasBigDecimal = true; + } + //是否主键 + if ("PRI".equalsIgnoreCase(column.getStr("columnKey")) && tableEntity.getPk() == null) { + tableEntity.setPk(columnEntity); + } + + columnList.add(columnEntity); + } + tableEntity.setColumns(columnList); + + //没主键,则第一个字段为主键 + if (tableEntity.getPk() == null) { + tableEntity.setPk(tableEntity.getColumns().get(0)); + } + + //设置velocity资源加载器 + Properties prop = new Properties(); + prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + Velocity.init(prop); + //封装模板数据 + Map map = new HashMap<>(16); + map.put("tableName", tableEntity.getTableName()); + map.put("pk", tableEntity.getPk()); + map.put("className", tableEntity.getCaseClassName()); + map.put("classname", tableEntity.getLowerClassName()); + map.put("pathName", tableEntity.getLowerClassName().toLowerCase()); + map.put("columns", tableEntity.getColumns()); + map.put("hasBigDecimal", hasBigDecimal); + map.put("datetime", DateUtil.now()); + map.put("year", DateUtil.year(new Date())); + + if (StrUtil.isNotBlank(genConfig.getComments())) { + map.put("comments", genConfig.getComments()); + } else { + map.put("comments", tableEntity.getComments()); + } + + if (StrUtil.isNotBlank(genConfig.getAuthor())) { + map.put("author", genConfig.getAuthor()); + } else { + map.put("author", props.getStr("author")); + } + + if (StrUtil.isNotBlank(genConfig.getModuleName())) { + map.put("moduleName", genConfig.getModuleName()); + } else { + map.put("moduleName", props.getStr("moduleName")); + } + + if (StrUtil.isNotBlank(genConfig.getPackageName())) { + map.put("package", genConfig.getPackageName()); + map.put("mainPath", genConfig.getPackageName()); + } else { + map.put("package", props.getStr("package")); + map.put("mainPath", props.getStr("mainPath")); + } + VelocityContext context = new VelocityContext(map); + + //获取模板列表 + List templates = getTemplates(); + for (String template : templates) { + //渲染模板 + StringWriter sw = new StringWriter(); + Template tpl = Velocity.getTemplate(template, CharsetUtil.UTF_8); + tpl.merge(context, sw); + + try { + //添加到zip + zip.putNextEntry(new ZipEntry(Objects.requireNonNull(getFileName(template, tableEntity.getCaseClassName(), map + .get("package") + .toString(), map.get("moduleName").toString())))); + IoUtil.write(zip, StandardCharsets.UTF_8, false, sw.toString()); + IoUtil.close(sw); + zip.closeEntry(); + } catch (IOException e) { + throw new RuntimeException("渲染模板失败,表名:" + tableEntity.getTableName(), e); + } + } + } + + + /** + * 列名转换成Java属性名 + */ + private String columnToJava(String columnName) { + return WordUtils.capitalizeFully(columnName, new char[]{'_'}).replace("_", ""); + } + + /** + * 表名转换成Java类名 + */ + private String tableToJava(String tableName, String tablePrefix) { + if (StrUtil.isNotBlank(tablePrefix)) { + tableName = tableName.replaceFirst(tablePrefix, ""); + } + return columnToJava(tableName); + } + + /** + * 获取配置信息 + */ + private Props getConfig() { + Props props = new Props("generator.properties"); + props.autoLoad(true); + return props; + } + + /** + * 获取文件名 + */ + private String getFileName(String template, String className, String packageName, String moduleName) { + // 包路径 + String packagePath = GenConstants.SIGNATURE + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator; + // 资源路径 + String resourcePath = GenConstants.SIGNATURE + File.separator + "src" + File.separator + "main" + File.separator + "resources" + File.separator; + // api路径 + String apiPath = GenConstants.SIGNATURE + File.separator + "api" + File.separator; + + if (StrUtil.isNotBlank(packageName)) { + packagePath += packageName.replace(".", File.separator) + File.separator + moduleName + File.separator; + } + + if (template.contains(ENTITY_JAVA_VM)) { + return packagePath + "entity" + File.separator + className + ".java"; + } + + if (template.contains(MAPPER_JAVA_VM)) { + return packagePath + "mapper" + File.separator + className + "Mapper.java"; + } + + if (template.contains(SERVICE_JAVA_VM)) { + return packagePath + "service" + File.separator + className + "Service.java"; + } + + if (template.contains(SERVICE_IMPL_JAVA_VM)) { + return packagePath + "service" + File.separator + "impl" + File.separator + className + "ServiceImpl.java"; + } + + if (template.contains(CONTROLLER_JAVA_VM)) { + return packagePath + "controller" + File.separator + className + "Controller.java"; + } + + if (template.contains(MAPPER_XML_VM)) { + return resourcePath + "mapper" + File.separator + className + "Mapper.xml"; + } + + if (template.contains(API_JS_VM)) { + return apiPath + className.toLowerCase() + ".js"; + } + + return null; + } +} +``` + +### 3.4. 其余代码参见demo + +## 4. 演示 + + + +## 5. 参考 + +- [基于人人开源 自动构建项目_V1](https://qq343509740.gitee.io/2018/12/20/%E7%AC%94%E8%AE%B0/%E8%87%AA%E5%8A%A8%E6%9E%84%E5%BB%BA%E9%A1%B9%E7%9B%AE/%E5%9F%BA%E4%BA%8E%E4%BA%BA%E4%BA%BA%E5%BC%80%E6%BA%90%20%E8%87%AA%E5%8A%A8%E6%9E%84%E5%BB%BA%E9%A1%B9%E7%9B%AE_V1/) + +- [Mybatis-Plus代码生成器](https://mybatis.plus/guide/generator.html#%E6%B7%BB%E5%8A%A0%E4%BE%9D%E8%B5%96) + diff --git a/spring-boot-demo-codegen/src/main/java/com/xkcoding/codegen/constants/GenConstants.java b/spring-boot-demo-codegen/src/main/java/com/xkcoding/codegen/constants/GenConstants.java index 52674c8..599373b 100644 --- a/spring-boot-demo-codegen/src/main/java/com/xkcoding/codegen/constants/GenConstants.java +++ b/spring-boot-demo-codegen/src/main/java/com/xkcoding/codegen/constants/GenConstants.java @@ -17,5 +17,5 @@ public interface GenConstants { /** * 签名 */ - String SIGNATURE = "xkcoding"; + String SIGNATURE = "xkcoding代码生成"; } diff --git a/spring-boot-demo-codegen/src/main/resources/static/index.html b/spring-boot-demo-codegen/src/main/resources/static/index.html index 1a2460f..3d9a0ea 100644 --- a/spring-boot-demo-codegen/src/main/resources/static/index.html +++ b/spring-boot-demo-codegen/src/main/resources/static/index.html @@ -280,7 +280,11 @@ search(name) { this.$refs[name].validate((valid) => { if (this.tableRequest.prepend === "") { - this.$Message.error("请选择前缀"); + this.$Message.error("请选择jdbc-url前缀"); + return + } + if (this.tableRequest.prepend !== "jdbc:mysql://") { + this.$Message.error("暂时只支持 mysql 类型"); return } if (valid) {