本站建设:代码生成功能集成

文章来源原创   作者:临窗旋墨   发布时间:2021-06-22   阅读:665   标签:springboot
[TOC]

003-代码生成功能集成

2019-11-14

1- 代码生成思路

​ 网上关于代码自动生成的开源项目很多,基本可以拿来之后修改模板文件直接使用.本项目的代码自动生成主要是17年左右借鉴人人开源上面的代码而来.

​ 基本思路都是一样的:

  1. 连接数据库获取数据库表的全部信息(本项目只实现mysql版本)
    • 如需支持多种数据库,则定义dao接口,不同的数据库做不同的实现,根据配置文件指定Primary
  2. 解析表的基本信息,列的基本信息映射成对象
  3. 编写各层模板,根据解析的数据对模板进行填充
  4. 导出填充后的模板

2-本项目中代码生成功能的大概实现

2.1 配置文件与映射

generator-config.properties

  1. #代码生成器,配置信息
  2. #包名
  3. packageName=pers.vic
  4. #模块名
  5. moduleName=system
  6. #作者
  7. author=Vic.xu
  8. #Email
  9. email=xuduochoua@163.com
  10. #表前缀(类名不会包含表前缀)
  11. tablePrefix=
  12. #需要填充的模板
  13. templates[0]=generator/templates/Entity.java.vm
  14. #略
  15. #数据类型转换,配置信息:数据库类型->java类型
  16. tinyint=Integer
  17. #略

2.2 解析表后的实体

  1. TableEntity 对应一张表的基本数据:表名/备注/主键/对应的类名/创建时间/关联的ColumnEntity列表等
  2. ColumnEntity对应列的属性:列名/列属性/备注/属性名/属性类型/是否主键/对应的ColumnExtend
  3. ColumnExtend列的扩展:本项目额外增加的根据备注对列做的额外的处理说明

