You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

README.md 14 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. # spring-boot-demo-codegen
  2. > 此 demo 主要演示了 Spring Boot 使用**模板技术**生成代码,并提供前端页面,可生成 Entity/Mapper/Service/Controller 等代码。
  3. ## 1. 主要功能
  4. 1. 使用 `velocity` 代码生成
  5. 2. 暂时支持mysql数据库的代码生成
  6. 3. 提供前端页面展示,并下载代码压缩包
  7. > 注意:① Entity里使用lombok,简化代码 ② Mapper 和 Service 层集成 Mybatis-Plus 简化代码
  8. ## 2. 运行
  9. 1. 运行 `SpringBootDemoCodegenApplication` 启动项目
  10. 2. 打开浏览器,输入 http://localhost:8080/demo/index.html
  11. 3. 输入查询条件,生成代码
  12. ## 3. 关键代码
  13. ### 3.1. pom.xml
  14. ```xml
  15. <?xml version="1.0" encoding="UTF-8"?>
  16. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  17. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  18. <modelVersion>4.0.0</modelVersion>
  19. <artifactId>spring-boot-demo-codegen</artifactId>
  20. <version>1.0.0-SNAPSHOT</version>
  21. <packaging>jar</packaging>
  22. <name>spring-boot-demo-codegen</name>
  23. <description>Demo project for Spring Boot</description>
  24. <parent>
  25. <groupId>com.xkcoding</groupId>
  26. <artifactId>spring-boot-demo</artifactId>
  27. <version>1.0.0-SNAPSHOT</version>
  28. </parent>
  29. <properties>
  30. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  31. <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  32. <java.version>1.8</java.version>
  33. </properties>
  34. <dependencies>
  35. <dependency>
  36. <groupId>org.springframework.boot</groupId>
  37. <artifactId>spring-boot-starter-web</artifactId>
  38. <exclusions>
  39. <exclusion>
  40. <groupId>org.springframework.boot</groupId>
  41. <artifactId>spring-boot-starter-tomcat</artifactId>
  42. </exclusion>
  43. </exclusions>
  44. </dependency>
  45. <dependency>
  46. <groupId>org.springframework.boot</groupId>
  47. <artifactId>spring-boot-starter-undertow</artifactId>
  48. </dependency>
  49. <dependency>
  50. <groupId>org.springframework.boot</groupId>
  51. <artifactId>spring-boot-starter-test</artifactId>
  52. <scope>test</scope>
  53. </dependency>
  54. <dependency>
  55. <groupId>com.zaxxer</groupId>
  56. <artifactId>HikariCP</artifactId>
  57. </dependency>
  58. <!--velocity代码生成使用模板 -->
  59. <dependency>
  60. <groupId>org.apache.velocity</groupId>
  61. <artifactId>velocity</artifactId>
  62. <version>1.7</version>
  63. </dependency>
  64. <dependency>
  65. <groupId>org.apache.commons</groupId>
  66. <artifactId>commons-text</artifactId>
  67. <version>1.6</version>
  68. </dependency>
  69. <dependency>
  70. <groupId>mysql</groupId>
  71. <artifactId>mysql-connector-java</artifactId>
  72. </dependency>
  73. <dependency>
  74. <groupId>cn.hutool</groupId>
  75. <artifactId>hutool-all</artifactId>
  76. </dependency>
  77. <dependency>
  78. <groupId>com.google.guava</groupId>
  79. <artifactId>guava</artifactId>
  80. </dependency>
  81. <dependency>
  82. <groupId>org.projectlombok</groupId>
  83. <artifactId>lombok</artifactId>
  84. <optional>true</optional>
  85. </dependency>
  86. </dependencies>
  87. <build>
  88. <finalName>spring-boot-demo-codegen</finalName>
  89. <plugins>
  90. <plugin>
  91. <groupId>org.springframework.boot</groupId>
  92. <artifactId>spring-boot-maven-plugin</artifactId>
  93. </plugin>
  94. </plugins>
  95. </build>
  96. </project>
  97. ```
  98. ### 3.2. 代码生成器配置
  99. ```properties
  100. #代码生成器,配置信息
  101. mainPath=com.xkcoding
  102. #包名
  103. package=com.xkcoding
  104. moduleName=generator
  105. #作者
  106. author=Yangkai.Shen
  107. #表前缀(类名不会包含表前缀)
  108. tablePrefix=tb_
  109. #类型转换,配置信息
  110. tinyint=Integer
  111. smallint=Integer
  112. mediumint=Integer
  113. int=Integer
  114. integer=Integer
  115. bigint=Long
  116. float=Float
  117. double=Double
  118. decimal=BigDecimal
  119. bit=Boolean
  120. char=String
  121. varchar=String
  122. tinytext=String
  123. text=String
  124. mediumtext=String
  125. longtext=String
  126. date=LocalDateTime
  127. datetime=LocalDateTime
  128. timestamp=LocalDateTime
  129. ```
  130. ### 3.3. CodeGenUtil.java
  131. ```java
  132. /**
  133. * <p>
  134. * 代码生成器 工具类
  135. * </p>
  136. *
  137. * @package: com.xkcoding.codegen.utils
  138. * @description: 代码生成器 工具类
  139. * @author: yangkai.shen
  140. * @date: Created in 2019-03-22 09:27
  141. * @copyright: Copyright (c) 2019
  142. * @version: V1.0
  143. * @modified: yangkai.shen
  144. */
  145. @Slf4j
  146. @UtilityClass
  147. public class CodeGenUtil {
  148. private final String ENTITY_JAVA_VM = "Entity.java.vm";
  149. private final String MAPPER_JAVA_VM = "Mapper.java.vm";
  150. private final String SERVICE_JAVA_VM = "Service.java.vm";
  151. private final String SERVICE_IMPL_JAVA_VM = "ServiceImpl.java.vm";
  152. private final String CONTROLLER_JAVA_VM = "Controller.java.vm";
  153. private final String MAPPER_XML_VM = "Mapper.xml.vm";
  154. private final String API_JS_VM = "api.js.vm";
  155. private List<String> getTemplates() {
  156. List<String> templates = new ArrayList<>();
  157. templates.add("template/Entity.java.vm");
  158. templates.add("template/Mapper.java.vm");
  159. templates.add("template/Mapper.xml.vm");
  160. templates.add("template/Service.java.vm");
  161. templates.add("template/ServiceImpl.java.vm");
  162. templates.add("template/Controller.java.vm");
  163. templates.add("template/api.js.vm");
  164. return templates;
  165. }
  166. /**
  167. * 生成代码
  168. */
  169. public void generatorCode(GenConfig genConfig, Entity table, List<Entity> columns, ZipOutputStream zip) {
  170. //配置信息
  171. Props props = getConfig();
  172. boolean hasBigDecimal = false;
  173. //表信息
  174. TableEntity tableEntity = new TableEntity();
  175. tableEntity.setTableName(table.getStr("tableName"));
  176. if (StrUtil.isNotBlank(genConfig.getComments())) {
  177. tableEntity.setComments(genConfig.getComments());
  178. } else {
  179. tableEntity.setComments(table.getStr("tableComment"));
  180. }
  181. String tablePrefix;
  182. if (StrUtil.isNotBlank(genConfig.getTablePrefix())) {
  183. tablePrefix = genConfig.getTablePrefix();
  184. } else {
  185. tablePrefix = props.getStr("tablePrefix");
  186. }
  187. //表名转换成Java类名
  188. String className = tableToJava(tableEntity.getTableName(), tablePrefix);
  189. tableEntity.setCaseClassName(className);
  190. tableEntity.setLowerClassName(StrUtil.lowerFirst(className));
  191. //列信息
  192. List<ColumnEntity> columnList = Lists.newArrayList();
  193. for (Entity column : columns) {
  194. ColumnEntity columnEntity = new ColumnEntity();
  195. columnEntity.setColumnName(column.getStr("columnName"));
  196. columnEntity.setDataType(column.getStr("dataType"));
  197. columnEntity.setComments(column.getStr("columnComment"));
  198. columnEntity.setExtra(column.getStr("extra"));
  199. //列名转换成Java属性名
  200. String attrName = columnToJava(columnEntity.getColumnName());
  201. columnEntity.setCaseAttrName(attrName);
  202. columnEntity.setLowerAttrName(StrUtil.lowerFirst(attrName));
  203. //列的数据类型,转换成Java类型
  204. String attrType = props.getStr(columnEntity.getDataType(), "unknownType");
  205. columnEntity.setAttrType(attrType);
  206. if (!hasBigDecimal && "BigDecimal".equals(attrType)) {
  207. hasBigDecimal = true;
  208. }
  209. //是否主键
  210. if ("PRI".equalsIgnoreCase(column.getStr("columnKey")) && tableEntity.getPk() == null) {
  211. tableEntity.setPk(columnEntity);
  212. }
  213. columnList.add(columnEntity);
  214. }
  215. tableEntity.setColumns(columnList);
  216. //没主键,则第一个字段为主键
  217. if (tableEntity.getPk() == null) {
  218. tableEntity.setPk(tableEntity.getColumns().get(0));
  219. }
  220. //设置velocity资源加载器
  221. Properties prop = new Properties();
  222. prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
  223. Velocity.init(prop);
  224. //封装模板数据
  225. Map<String, Object> map = new HashMap<>(16);
  226. map.put("tableName", tableEntity.getTableName());
  227. map.put("pk", tableEntity.getPk());
  228. map.put("className", tableEntity.getCaseClassName());
  229. map.put("classname", tableEntity.getLowerClassName());
  230. map.put("pathName", tableEntity.getLowerClassName().toLowerCase());
  231. map.put("columns", tableEntity.getColumns());
  232. map.put("hasBigDecimal", hasBigDecimal);
  233. map.put("datetime", DateUtil.now());
  234. map.put("year", DateUtil.year(new Date()));
  235. if (StrUtil.isNotBlank(genConfig.getComments())) {
  236. map.put("comments", genConfig.getComments());
  237. } else {
  238. map.put("comments", tableEntity.getComments());
  239. }
  240. if (StrUtil.isNotBlank(genConfig.getAuthor())) {
  241. map.put("author", genConfig.getAuthor());
  242. } else {
  243. map.put("author", props.getStr("author"));
  244. }
  245. if (StrUtil.isNotBlank(genConfig.getModuleName())) {
  246. map.put("moduleName", genConfig.getModuleName());
  247. } else {
  248. map.put("moduleName", props.getStr("moduleName"));
  249. }
  250. if (StrUtil.isNotBlank(genConfig.getPackageName())) {
  251. map.put("package", genConfig.getPackageName());
  252. map.put("mainPath", genConfig.getPackageName());
  253. } else {
  254. map.put("package", props.getStr("package"));
  255. map.put("mainPath", props.getStr("mainPath"));
  256. }
  257. VelocityContext context = new VelocityContext(map);
  258. //获取模板列表
  259. List<String> templates = getTemplates();
  260. for (String template : templates) {
  261. //渲染模板
  262. StringWriter sw = new StringWriter();
  263. Template tpl = Velocity.getTemplate(template, CharsetUtil.UTF_8);
  264. tpl.merge(context, sw);
  265. try {
  266. //添加到zip
  267. zip.putNextEntry(new ZipEntry(Objects.requireNonNull(getFileName(template, tableEntity.getCaseClassName(), map
  268. .get("package")
  269. .toString(), map.get("moduleName").toString()))));
  270. IoUtil.write(zip, StandardCharsets.UTF_8, false, sw.toString());
  271. IoUtil.close(sw);
  272. zip.closeEntry();
  273. } catch (IOException e) {
  274. throw new RuntimeException("渲染模板失败,表名:" + tableEntity.getTableName(), e);
  275. }
  276. }
  277. }
  278. /**
  279. * 列名转换成Java属性名
  280. */
  281. private String columnToJava(String columnName) {
  282. return WordUtils.capitalizeFully(columnName, new char[]{'_'}).replace("_", "");
  283. }
  284. /**
  285. * 表名转换成Java类名
  286. */
  287. private String tableToJava(String tableName, String tablePrefix) {
  288. if (StrUtil.isNotBlank(tablePrefix)) {
  289. tableName = tableName.replaceFirst(tablePrefix, "");
  290. }
  291. return columnToJava(tableName);
  292. }
  293. /**
  294. * 获取配置信息
  295. */
  296. private Props getConfig() {
  297. Props props = new Props("generator.properties");
  298. props.autoLoad(true);
  299. return props;
  300. }
  301. /**
  302. * 获取文件名
  303. */
  304. private String getFileName(String template, String className, String packageName, String moduleName) {
  305. // 包路径
  306. String packagePath = GenConstants.SIGNATURE + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator;
  307. // 资源路径
  308. String resourcePath = GenConstants.SIGNATURE + File.separator + "src" + File.separator + "main" + File.separator + "resources" + File.separator;
  309. // api路径
  310. String apiPath = GenConstants.SIGNATURE + File.separator + "api" + File.separator;
  311. if (StrUtil.isNotBlank(packageName)) {
  312. packagePath += packageName.replace(".", File.separator) + File.separator + moduleName + File.separator;
  313. }
  314. if (template.contains(ENTITY_JAVA_VM)) {
  315. return packagePath + "entity" + File.separator + className + ".java";
  316. }
  317. if (template.contains(MAPPER_JAVA_VM)) {
  318. return packagePath + "mapper" + File.separator + className + "Mapper.java";
  319. }
  320. if (template.contains(SERVICE_JAVA_VM)) {
  321. return packagePath + "service" + File.separator + className + "Service.java";
  322. }
  323. if (template.contains(SERVICE_IMPL_JAVA_VM)) {
  324. return packagePath + "service" + File.separator + "impl" + File.separator + className + "ServiceImpl.java";
  325. }
  326. if (template.contains(CONTROLLER_JAVA_VM)) {
  327. return packagePath + "controller" + File.separator + className + "Controller.java";
  328. }
  329. if (template.contains(MAPPER_XML_VM)) {
  330. return resourcePath + "mapper" + File.separator + className + "Mapper.xml";
  331. }
  332. if (template.contains(API_JS_VM)) {
  333. return apiPath + className.toLowerCase() + ".js";
  334. }
  335. return null;
  336. }
  337. }
  338. ```
  339. ### 3.4. 其余代码参见demo
  340. ## 4. 演示
  341. <video id="video" controls="" preload="none">
  342. <source id="mp4" src="https://static.xkcoding.com/code/spring-boot-demo/codegen/codegen.mp4" type="video/mp4">
  343. <p>您的浏览器版本过低,不支持播放视频演示,可下载演示视频观看,https://static.xkcoding.com/code/spring-boot-demo/codegen/codegen.mp4</p>
  344. </video>
  345. ## 5. 参考
  346. - [基于人人开源 自动构建项目_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/)
  347. - [Mybatis-Plus代码生成器](https://mybatis.plus/guide/generator.html#%E6%B7%BB%E5%8A%A0%E4%BE%9D%E8%B5%96)

一个用来深度学习并实战 spring boot 的项目,目前总共包含 66 个集成demo,已经完成 55 个。