1、freemarker是什么,主要功能是什么?
FreeMarker 是一款模板引擎,即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。这是官方的解释,我个人的理解是,freemarker是一个模板引擎工具,我们先用特定语言定义好模板文本并预留好参数位置,然后动态传入参数。这样freemarker就能动态的根据输入的参数返回不同的文本数据。所以它的功能简单理解是根据模板和数据动态生成文本。
2、freemarker功能构成
freemarker主要由模板模型和数据模型组成,模板模型一般是用符合FreeMarker Template Language编写的文本文件,或者在程序中动态生成对应的文本字符串也行。直接生成文本字符串虽然更灵活,但是却没有编写文本文件直观。数据模型一般则是指符合freemarker规范类型的参数数据。freemarker运行的时候会将该参数数据对应的替换到模板模型文件的占位符中。
由此可知freemarker的核心便是模板模型和数据模型。由于模板模型是一个文本(也可以是字符串),所以它有对应的语言和语法规则,如if、list、include等的使用。初次使用前尽量先大致了解下freemarker的语言规则,然后再随用随查。数据模型则是指模板模型中可动态放置的参数集合。这些放入的数据集合也有一些宽泛的要求和常见的方法,初次使用时也可以先概览,随后再随用随查。
3、动态select sql生成demo
3.1)首先加入依赖
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
3.2)其次编辑模板模型文件(文件名称是IndicatorProdSql.sql)
select ${express}
from ${modelName}
<#if joinList??>
<#list joinList as joinObj>
${joinObj.type} ${joinObj.modelName} on ${joinObj.criteria}
</#list>
</#if>
<#if whereList??>
where 1=1
<#list whereList as whereObj>
${whereObj.type} ${whereObj.criteria}
</#list>
</#if>
<#if groupList??>
group by
<#list groupList as criteria>
${criteria}<#if criteria_has_next>, </#if>
</#list>
</#if>
<#if orderList??>
order by
<#list orderList as criteria>
${criteria}<#if criteria_has_next>, </#if>
</#list>
</#if>
模型文件不限制文件名和类型,只要内部文本符合freemarker语言规则即可。
3.3)基础代码
/************************************* 数据模型 ************************************/
public class FreemarkerSqlBean {
public String express;
public String modelName;
public List<FreemarkerSqlJoin> joinList;
public List<FreemarkerSqlWhere> whereList;
public List<String> groupList;
public List<String> orderList;
}
public class FreemarkerSqlJoin {
public String type;
public String modelName;
public String criteria;
}
public class FreemarkerSqlWhere {
public String type;
public String criteria;
}
/************************************* 基础代码 ************************************/
public class FreemarkerDemo{
public final static int[] FREEMARKERVERSION = new int[]{2,3,31};
public final static String FREEMARKERSQLFILE = "IndicatorProdSql.sql";
public String getSql(FreemarkerSqlBean bean) throws Exception {
// 第一步:创建一个Configuration对象,直接new一个对象。构造方法的参数就是freemarker对于的版本号。
Configuration configuration = new Configuration(new Version(Constant.FREEMARKERVERSION[0], Constant.FREEMARKERVERSION[1], Constant.FREEMARKERVERSION[2]));
// 第二步:设置模板文件所在的路径。
String rootPath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
configuration.setDirectoryForTemplateLoading(new File(rootPath));
// 第三步:设置模板文件使用的字符集。一般就是utf-8.
configuration.setDefaultEncoding("utf-8");
// 第四步:加载一个模板,创建一个模板对象。
Template template = configuration.getTemplate(Constant.FREEMARKERSQLFILE);
// 第五步:创建一个模板使用的数据集,可以是pojo也可以是map。一般是Map。这里由方法输入
// 第六步:创建一个Writer对象,一般创建FileWriter对象,指定生成的文件名。也可以将生成的文本放入内存中
//Writer out = new FileWriter(new File("E:\\wyt01web\\src\\main\\resources\\table_ddl_create.sql"));
String sql = null;
try (Writer out = new StringWriter();) {
// 第七步:调用模板对象的process方法输出文件。
template.process(bean, out);
sql = ((StringWriter) out).getBuffer().toString();
} catch (Exception e) {
logger.error("请求信息{},异常信息:",JSONObject.toJSONString(bean),e);
}
return sql;
}
}
上面代码有几处可以留意下,不止这一个demo中可以用:
3.3.1)第二步获取resource路径
String rootPath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
3.3.2)第六步try-resource使用,不用再管理流的关闭
try (Writer out = new StringWriter();) {
} catch (Exception e) {
}
3.3.3)使用不同的Write实现类,输出文件或者字符串
输出文件:Writer out = new FileWriter(new File("E:\\wyt01web\\src\\main\\resources\\table_ddl_create.sql"));
输出字符串:Writer out = new StringWriter()
3.3.4)换行符和空格调整
直接输出字符串时,可能会遇到字符串中有换行符或者空格太多的情况,此时可以用如下方式进行去除换行符以及去除多余的空格
sql.replaceAll("\\r\\n"," ").replaceAll("\\s+"," ")
3.3.5)日志打印占位符以及打印完整错误信息
logger.error("请求信息{},异常信息:",JSONObject.toJSONString(bean),e);
即用大括号{}进行占位,然后在后面追加参数,如果有多个参数就用逗号隔开,且可以插入多个占位符。另外打印异常信息时不用加占位符,直接加e就可以在本行日志末尾输出完整的异常信息。
4、扩展使用
目前是根据mysql类型的语法编辑的sql模板,后期如果使用其它语法类型的查询,比如oracle、mongodb、es等,这个时候可以通过新增sql模板或者直接使用临时构建模板模型字符串文本方式来解决需求。一般推荐前者,因为比较直观而且操作相对于来说简单不易出错。当然如果对动态性要求比较高,且不是太复杂的文本需求可以使用后者。
参考链接:
http://freemarker.foofun.cn/dgui_quickstart_basics.html
https://www.cnblogs.com/itdragon/p/7750903.html