当前位置:   article > 正文

代码生成器_代码生成器是什么

代码生成器是什么

最近做项目写了一个代码生成器,现在就分享出来给大家,顺便说一下代码生成器是什么东西!

1.什么是代码生成器

代码生成器顾名思义就是一个生成代码的软件。为了节省成本,在日常的企业开发中,代码生成器使用比较普遍。

2.代码生成器的原理

代码生成器的原理就是: 根据模板+ 数据生成不同文件 。比如以下的两段代码。

1.ItripHotelOrderMapper 文件

2.ItripHotelOrderMapper 文件

在上述 ItripHotelOrderMapper 和 ItripHotelOrderMapper 文件中,我们注意到,两个文件的代码很相似。除了高亮部分不一致以外,其它的代码均一致。因此,我们可以设想,我们能不能编写模板生成这样的 Mapper 类。高亮部分使用占位符来进行代替,具体内容根据具体数据进行置换

3. 代码生成器三要素

了解了代码生成器的概念和原理,接下来我开始着手编写属于自己的代码生成器。我将代码生成器的分为三部分:
   ➢ 模板:生成文件的模板文件。
   ➢ 数据:生成文件所需要的关键数据。
   ➢ 合成机制:使用数据置换模板中的占位符,生成新的文件的机制。

 

话不多说,给大家看下代码

表的vo类:

  1. /**
  2. * 表Vo
  3. */
  4. public class TableVo {
  5. private String className;//帕斯卡风格的类名
  6. private String camelName;//骆驼风格的类名
  7. private String tableName;//下划线风格的表名
  8. private List<ColumnVo> columns = new ArrayList<ColumnVo>();//列集合
  9. }

列的vo类:

  1. /**
  2. * 列Vo类
  3. */
  4. public class ColumnVo {
  5. private String dbName;//数据库列名
  6. private String javaName;//java属性名
  7. private String dbType;//数据库列类型
  8. private String javaType;//java属性类型
  9. private String comm;//注释
  10. private String upperCaseColumnName;//转成帕斯卡之后的名称
  11. }
 

