FreeMarker快速入门
1. FreeMarker介绍
1.1 什么是FreeMarker
Apache FreeMarker是一款开源的模板引擎:即一种基于模板和要改变的数据,并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。它不是面向最终用户的,而是一个java类库,是一款程序员可以嵌入他们所开发产品的组件。
模板使用FreeMarker Template Language(FTL)模板语言编写,这是一种简单的专用语言。模板用于展示数据,数据模型用于呈现什么数据。
模板 + 数据模型 = 输出
FreeMarker最初是为在MVC Web应用程序框架中生成HTML页面而创建的,但它并不绑定到servlet、HTML或任何与Web相关的内容。它也可以用于非Web应用环境中。
1.2 FreeMarker特点
- 强大的模板语言
- 多用途且轻量
- 智能的国际化和本地化
- XML处理能力
- 通用的数据模型
1.3 应用场景
- 动态页面:它帮助从开发人员(Java程序员)中分离出网页设计师(HTML设计师)。设计师无需面对模板中的复杂逻辑,在没有程序员来修改或重新编译代码时,也可以修改页面的样式。
- 页面静态化:比较适合运用在访问量大(或页面数据量大),但是数据很少与后台进行交互(即对实时性要求不是很高的)的页面,比如商品网站上的商品详情页等。
- 代码生成器
2. 模板介绍及使用
2.1 模板总体结构
-
文本: 文本会照着原样来输出。
-
插值:${…} 这部分的输出会被计算的值来替换,可以是任意类型
-
FTL标签:<# …>和HTML标签相似,会被freemarker解析。(用户自定义的FTL标签用@代替#)
-
注释: <#-- and -->。FTL注释不会出现在输出中。
其他任何不是FTL标签,插值或注释的内容将被视为静态文本,不会被FreeMarker解析,会原样输出。
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<#-- 注释 -->
<h1>Welcome ${user}!</h1>
<ul>
<#list animals as animal>
<li>${animal.name} for ${animal.price} Euros
</#list>
</ul>
</body>
</html>
注:FTL是区分大小写的。插值仅仅可以在 文本 中使用。
2.2 指令
FTL标签也被称为指令。指令有预定义指令和自定义指令两种。语法与HTML和XML相似。
FreeMarker只关心FTL标签,它只会把HTML看做是文本原样输出,不会解析。FreeMarker会忽略FTL标签中多余的空白标记。
2.2.1 基本指令
-
if指令: 可以有条件地跳过模板的一些片段。
格式为:<#if condition>…</#if>
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>
Welcome ${user}<#if user == "Big Joe">, our beloved leader</#if>!
</h1>
</body>
</html>
此时,告诉FreeMarker,当user和"Big Joe"相同时,our beloved leader 才输出。如果 condition 是false(布尔值),那么介于 <#if condition>和
</#if> 标签中的内容会被略过。
使用<#else>标签可以指定当条件为false时程序索要执行的内容。比如:
<#if animals.python.price < animals.elephant.price>
Pythons are cheaper than elephants today.
<#elseif animals.elephant.price < animals.python.price>
Elephants are cheaper than pythons today.
<#else>
Elephants and pythons cost the same today.
</#if>
-
list指令: 列表显示内容。
格式为:<#list sequence as loopVariable>repeatThis</#list>
repeatThis部分将会在给定的 sequence 遍历时在每一项中重复
<p>We have these animals:
<table border=1>
<#list animals as animal>
<tr><td>${animal.name}<td>${animal.price} Euros
</#list>
</table>
输出:
<p>We have these animals:
<table border=1>
<tr><td>mouse<td>50 Euros
<tr><td>elephant<td>5000 Euros
<tr><td>python<td>4999 Euros
</table>
-
include指令: 在模板中插入其他文件的内容
格式为:<#include “指定文件”>
copyright_footer.html
<hr>
<i>
Copyright (c) 2000 <a href="http://www.acmee.com">Acmee Inc</a>,
<br>
All Rights Reserved.
</i>
<html>
<head>
<title>Test page</title>
</head>
<body>
<h1>Test page</h1>
<p>Blah blah...
<#include "/copyright_footer.html">
</body>
</html>
输出:
<html>
<head>
<title>Test page</title>
</head>
<body>
<h1>Test page</h1>
<p>Blah blah...
<hr>
<i>
Copyright (c) 2000 <a href="http://www.acmee.com">Acmee Inc</a>,
<br>
All Rights Reserved.
</i>
</body>
</html>
更多指令见官方中文文档:http://freemarker.foofun.cn/ref_directives.html
2.2.2 嵌套指令
在页面上也可以多次使用指令,而且指令间也可以很容易地相互嵌套。
<#list animals as animal>
<div<#if animal.protected> class="protected"</#if>>
${animal.name} for ${animal.price} Euros
</div>
</#list>
2.2.3 内建函数
内建函数类似java的方法, 它不是数据模型中的东西,是 FreeMarker 在数值上添加的。使用 ?
(问号)来访问它们。
内建函数应用可以链式操作,比如user?upper_case?html
会先转换用户名到大写形式,之后再进行HTML转义。
2.2.4 处理不存在的变量
FreeMarker 不允许引用不存在的变量,会报错。
不论在哪里引用变量,都可以指定一个默认值来避免变量丢失这种情况, 通过在变量名后面跟着一个 !
和默认值。
<h1>Welcome ${user!"visitor"}!</h1>
2.3 自定义指令
自定义指令可以使用 macro
指令来定义,Java程序员若不想在模板中实现自定义指令,可以使用 freemarker.template.TemplateDirectiveModel
类来扩展
2.3.1 基本内容
宏是有一个变量名的模板片段。可以在模板中使用宏作为自定义指令, 这样就能进行重复性的工作。例如,创建一个宏变量来输出大字号的’‘Hello Joe!’’:
<#macro greet>
<font size="+2">Hello Joe!</font>
</#macro>
macro
指令自身不输出任何内容, 它只是用来创建宏变量,所以就会有一个名为 greet
的变量。在 <#macro greet>
和 </#macro>
之间的内容 (称为 宏定义体) 将会在使用该变量作为指令时执行。宏定义体中可以包含${…}和FTL指令。那么, 就可以这样来使用 greet
:
<@greet></@greet>
如果定义宏时,没使用nested指令,那么嵌套的内容不会被执行。即<@greet>和< /@greet>的内容不会显示。
2.3.2 命名空间
命名空间是使用assgin
和macro
指令创建的变量的集合。
如果想创建可以重复使用的宏,函数和其它变量的集合,通常用术语来说就是引用库。使用多个命名空间是必然的。
创建一个库,my_test.ftl
<#macro copyright date>
<p>Copyright (C) ${date} Julia Smith. All rights reserved.</p>
</#macro>
<#assign mail = "jsmith@acme.com">
在其他位置使用这个模板:
<#import "/my_test.ftl" as my> <#-- the hash called "my" will be the "gate" -->
<@my.copyright date="1999-2002"/>
${my.mail}
输出:
<p>Copyright (C) 1999-2002 Julia Smith. All rights reserved.</p>
jsmith@acme.com
3. 程序开发
3.1 入门案例
import freemarker.template.*;
import java.util.*;
import java.io.*;
public class Test {
public static void main(String[] args) throws Exception {
//1. 创建Configuration实例
//Configuration实例是存储 FreeMarker 应用级设置的核心部分
Configuration cfg = new Configuration(Configuration.getVersion());
//指定模板文件所在路径
cfg.setDirectoryForTemplateLoading(new File("D:/templates"));
//设置模板文件字符集
cfg.setDefaultEncoding("UTF-8");
//2. 创建数据模型
/**
*(root)
* |
* +- user = "Big Joe"
* |
* +- latestProduct
* |
* +- url = "products/greenmouse.html"
* |
* +- name = "green mouse"
*/
Map root = new HashMap();
root.put("user", "Big Joe");
Map latest = new HashMap();
root.put("latestProduct", latest);
latest.put("url", "products/greenmouse.html");
latest.put("name", "green mouse");
//3. 加载模板
//通过读取/where/you/store/templates/test.ftl 文件,之后解析(编译)它。
Template temp = cfg.getTemplate("test.ftl");
//4. 合并模板和数据模型
Writer out = new OutputStreamWriter(System.out);
temp.process(root, out);
o.close();
}
3.2 SpringBoot集成FreeMarker
3.2.1 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
3.2.2 配置
#模板存放路径
spring.freemarker.template-loader-path=classpath:/templates/
spring.freemarker.charset=utf-8
#是否开启缓存
spring.freemarker.cache=false
#是否在与模板合并之前将所有请求属性添加到模型中
spring.freemarker.expose-request-attributes=false
spring.freemarker.expose-session-attributes=false
#模板文件后缀名
spring.freemarker.suffix=.ftl
3.2.3 编写模板
index.ftl
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>${title}</title>
</head>
<body>
<h1>Hello,${name}</h1>
</body>
</html>
3.2.4 填写数据
FreemarkerController.java
@Controller
class FreemarkerController {
@RequestMapping("/index")
public String index(Model model){
model.addAttribute("title","freemarker");
model.addAttribute("name","FreeMarker");
return "index";
}
}
输出效果如图:
想了解更多,参考freemarker中文官方文档:http://freemarker.foofun.cn/