Freemarker代码生成器

       前言

        FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据,并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具。


代码生成器原理

        Freemarker代码生成器主要通过需要生成的template模板放入Freemarker中,然后将页面所需要的数据动态绑定,并放入Map中。使用Freemarker中的模板解析方法template.process();将静态页面的生成在指定的目录中。

官方网址

upload successful

  • 代码生成器三要素

    • 模板:生成文件的模板文件。
    • 数据:生成文件所需要的关键数据。
    • 合成机制:使用数据置换模板中的占位符,生成新的文件的机制。
  • 具体过程

    • 有后缀为.fld的模板文件
    • 创建一个Configuration对象
    • 设置模板文件所在路径
    • 设置模板文件所使用的字符集
    • 根据路径加载模板文件,创建模板对象
    • 创建数据集对象,并向对象填充数据
    • 创建输出流对象Writer(此步骤是设置输出的文件所在的路径及其名字)
    • 调用模板对象的process方法输出(生成)HTML文件或其他文件
    • 关闭流对象
    • 关闭流对象

Freemarker使用

        最简单的模板是纯HTML文件(或其他文本文件; FreeMarker不限于HTML)。当客户端访问该页面时,FreeMarker会将HTML照原样发送给客户端。但是,如果您希望该页面更具动态性,则可以开始将特殊部分放入HTML中,FreeMarker可以理解这些特殊部分

  • ${…}:FreeMarker将在输出中将其替换为大括号内表达式的实际值。它们被称为 插值。

  • FTL标记(用于FreeMarker模板语言标记):FTL标记与HTML标记有点相似,但是它们是FreeMarker的说明,不会打印到输出中。这些标记的名称以开头 #。(用户定义的FTL标签使用 @代替#,但它们是高级主题。)

  • 注释:注释与HTML注释相似,但由<#–和分隔 –>。与HTML注释不同,FTL注释不会进入输出(访问者的页面源中将不可见),因为FreeMarker会跳过它们。


Freemarker一些基本指令
  • if指令

    //示例1
    <#if user ==“ Big Joe”>
        我们心爱的领袖1
    </#if>
    
    //示例2
    <#if user ==“ Big Joe”>
        我们心爱的领袖1
    <#elseif user ==“My Bie”>
        我们心爱的领袖2
    <#else>
        我们心爱的领袖3
    </#if>
  • list指令

    <#list userlist as user> 
        <tr> 
          <td> $ { user .name} </td>
          <td> $ { user .price} </td>
         </tr>
      </#list> 

Freemarker示例代码
  • 导入Freemarker依赖

     <dependency>
        <groupId>com.quhaodian</groupId>
        <artifactId>freemarker</artifactId>
        <version>1.8.1</version>
    </dependency>
  • 打开连接加载数据库驱动通过DatabaseMetaData类获得数据库中的表

    DatabaseMetaData meta = conn.getMetaData();
    List<String> nameList = new ArrayList<String>();
    //表目录、表模式、表名、表类型
    //conn.getCatalog()获得连接的数据库
    //通过getTables方法获得,不指定数据库则获得所有的表信息
    ResultSet rs = meta.getTables(conn.getCatalog(),null,new String[]{"TABLE"});
       //通过循环得到所有表的名称存入集合
    while (rs.next()){
         String tName = rs.getString("TABLE_NAME");
         nameList.add(tName);
    }
    //返回一个数组
    return nameList.toArray(new String[]{});
  • 通过DatabaseMetaData类获得数据库中每张表的列

    //通过表名称将所有列存入rs中
    //类别名称、模式名称、表名称、列名称
    ResultSet rs = meta.getColumns(null,"%",tableName,"%");
    List<String[]> columnsInfoList = new ArrayList<String[]>();
    //循环存入创建实体类需要的一些字段
    while (rs.next()){
        String[] colInfo = new String[3];
        //列名、注释、数据库类型
        colInfo[0] = rs.getString("COLUMN_NAME");
        colInfo[1] = rs.getString("REMARKS");
        colInfo[2] = rs.getString("TYPE_NAME");
        columnsInfoList.add(colInfo);
    }
    return columnsInfoList;
  • 模板示例pojo.ftl

    package ${package}.pojo;
    
    import java.io.Serializable;
    import java.util.Date;
    
    public class ${table.className} implements Serializable{
    
        //生成私有属性
        <#list table.columns as col>
            //${col.comment}
            private ${col.javaType} ${col.fieldName};
        </#list>
    
        //生成getter方法
        <#list table.columns as col>
            public void set${col.upperCaseColumnName}(${col.javaType} ${col.fieldName}){
                this.${col.fieldName} = ${col.fieldName};
            }
            public ${col.javaType} get${col.upperCaseColumnName}(){
                return ${col.fieldName};
            }
        </#list>
    }
  • 创建Configuration对象

    //得到最新的Configuration对象
    Configuration cfg = new Configuration(Configuration.getVersion());
  • 设置模板文件所在路径

     加载模板文件路径的三种方式
    //1.类路径加载,直接加载resources文件夹下cfg.setClassForTemplateLoading(this.getClass(),"/flt");
    //2.文件的绝对路径加载cfg.setDirectoryForTemplateLoading("src/main/resources/flt");
    //3.基于WEB服务器的路径加载cfg.setServletContextForTemplateLoading("file/resources/flt");
  • 设置模板文件所在路径

    Template template = cfg.getTemplate("pojo.ftl");
  • 设置模板文件所使用的字符集

    cfg.setDefaultEncoding("utf-8");
    //用于存储赋值在模板中的参数
    valueMap = new HashMap();
  • 编辑转换的工具类:帕斯卡、骆驼、数据类型

  • 获取所有表信息、列信息、转换对象

      //获取所有表名
    String [] tableNameArr = MetadataUtil.getTableNames();
    //建立表对象、存储数据库表名、转换后的表名(大小写类名)、注释、列集合
    TableVo table = new TableVo();
      //通过循环每张表获取列名、
      List<String[]> colInfoList=MetadataUtil.getTableColumnsInfo(tName);
     //建立列对象、存储数据库列名、转换后的列名(Java属性名)、注释、数据库中类型、java类型
       ColumnVo column = new ColumnVo();
     //存入表对象
     table.getColumns().add(column);
  • 创建输出流对象Writer,调用模板对象的process方法输出(生成)HTML文件或其他文件

  //生成代码的方法,各子类的实现
  public void generateCode() {
      System.out.println("------开始生成"+template.getName()+"代码-----");
      OutputStreamWriter writer = null;
      //循环每个表对象生成代码
      for (TableVo table:tableVoList) {
          valueMap.put("table",table);
          //生成每个代码文件,拼接文件名,创建一个文件写入器
         try{
             writer = new FileWriter
                     (savePath+"/"+table.getClassName()+ fileNameSuffix);
             //Freemarker合成数据和模板,输出到代码文件
             this.template.process(valueMap,writer);
             writer.flush();
         }catch (TemplateException e){
             e.printStackTrace();
         }catch (IOException e){
             e.printStackTrace();
         }finally {
             try {
                 writer.close();
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }
      }
      System.out.println("根据"+template.getName()+"模板生成代码成功!\n\n");
  }

  //包路径的set方法
  public void setPackage(String packg){
    this.valueMap.put("package",packg);
}