转换Java格式名称的工具类:

  1. /**
  2. * 转换java格式名称的工具类
  3. */
  4. public class JavaNameUtil {
  5. /**
  6. * 下划线风格的命名转换为java骆驼命名法或帕斯卡命名法的名称
  7. * @param underscoreName
  8. * @param isPascal true:帕斯卡,false:骆驼
  9. * @return
  10. */
  11. public static String translate(String underscoreName, boolean isPascal) {
  12. StringBuilder result = new StringBuilder();
  13. if(underscoreName != null && underscoreName.length() > 0) {
  14. boolean flag = false;
  15. //首字母特殊处理,转换成帕斯卡命名法或骆驼命名法的名称
  16. char firstChar = underscoreName.charAt(0);
  17. if(isPascal) {
  18. result.append(Character.toUpperCase(firstChar));
  19. } else {
  20. result.append(firstChar);
  21. }
  22. //第二个之后的所有字符
  23. for(int i = 1; i < underscoreName.length(); i++) {
  24. char ch = underscoreName.charAt(i);
  25. //如果这个字符为下划线,下个字符需要大写处理
  26. if('_' == ch) {
  27. flag = true;
  28. } else {
  29. if(flag) {
  30. result.append(Character.toUpperCase(ch));
  31. flag = false;
  32. } else {
  33. result.append(ch);
  34. }
  35. }
  36. }
  37. }
  38. return result.toString();
  39. }
  40. /**
  41. * 将下划线风格的命名直接转换为骆驼命名法的名称
  42. * @param str
  43. * @return
  44. */
  45. public static String toCamel(String str) {
  46. return translate(str, false);
  47. }
  48. /**
  49. * 将下划线风格的命名直接转换为帕斯卡命名法的名称
  50. * @param str
  51. * @return
  52. */
  53. public static String toPascal(String str) {
  54. return translate(str, true);
  55. }
  56. /**
  57. * 将数据库类型转换成java类型
  58. * @param dbType
  59. * @return
  60. */
  61. public static String dbTypeToJavaType(String dbType) {
  62. String javaType = null;
  63. switch (dbType) {
  64. case "VARCHAR": javaType = "String";break;
  65. case "BIGINT": javaType = "Long";break;
  66. case "INT": javaType = "Integer";break;
  67. case "DATETIME":javaType = "Date";break;
  68. default: javaType = "String";break;
  69. }
  70. return javaType;
  71. }

负责连接数据库、获取表、列的元信息:

  1. /**
  2. * 负责连接数据库、获取表、列的元信息
  3. */
  4. public class MetadataUtil {
  5. private static Connection conn;//连接
  6. private static DatabaseMetaData meta;//数据库员信息
  7. //静态代码加载数据库驱动
  8. static {
  9. try {
  10. Class.forName("com.mysql.jdbc.Driver");
  11. } catch (ClassNotFoundException e) {
  12. e.printStackTrace();
  13. System.out.println("数据库连接失败");
  14. }
  15. }
  16. //打开连接,获取数据库元信息
  17. public static void openConnection() {
  18. try {
  19. if(conn == null || conn.isClosed()) {
  20. conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/数据库名?useUnicode=true",
  21. "账号",
  22. "密码");
  23. meta = conn.getMetaData();//获取数据库的元数据对象
  24. }
  25. } catch (SQLException e) {
  26. e.printStackTrace();
  27. }
  28. }
  29. //关闭连接
  30. public static void closeConnection() {
  31. try {
  32. if(conn != null || !conn.isClosed()) {
  33. conn.isClosed();
  34. }
  35. } catch (SQLException e) {
  36. e.printStackTrace();
  37. }
  38. }
  39. //获取所有表名称
  40. public static String[] getTableNames() {
  41. openConnection();
  42. ResultSet rs = null;
  43. List<String> nameList = new ArrayList<String>();
  44. try {
  45. rs = meta.getTables(null, null, null, new String[] {"TABLE"});
  46. while (rs.next()) {
  47. String tName = rs.getString("TABLE_NAME");
  48. nameList.add(tName);
  49. }
  50. } catch (SQLException e) {
  51. e.printStackTrace();
  52. } finally {
  53. closeConnection();
  54. }
  55. return (String [])nameList.toArray(new String [] {});
  56. }
  57. //获取某个表的列信息
  58. public static List<String []> getTableColumnsInfo(String tableName) throws SQLException {
  59. openConnection();
  60. ResultSet rs = meta.getColumns(null, "%", tableName, "%");
  61. List<String[]> columnInfoList = new ArrayList<String[]>();
  62. while (rs.next()) {
  63. String[] colInfo = new String[3];
  64. colInfo[0] = rs.getString("COLUMN_NAME");
  65. colInfo[1] = rs.getString("REMARKS");
  66. colInfo[2] = rs.getString("TYPE_NAME");
  67. columnInfoList.add(colInfo);
  68. }
  69. closeConnection();
  70. return columnInfoList;
  71. }

代码生成器类:

  1. **
  2. * 代码生成器
  3. */
  4. public class CodeGenerator {
  5. protected Configuration cfg;//Freemarker配置对象
  6. protected Map valueMap;//要填充到模板的数据
  7. protected Template template;//ftl模板对象
  8. protected String savePath;//保存代码的路径
  9. protected List<TableVo> tableList;//表信息对象集合
  10. protected String fileNameSuffix;//生成的文件名后缀
  11. public CodeGenerator(String ftl) throws Exception {
  12. cfg = new Configuration();//Freemarker配置对象
  13. cfg.setClassForTemplateLoading(this.getClass(), "/templates");//设置加载ftl模板的路径
  14. template = cfg.getTemplate(ftl);//加载模板文件
  15. valueMap = new HashMap();
  16. parseMetadata();
  17. }
  18. //获取所有的表信息、列信息,并且转换为对象
  19. public void parseMetadata() throws Exception {
  20. tableList = new ArrayList<TableVo>();
  21. //获取所有表名
  22. String [] tableNameArr = MetadataUtil.getTableNames();
  23. for (String tName : tableNameArr) {
  24. TableVo table= new TableVo();//表对象
  25. //下划线转帕斯卡命名
  26. table.setClassName(JavaNameUtil.toPascal(tName));
  27. table.setTableName(tName);
  28. table.setCamelName(JavaNameUtil.toCamel(tName));
  29. //调用工具类,获取列信息
  30. List<String []> colInfoList = MetadataUtil.getTableColumnsInfo(tName);
  31. for(String[] colInfo : colInfoList) {
  32. String colName = colInfo[0];//列名
  33. String comment = colInfo[1];//列注释
  34. String colType = colInfo[2];//列类型
  35. ColumnVo column = new ColumnVo();
  36. column.setDbName(colName);
  37. column.setDbType(colType);
  38. column.setComm(comment);
  39. column.setJavaName(JavaNameUtil.toCamel(colName));
  40. column.setJavaType(JavaNameUtil.dbTypeToJavaType(colType));
  41. //列名转帕斯卡命名法,用户生成get和set方法命名
  42. column.setUpperCaseColumnName(JavaNameUtil.toPascal(colName));
  43. //将列信息加入表对象的列信息列表中
  44. table.getColumns().add(column);
  45. }
  46. //加入表集合
  47. tableList.add(table);
  48. }
  49. MetadataUtil.closeConnection();//关闭数据库连接
  50. System.out.println("构建元数据成功!\n\n");
  51. }
  52. //抽象生成代码的方法,各子类实现
  53. public void generateCode() throws Exception {
  54. System.out.println("--------------开始生成" + template.getName() + "代码生成器开始生成代码");
  55. OutputStreamWriter writer = null;
  56. for(TableVo table : tableList) {
  57. valueMap.put("table", table);
  58. try {
  59. //生成的每个代码文件,拼接文件名,创建文件写入器
  60. writer = new FileWriter(savePath + "/" + table.getClassName() + fileNameSuffix);
  61. //Freemarker合成数据和模板,输出到代码文件
  62. this.template.process(valueMap, writer);
  63. //清空写入器缓冲
  64. writer.flush();
  65. } catch (TemplateException e) {
  66. e.printStackTrace();
  67. } catch (IOException e) {
  68. e.printStackTrace();
  69. } finally {
  70. try {
  71. writer.close();
  72. } catch (IOException e) {
  73. e.printStackTrace();
  74. }
  75. }
  76. }
  77. System.out.println("根据" + template.getName() + "模板生成代码成功");
  78. }

代码生成器入口类main方法:

  1. public class App {
  2. public static void main(String [] args) throws Exception {
  3. String myProjectPkg = "cn.itrip";
  4. //实体类生成器
  5. CodeGenerator pojoGenerator = new CodeGenerator("pojo.ftl");//设置所用的模板
  6. pojoGenerator.setSavePath("url");//设置生成代码保存的位置
  7. pojoGenerator.setFileNameSuffix(".java");//设置文件后缀名
  8. pojoGenerator.setPackage(myProjectPkg);//项目包名
  9. //mapper接口生成器
  10. CodeGenerator mapperGenerator = new CodeGenerator("mapper.ftl");//设置所用的模板
  11. mapperGenerator.setSavePath("url");//设置生成代码保存的位置
  12. mapperGenerator.setFileNameSuffix("Mapper.java");//设置文件后缀名
  13. mapperGenerator.setPackage(myProjectPkg);//项目包名
  14. //mapper映射文件生成器
  15. CodeGenerator sqlGenerator = new CodeGenerator("sql.ftl");//设置所用的模板
  16. sqlGenerator.setSavePath("url");//设置生成代码保存的位置
  17. sqlGenerator.setFileNameSuffix("Mapper.xml");//设置文件后缀名
  18. sqlGenerator.setPackage(myProjectPkg);//项目包名
  19. try {
  20. //调用代码生成器
  21. pojoGenerator.generateCode();
  22. mapperGenerator.generateCode();
  23. sqlGenerator.generateCode();
  24. } catch (Exception e) {
  25. e.printStackTrace();
  26. }
  27. }

最后在写3个模板文件(pojo、mapper、sql.ftl)然后运行一下App类就可以自动生成代码了

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/954352
推荐阅读
相关标签
  

闽ICP备14008679号