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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  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. * @author yangkai.shen
  138. * @date Created in 2019-03-22 09:27
  139. */
  140. @Slf4j
  141. @UtilityClass
  142. public class CodeGenUtil {
  143. private final String ENTITY_JAVA_VM = "Entity.java.vm";
  144. private final String MAPPER_JAVA_VM = "Mapper.java.vm";
  145. private final String SERVICE_JAVA_VM = "Service.java.vm";
  146. private final String SERVICE_IMPL_JAVA_VM = "ServiceImpl.java.vm";
  147. private final String CONTROLLER_JAVA_VM = "Controller.java.vm";
  148. private final String MAPPER_XML_VM = "Mapper.xml.vm";
  149. private final String API_JS_VM = "api.js.vm";
  150. private List<String> getTemplates() {
  151. List<String> templates = new ArrayList<>();
  152. templates.add("template/Entity.java.vm");
  153. templates.add("template/Mapper.java.vm");
  154. templates.add("template/Mapper.xml.vm");
  155. templates.add("template/Service.java.vm");
  156. templates.add("template/ServiceImpl.java.vm");
  157. templates.add("template/Controller.java.vm");
  158. templates.add("template/api.js.vm");
  159. return templates;
  160. }
  161. /**
  162. * 生成代码
  163. */
  164. public void generatorCode(GenConfig genConfig, Entity table, List<Entity> columns, ZipOutputStream zip) {
  165. //配置信息
  166. Props props = getConfig();
  167. boolean hasBigDecimal = false;
  168. //表信息
  169. TableEntity tableEntity = new TableEntity();
  170. tableEntity.setTableName(table.getStr("tableName"));
  171. if (StrUtil.isNotBlank(genConfig.getComments())) {
  172. tableEntity.setComments(genConfig.getComments());
  173. } else {
  174. tableEntity.setComments(table.getStr("tableComment"));
  175. }
  176. String tablePrefix;
  177. if (StrUtil.isNotBlank(genConfig.getTablePrefix())) {
  178. tablePrefix = genConfig.getTablePrefix();
  179. } else {
  180. tablePrefix = props.getStr("tablePrefix");
  181. }
  182. //表名转换成Java类名
  183. String className = tableToJava(tableEntity.getTableName(), tablePrefix);
  184. tableEntity.setCaseClassName(className);
  185. tableEntity.setLowerClassName(StrUtil.lowerFirst(className));
  186. //列信息
  187. List<ColumnEntity> columnList = Lists.newArrayList();
  188. for (Entity column : columns) {
  189. ColumnEntity columnEntity = new ColumnEntity();
  190. columnEntity.setColumnName(column.getStr("columnName"));
  191. columnEntity.setDataType(column.getStr("dataType"));
  192. columnEntity.setComments(column.getStr("columnComment"));
  193. columnEntity.setExtra(column.getStr("extra"));
  194. //列名转换成Java属性名
  195. String attrName = columnToJava(columnEntity.getColumnName());
  196. columnEntity.setCaseAttrName(attrName);
  197. columnEntity.setLowerAttrName(StrUtil.lowerFirst(attrName));
  198. //列的数据类型,转换成Java类型
  199. String attrType = props.getStr(columnEntity.getDataType(), "unknownType");
  200. columnEntity.setAttrType(attrType);
  201. if (!hasBigDecimal && "BigDecimal".equals(attrType)) {
  202. hasBigDecimal = true;
  203. }
  204. //是否主键
  205. if ("PRI".equalsIgnoreCase(column.getStr("columnKey")) && tableEntity.getPk() == null) {
  206. tableEntity.setPk(columnEntity);
  207. }
  208. columnList.add(columnEntity);
  209. }
  210. tableEntity.setColumns(columnList);
  211. //没主键,则第一个字段为主键
  212. if (tableEntity.getPk() == null) {
  213. tableEntity.setPk(tableEntity.getColumns().get(0));
  214. }
  215. //设置velocity资源加载器
  216. Properties prop = new Properties();
  217. prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
  218. Velocity.init(prop);
  219. //封装模板数据
  220. Map<String, Object> map = new HashMap<>(16);
  221. map.put("tableName", tableEntity.getTableName());
  222. map.put("pk", tableEntity.getPk());
  223. map.put("className", tableEntity.getCaseClassName());
  224. map.put("classname", tableEntity.getLowerClassName());
  225. map.put("pathName", tableEntity.getLowerClassName().toLowerCase());
  226. map.put("columns", tableEntity.getColumns());
  227. map.put("hasBigDecimal", hasBigDecimal);
  228. map.put("datetime", DateUtil.now());
  229. map.put("year", DateUtil.year(new Date()));
  230. if (StrUtil.isNotBlank(genConfig.getComments())) {
  231. map.put("comments", genConfig.getComments());
  232. } else {
  233. map.put("comments", tableEntity.getComments());
  234. }
  235. if (StrUtil.isNotBlank(genConfig.getAuthor())) {
  236. map.put("author", genConfig.getAuthor());
  237. } else {
  238. map.put("author", props.getStr("author"));
  239. }
  240. if (StrUtil.isNotBlank(genConfig.getModuleName())) {
  241. map.put("moduleName", genConfig.getModuleName());
  242. } else {
  243. map.put("moduleName", props.getStr("moduleName"));
  244. }
  245. if (StrUtil.isNotBlank(genConfig.getPackageName())) {
  246. map.put("package", genConfig.getPackageName());
  247. map.put("mainPath", genConfig.getPackageName());
  248. } else {
  249. map.put("package", props.getStr("package"));
  250. map.put("mainPath", props.getStr("mainPath"));
  251. }
  252. VelocityContext context = new VelocityContext(map);
  253. //获取模板列表
  254. List<String> templates = getTemplates();
  255. for (String template : templates) {
  256. //渲染模板
  257. StringWriter sw = new StringWriter();
  258. Template tpl = Velocity.getTemplate(template, CharsetUtil.UTF_8);
  259. tpl.merge(context, sw);
  260. try {
  261. //添加到zip
  262. zip.putNextEntry(new ZipEntry(Objects.requireNonNull(getFileName(template, tableEntity.getCaseClassName(), map
  263. .get("package")
  264. .toString(), map.get("moduleName").toString()))));
  265. IoUtil.write(zip, StandardCharsets.UTF_8, false, sw.toString());
  266. IoUtil.close(sw);
  267. zip.closeEntry();
  268. } catch (IOException e) {
  269. throw new RuntimeException("渲染模板失败,表名:" + tableEntity.getTableName(), e);
  270. }
  271. }
  272. }
  273. /**
  274. * 列名转换成Java属性名
  275. */
  276. private String columnToJava(String columnName) {
  277. return WordUtils.capitalizeFully(columnName, new char[]{'_'}).replace("_", "");
  278. }
  279. /**
  280. * 表名转换成Java类名
  281. */
  282. private String tableToJava(String tableName, String tablePrefix) {
  283. if (StrUtil.isNotBlank(tablePrefix)) {
  284. tableName = tableName.replaceFirst(tablePrefix, "");
  285. }
  286. return columnToJava(tableName);
  287. }
  288. /**
  289. * 获取配置信息
  290. */
  291. private Props getConfig() {
  292. Props props = new Props("generator.properties");
  293. props.autoLoad(true);
  294. return props;
  295. }
  296. /**
  297. * 获取文件名
  298. */
  299. private String getFileName(String template, String className, String packageName, String moduleName) {
  300. // 包路径
  301. String packagePath = GenConstants.SIGNATURE + File.separator + "src" + File.separator + "main" + File.separator + "java" + File.separator;
  302. // 资源路径
  303. String resourcePath = GenConstants.SIGNATURE + File.separator + "src" + File.separator + "main" + File.separator + "resources" + File.separator;
  304. // api路径
  305. String apiPath = GenConstants.SIGNATURE + File.separator + "api" + File.separator;
  306. if (StrUtil.isNotBlank(packageName)) {
  307. packagePath += packageName.replace(".", File.separator) + File.separator + moduleName + File.separator;
  308. }
  309. if (template.contains(ENTITY_JAVA_VM)) {
  310. return packagePath + "entity" + File.separator + className + ".java";
  311. }
  312. if (template.contains(MAPPER_JAVA_VM)) {
  313. return packagePath + "mapper" + File.separator + className + "Mapper.java";
  314. }
  315. if (template.contains(SERVICE_JAVA_VM)) {
  316. return packagePath + "service" + File.separator + className + "Service.java";
  317. }
  318. if (template.contains(SERVICE_IMPL_JAVA_VM)) {
  319. return packagePath + "service" + File.separator + "impl" + File.separator + className + "ServiceImpl.java";
  320. }
  321. if (template.contains(CONTROLLER_JAVA_VM)) {
  322. return packagePath + "controller" + File.separator + className + "Controller.java";
  323. }
  324. if (template.contains(MAPPER_XML_VM)) {
  325. return resourcePath + "mapper" + File.separator + className + "Mapper.xml";
  326. }
  327. if (template.contains(API_JS_VM)) {
  328. return apiPath + className.toLowerCase() + ".js";
  329. }
  330. return null;
  331. }
  332. }
  333. ```
  334. ### 3.4. 其余代码参见demo
  335. ## 4. 演示
  336. <video id="video" controls="" preload="none">
  337. <source id="mp4" src="https://static.xkcoding.com/code/spring-boot-demo/codegen/codegen.mp4" type="video/mp4">
  338. <p>您的浏览器版本过低,不支持播放视频演示,可下载演示视频观看,https://static.xkcoding.com/code/spring-boot-demo/codegen/codegen.mp4</p>
  339. </video>
  340. ## 5. 参考
  341. - [基于人人开源 自动构建项目_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/)
  342. - [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 个。