Freemarker代码生成器
前言
FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据,并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具。
代码生成器原理
Freemarker代码生成器主要通过需要生成的template模板放入Freemarker中,然后将页面所需要的数据动态绑定,并放入Map中。使用Freemarker中的模板解析方法template.process();将静态页面的生成在指定的目录中。
代码生成器三要素
- 模板:生成文件的模板文件。
- 数据:生成文件所需要的关键数据。
- 合成机制:使用数据置换模板中的占位符,生成新的文件的机制。
具体过程
- 有后缀为.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);
}