2.3service层大体代码

  1. @Service
  2. public class GeneratorService{
  3. @Resource
  4. private ConfigurationOfGenerator configurationOfGenerator;
  5. @Resource
  6. private GeneratorMapper generatorMapper;
  7. public List<TableEntity> list(Lookup lookup) {
  8. List<TableEntity> datas = generatorMapper.queryList(lookup);
  9. return datas;
  10. }
  11. private List<ColumnEntity> queryColumns(String tableName) {
  12. return generatorMapper.queryColumns(tableName);
  13. }
  14. private TableEntity queryTable(String tableName) {
  15. return generatorMapper.queryTable(tableName);
  16. }
  17. /**
  18. * 根据表名生成代码
  19. *
  20. * @param moduleName
  21. * @param packageName
  22. */
  23. public byte[] generatorCode(String[] tableNames, String packageName, String moduleName) {
  24. ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
  25. ZipOutputStream zip = new ZipOutputStream(outputStream);
  26. for (String tableName : tableNames) {
  27. // 查询表信息
  28. TableEntity table = queryTable(tableName);
  29. // 查询列信息
  30. List<ColumnEntity> columns = queryColumns(tableName);
  31. // 生成代码
  32. generatorCode(table, packageName, moduleName, columns, zip);
  33. }
  34. IOUtils.closeQuietly(zip);
  35. return outputStream.toByteArray();
  36. }
  37. private void generatorCode(TableEntity table, String packageName, String moduleName, List<ColumnEntity> columns,
  38. ZipOutputStream zip) {
  39. Map<String, Object> map = getTemplateData(table, packageName, moduleName, columns);
  40. VelocityContext context = new VelocityContext(map);
  41. // 获取模板列表
  42. List<String> templates = getTemplates();
  43. for (String template : templates) {
  44. // 渲染模板
  45. StringWriter sw = new StringWriter();
  46. Template tpl = Velocity.getTemplate(template, "UTF-8");
  47. tpl.merge(context, sw);
  48. try {
  49. // 添加到zip
  50. String fileName = getFileName(template, table.getClassName(), configurationOfGenerator.getPackageName(),
  51. configurationOfGenerator.getModuleName());
  52. zip.putNextEntry(new ZipEntry(fileName));
  53. IOUtils.write(sw.toString(), zip, "UTF-8");
  54. IOUtils.closeQuietly(sw);
  55. zip.closeEntry();
  56. } catch (Exception e) {
  57. throw new RuntimeException("渲染模板失败,表名:" + table.getTableName(), e);
  58. }
  59. }
  60. }
  61. //获得渲染模板的数据
  62. private Map<String, Object> getTemplateData(TableEntity table, String packageName, String moduleName, List<ColumnEntity> columns) {
  63. // 配置信息
  64. Configuration config = getConfig();
  65. boolean hasBigDecimal = false;
  66. String className = tableToJava(table.getTableName(), configurationOfGenerator.getTablePrefix());
  67. table.setClassName(className);
  68. // 第一个字母小写
  69. table.setClassname(StringUtils.uncapitalize(className));
  70. // 列信息
  71. for (ColumnEntity column : columns) {
  72. // 列名转换成Java属性名
  73. String attrName = columnToJava(column.getColumnName());
  74. column.setAttrName(attrName);
  75. column.setAttrname(StringUtils.uncapitalize(attrName));
  76. // 列的数据类型,转换成Java类型
  77. String attrType = config.getString(column.getDataType(), "unknowType");
  78. column.setAttrType(attrType);
  79. if (!hasBigDecimal && attrType.equals("BigDecimal")) {
  80. hasBigDecimal = true;
  81. }
  82. if ("Date".equals(attrType)) {
  83. table.setHasDate(true);
  84. }
  85. // 是否主键
  86. if ("PRI".equalsIgnoreCase(column.getColumnKey()) && table.getPk() == null) {
  87. table.setPk(column);
  88. }
  89. // 根据列是否是图片和日期 判断表中是否含有图片和日期
  90. ColumnExtend extend = ColumnExtend.initExtends(column);
  91. table.findExtend(extend);
  92. }
  93. // 没主键,则第一个字段为主键
  94. table.setColumns(columns);
  95. if (table.getPk() == null) {
  96. table.setPk(columns.get(0));
  97. }
  98. // 设置velocity资源加载器
  99. Properties prop = new Properties();
  100. prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
  101. Velocity.init(prop);
  102. // 封装模板数据
  103. Map<String, Object> map = new HashMap<String, Object>();
  104. map.put("table", table);
  105. map.put("tableName", table.getTableName());
  106. map.put("comments", table.getComments());
  107. map.put("pk", table.getPk());
  108. map.put("className", table.getClassName());
  109. map.put("classname", table.getClassname());
  110. map.put("pathName", table.getClassname().toLowerCase());
  111. map.put("columns", table.getColumns());
  112. map.put("hasBigDecimal", hasBigDecimal);
  113. if (StringUtils.isEmpty(packageName)) {
  114. map.put("package", config.getString("packageName"));
  115. } else {
  116. map.put("package", packageName);
  117. }
  118. if (StringUtils.isEmpty(packageName)) {
  119. map.put("moduleName", config.getString("moduleName"));
  120. } else {
  121. map.put("moduleName", moduleName);
  122. }
  123. map.put("author", config.getString("author"));
  124. map.put("email", config.getString("email"));
  125. map.put("datetime", DateFormatUtils.format(new Date(), "yyyy-mm-dd HH:mm"));
  126. return map;
  127. }
  128. /**
  129. * 获取文件名
  130. */
  131. public static String getFileName(String template, String className, String packageName, String moduleName) {
  132. String packagePath = "generator" + File.separator + className;
  133. /*
  134. * packagePath = "main" + File.separator + "java" + File.separator; if
  135. * (StringUtils.isNotBlank(packageName)) { packagePath +=
  136. * packageName.replace(".", File.separator) + File.separator + moduleName +
  137. * File.separator; }
  138. */
  139. // 实体
  140. if (template.contains("Entity.java.vm")) {
  141. return packagePath + File.separator + className + ".java";
  142. }
  143. // 查询条件
  144. if (template.contains("Lookup.java.vm")) {
  145. return packagePath + File.separator + className + "Lookup.java";
  146. }
  147. // mapper.java
  148. if (template.contains("Mapper.java.vm")) {
  149. return packagePath + File.separator + className + "Mapper.java";
  150. }
  151. // service
  152. if (template.contains("Service.java.vm")) {
  153. return packagePath + File.separator + className + "Service.java";
  154. }
  155. // controller
  156. if (template.contains("Controller.java.vm")) {
  157. return packagePath + File.separator + className + "Controller.java";
  158. }
  159. // mapper.xnl
  160. if (template.contains("Mapper.xml.vm")) {
  161. return packagePath + File.separator + className + "Mapper.xml";
  162. }
  163. // list.jsp
  164. if (template.contains("list.jsp.vm")) {
  165. return packagePath + File.separator + "list.jsp";
  166. }
  167. // form.jsp
  168. if (template.contains("form.jsp.vm")) {
  169. return packagePath + File.separator + "form.jsp";
  170. }
  171. return null;
  172. }
  173. /**
  174. * 获取要填充的模板
  175. * @return
  176. */
  177. public List<String> getTemplates() {
  178. return configurationOfGenerator.getTemplates();
  179. }
  180. /**
  181. * 表名转换成Java类名
  182. */
  183. private String tableToJava(String tableName, String tablePrefix) {
  184. if (StringUtils.isNotBlank(tablePrefix)) {
  185. tableName = tableName.replaceFirst(tablePrefix, "");
  186. }
  187. return columnToJava(tableName);
  188. }
  189. /**
  190. * 列名转换成Java属性名
  191. */
  192. public static String columnToJava(String columnName) {
  193. // return WordUtils.capitalizeFully(columnName, new char[] { '_' }).replace("_", "");//aaBBcc-->aabbcc 不是我想要的
  194. return underlineToCamel(columnName);
  195. }
  196. /**
  197. * 下划线转驼峰 但是不小写
  198. *
  199. * @param str
  200. * @return
  201. */
  202. static String UNDERLINE = "_";
  203. public static String underlineToCamel(String str) {
  204. if (StringUtils.isEmpty(str)) {
  205. return str;
  206. }
  207. StringBuffer sb = new StringBuffer();
  208. for (String s : str.split(UNDERLINE)) {
  209. sb.append(StringUtils.capitalize(s));
  210. }
  211. return sb.toString();
  212. }
  213. /**
  214. * 获取配置信息
  215. */
  216. public static Configuration getConfig() {
  217. try {
  218. return new PropertiesConfiguration("config/generator-config.properties");
  219. } catch (ConfigurationException e) {
  220. throw new RuntimeException("获取配置文件失败,", e);
  221. }
  222. }
  223. public Map<String, String> findTableDetail(String tableName, String packageName, String moduleName) {
  224. // 查询表信息
  225. TableEntity table = queryTable(tableName);
  226. // 查询列信息
  227. List<ColumnEntity> columns = queryColumns(tableName);
  228. Map<String, Object> map = getTemplateData(table, packageName, moduleName, columns);
  229. VelocityContext context = new VelocityContext(map);
  230. // 获取模板列表
  231. List<String> templates = getTemplates();
  232. Map<String, String> data = new LinkedHashMap<String, String>();
  233. for (String template : templates) {
  234. // 渲染模板
  235. StringWriter sw = new StringWriter();
  236. Template tpl = Velocity.getTemplate(template, "UTF-8");
  237. tpl.merge(context, sw);
  238. try {
  239. // 添加到zip
  240. String fileName = getFileName(template, table.getClassName(), configurationOfGenerator.getPackageName(),
  241. configurationOfGenerator.getModuleName());
  242. data.put(fileName.replace("generator" + File.separator, "").replace(File.separator, "_"), sw.toString());
  243. } catch (Exception e) {
  244. throw new RuntimeException("渲染模板失败,表名:" + table.getTableName(), e);
  245. }
  246. }
  247. return data;
  248. }
  249. }

发表评论

目录