一、装配使用
1、导入依赖
<!--SpringBootFreemarker模板依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
2、在properties里进行配置
##Freemarker配置
##自定义模板文件配置路径默认模板路径在resources/templates下,默认后缀.ftl
##spring.freemarker.template-loader-path=classpath:/web/
spring.freemarker.cache=false
spring.freemarker.charset=UTF-8
spring.freemarker.check-template-location=true
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=true
spring.freemarker.expose-session-attributes=true
spring.freemarker.request-context-attribute=request
spring.freemarker.suffix=.ftl
3、编写controller
package com.tcc.controller;
import java.util.Date;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class TestController {
@RequestMapping("f1")
public String test1(ModelMap map) {
//存值
map.addAttribute("flag", true);
map.addAttribute("date", new Date());
map.addAttribute("a",5.5474);
map.addAttribute("b",18);
map.addAttribute("c",10000);
map.addAttribute("t1","Hello");
map.addAttribute("t2", "world");
map.addAttribute("t3", "hello world");
//跳转页面
return "f1";
}
}
4、在src/main/resource目录下创建文件夹templates存放.ftl后缀的页面
二、内建函数
1、后台传入数据跳转页面
package com.tcc.controller;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class TestController {
/**
* 访问路径:localhost:8080/f1
* @param map
* @return 返回给页面的数据
*/
@RequestMapping("f1")
public String test1(ModelMap map) {
//布尔类型
map.addAttribute("flag", true);
//日期类型
map.addAttribute("date", new Date());
//数字类型
map.addAttribute("a",5.5474);
map.addAttribute("b",18);
map.addAttribute("c",10000);
//字符串
map.addAttribute("t1","Hello");
map.addAttribute("t2", "world");
map.addAttribute("t3", "hello world");
// 空字符串
map.addAttribute("test1", "");
map.addAttribute("test2", null);
//数组类型
String[] st = {"北京","上海","广东","深圳"};
map.addAttribute("st",st);
//集合类型
List<String> cityList = new ArrayList<>();
cityList.add("北京");
cityList.add("上海");
cityList.add("广东");
cityList.add("深圳");
map.addAttribute("cityList",cityList);
//map类型
Map<String,Object> map2 = new HashMap<>();
map2.put("name", "张三");
map2.put("age", 22);
map2.put("sex", "男");
map.addAttribute("map",map2);
//跳转页面
return "f1";
}
}
2、前台获取不同类型的值
- 只列举了一部分方法,更多方法请查看官网:http://freemarker.foofun.cn/ref_builtins_string.html
<!--
注释(查看网页源代码可以看到) 访问路径:localhost:8080/f1
-->
<#--
注释(前端看不到)
-->
<#-- 布尔类型的值不能直接接收,要在后面添加 ?c 或 ?string 或 ?string('yes','no') -->
<h3>布尔值</h3>
${flag?c} <br/>
${flag?string} <br/>
${flag?string("yes","no")} <br/>
<hr/>
<#-- 日期类型的值不能直接接收,要在后面添加 ?date 或 ?time 或 ?datetime 或 ?string('yyyy/MM/dd') -->
<h3>日期</h3>
${date?date} <br/>
${date?time} <br/>
${date?datetime} <br/>
${date?string("yyyy/MM/dd HH:mm:ss")} <br/>
<hr/>
<#--
数字类型的值可以直接接收,也可以转换类型
a:5.5474 b:18 c:10000
-->
<h3>数字</h3>
${a} <br/>
${a?c} <br/> <#-- 转为字符串 -->
${a?floor} <br/> <#-- 返回最近的整数。 如果数字以.5结尾,那么它将进位 -->
${a?round} <br/> <#-- 返回数字的舍掉小数后的整数 (也就是向负无穷舍弃) -->
${a?ceiling} <br/> <#-- 返回数字小数进位后的整数 (也就是向正无穷进位) -->
${c?string.currency} <br/> <#-- 货币类型 -->
${a?string["0.#"]} <br/> <#-- #小数位占位符,几个#代表保留小数点后几位 -->
<hr/>
<#--
字符串内建函数 t1:Hello t2:world t3:hello world
-->
<h3>字符串</h3>
${t1} -- ${t2} <br/>
${t2?cap_first} <br/> <#-- 首字母大写 -->
${t3?capitalize} <br/> <#-- 全部单词首字母大写 -->
${t1?ends_with("o")?c} <br/> <#-- 返回是否这个字符串以参数中指定的子串结尾 返回值为true或false 需要转换 -->
${t1?starts_with("o")?c} <br/> <#-- 返回是否这个字符串以参数中指定的子串开头 返回值为true或false 需要转换 -->
${t3?length} <br/> <#-- 字符串中字符的数量。 -->
${t1?lower_case} <br/> <#-- 全部小写。 -->
${t1?upper_case} <br/> <#-- 全部大写。 -->
<hr/>
<h3>空字符串[特殊]</h3>
<#--
test1:"" test2:null
test1不报错,test2报错
解决办法:在后面加上[!] 或 [!"为空时候的默认值"]
-->
${test1}
${test2!}
${test2!"yes"} <br/>
${test2!1} <br/>
<hr/>
<#--
序列内建函数:数组(st)、集合(list)、map(map)
-->
<h3>数组</h3>
${st?join(", ")} <br/> <#-- 使用给定的分隔符来连接序列中的项为一个独立的字符串 -->
${st?first} <br/> <#-- 获取第一个值 -->
${st?last} <br/> <#-- 获取最后一个值 -->
<#--
序列中子变量的数量(作为数字值)。
假设序列中至少有一个子变量, 那么序列 s 中最大的索引是 s?size - 1
(因为第一个子变量的序列是0)。
-->
${st?size} <br/>
<#-- 辨别序列中是否包含指定值。它包含一个参数,就是来查找的值。 -->
${st?seq_contains("北京")?string("yes","no")} <br/>
<#list st?reverse as s> <#-- 序列的反序形式。 -->
${s}
</#list>
<br/>
<#--
以升序方式返回序列。(要使用降序排列时,使用它之后使用 reverse 内建函数。)
这仅在子变量都是字符串时有效,或者子变量都是数字,
或者子变量都是日期值 (日期,时间,或日期+时间),
或者所有子变量都是布尔值时(从2.3.17版本开始)。
如果子变量是字符串,它使用本地化(语言)的具体单词排序(通常是大小写不敏感的)。
-->
<#list st?sort as s>
${s}
</#list>
<br/>
<#-- 降序输出 -->
<#list st?sort?reverse as s>
${s}
</#list>
<hr/>
<h3>集合</h3>
<#-- 可用方法和上面举例一样 -->
${cityList?join(", ")} <br/>
${cityList?size} <br/>
<#list cityList as ct>
${ct}
</#list>
<br/>
<#list cityList?sort as ct>
${ct}
</#list>
<hr/>
<h3>Map集合</h3>
<#-- key遍历输出 -->
<#list map?keys as key>
${key} -- ${map[key]} <br/>
</#list>
<br/>
<#-- value遍历输出 -->
<#list map?values as value>
${value} <br/>
</#list>
三、常用指令
1、assign定义变量
1.1、概念
使用该指令你可以创建一个新的变量, 或者替换一个已经存在的变量。注意仅仅顶级变量可以被创建/替换 (也就是说你不能创建/替换 some_hash.subvar
, 除了 some_hash
)。
1.2、使用
-
变量
seq
存储一个序列: -
<#assign seq = ["foo","bar","baz"]> <#-- 创建变量 --> ${seq?join(", ")} <#-- 遍历变量 -->
-
一次定义多个变量
-
<#assign seq = ["foo", "bar", "baz"] x++ >
-
-
变量中插入变量
-
<#assign z = "张${username}">
-
2、if,else,elseif
2.1、概念
相当于java中的if,else结构, if
中可以包含任意数量的 elseif
(包括0个) 而且结束时 else
是可选的
2.2、用法一
-
只有
if
没有elseif
和else
:<#if x == 1> x is 1 </#if>
-
只有
if
没有elseif
但是有else
:
<#if x == 1>
x is 1
<#else>
x is not 1
</#if>
- 有
if
和两个elseif
但是没有else
:
<#if x == 1>
x is 1
<#elseif x == 2>
x is 2
<#elseif x == 3>
x is 3
</#if>
- 有
if
和三个elseif
还有else
:
<#if x == 1>
x is 1
<#elseif x == 2>
x is 2
<#elseif x == 3>
x is 3
<#elseif x == 4>
x is 4
<#else>
x is not 1 nor 2 nor 3 nor 4
</#if>
- 也可以嵌套
if
指令:
<#if x == 1>
x is 1
<#if y == 1>
and y is 1 too
<#else>
but y is not
</#if>
<#else>
x is not 1
<#if y < 0>
and y is less than 0
</#if>
</#if>
-
测试:
<#assign score = 80> <#if score lt 60> <h5>不及格</h5> <#elseif score = 60> <h5>不多不少刚刚好</h5> <#elseif score gt 60 && score lt 80> <h5>革命尚未成功,同志仍需努力</h5> <#else> <h5>考的不错呦</h5> </#if>
-
注意: 当你想测试是否
x > 0
或x >= 0
,编写<#if x > 0>
和<#if x >= 0>
是错误的, 因为第一个>
会结束#if
标签。要这么来做,可以编写<#if x gt 0>
或<#if gte 0>
。也请注意,如果比较发生在括号内部,那么就没有这样的问题, 比如<#if foo.bar(x > 0)>
就会得到想要的结果。
2.3、用法二
-
根据变量有无值显示内容。
-
测试:
<#-- 有值 --> <#assign a = ""> <#if a??> <h5>a有值</h5> <#else> <h5>a没有值</h5> </#if> <#-- 无值 --> <#if a1??> <h5>a1有值</h5> <#else> <h5>a1没有值</h5> </#if>
-
结果:
3、list,else
遍历数组或集合或map。
-
使用:
<#-- 数组有值 --> <#assign num = [1,2,3,5,4]> <#list num as n> ${n} </#list> <#-- 数组无值 --> <#assign num1 = []> <#list num1 as n> ${n} <#else> <h5>该集合无值</h5> </#list>
-
结果:
4、macro自定义指令
4.1、概念
宏变量存储模板片段(称为宏定义体)可以被用作 自定义指令。 这个变量也存储自定义指令的被允许的参数名。当你将这个变量作为指令时, 你必须给所有参数赋值,除了有默认值的参数。 默认值当且仅当你调用宏而不给参数赋值时起作用。
4.2、写法
<#macro name param1 param2 ... paramN>
...
<#nested loopvar1, loopvar2, ..., loopvarN>
...
<#return>
...
</#macro>
name
: 宏变量的名称,它不是表达式。和 顶层变量 的语法相同,比如myMacro
或my\-macro
。 然而,它可以被写成字符串的形式,如果宏名称中包含保留字符时,这是很有用的, 比如<#macro "foo~bar">...
。 注意这个字符串没有扩展插值(如"${foo}"
)。param1
,param2
,等…: 局部变量 的名称,存储参数的值 (不是表达式),在=
号后面和默认值(是表达式)是可选的。 默认值也可以是另外一个参数,比如<#macro section title label=title>
。参数名称和 顶层变量 的语法相同,所以有相同的特性和限制。paramN
, 最后一个参数,可能会有三个点(...
), 这就意味着宏接受可变数量的参数,不匹配其它参数的参数可以作为最后一个参数 (也被称作笼统参数)。当宏被命名参数调用,paramN
将会是包含宏的所有未声明的键/值对的哈希表。当宏被位置参数调用,paramN
将是额外参数的序列。 (在宏内部,要查找参数,可以使用myCatchAllParam?is_sequence
。)loopvar1
,loopvar2
等…: 可选的,循环变量 的值, 是nested
指令想为嵌套内容创建的。这些都是表达式。
return
和 nested
指令是可选的,而且可以在 <#macro ...>
和 </#macro> 之间被用在任意位置和任意次数。
没有默认值的参数必须在有默认值参数 (paramName=defaultValue
) 之前。
4.3、用法
-
创建简单的自定义指令
<#-- 简单的自定义指令 --> <#macro test> This is Test </#macro> <#-- 调用指令 --> <@test/>
-
结果:
-
-
乘法表(自定义指令中包含内置指令)
<#-- 乘法表(自定义指令中包含内置指令) --> <#macro cfb> <#list 1..9 as i> <#list 1..i as j> ${i} * ${j} = ${i*j} </#list> <br/> </#list> </#macro> <@cfb/>
-
结果:
-
-
可以传参的乘法表
<#-- 可以传参的乘法表 --> <#macro cfb02 num> <#list 1..num as i> <#list 1..i as j> ${i} * ${j} = ${i*j} </#list> <br/> </#list> </#macro> <#-- 5,5乘法表 --> <@cfb02 num=5/>
-
结果:
-
-
有参数和默认值参数的宏
<#-- 有参数和默认值参数的宏 --> <#macro cfb02 num=9> <#list 1..num as i> <#list 1..i as j> ${i} * ${j} = ${i*j} </#list> <br/> </#list> </#macro> <#-- 5,5乘法表 --> <@cfb02 num=5/> <#-- 9,9乘法表,默认num=9 --> <@cfb02/>
-
结果:
-
4.4、nested占位符
nested
指令执行自定义指令开始和结束标签中间的模板片段。 嵌套的片段可以包含模板中任意合法的内容:插值,指令等…它在上下文环境中被执行, 也就是宏被调用的地方,而不是宏定义体的上下文中。因此,比如, 你不能看到嵌套部分的宏的局部变量。如果你没有调用 nested
指令, 自定义指令开始和结束标记中的部分将会被忽略。
使用
-
<#-- nested占位符 --> <#macro test> This is Test <#nested> </#macro> <#-- 调用指令 --> <@test>xxxx</@test>
-
结果:
-
4.5、注意
-
变量会在模板开始时被创建;而不管
macro
指令放置在模板的什么位置。所以这样也可以:<#-- 调用指令 --> <@test/> <#-- 简单的自定义指令 --> <#macro test> This is Test </#macro>
-
如果宏定义被插在
include
指令中, 它们直到 FreeMarker 执行include
指令时才会可用。
5、import
5.1、概念
引入一个库。也就是说,它创建一个新的空命名空间, 然后在那个命名空间中执行给定 path
参数中的模板, 所以模板用变量(宏,函数等)填充命名空间。 然后使得新创建的命名空间对哈希表的调用者可用。 这个哈希表变量将会在命名空间中,由 import
(就像你可以用 assign
指令来创建一样。) 的调用者被创建成一个普通变量,名字就是 hash
参数给定的。
5.2、写法
<#import path as hash>
path
:模板的路径。 这是一个算作是字符串的表达式。(换句话说,它不是一个固定的字符串, 它可以是这样的一些东西,比如,profile.baseDir + "/menu.ftl"
。)hash
: 访问命名空间的哈希表变量不带引号的名字。不是表达式。 (如果要引入动态创建的名字,那么就不得不使用 这个技巧。)
5.3、用法
-
在controller写跳转
f3.ftl
页面的请求路径@RequestMapping("f3") public String test2(ModelMap map) { return "f3"; }
-
创建commons.ftl用于存放公共的自定义指令
-
在测试页面中调用公共指令
<#import "commons.ftl" as cm> <br/> <@cm.test/> <br/> <@cm.cfb/> <br/> <@cm.cfb02 num=8/>
-
结果:
-
6、include包含
6.1、概念
你可以使用它在你的模板中插入另外一个 FreeMarker 模板文件 (由 path
参数指定)。 被包含模板的输出格式是在 include
标签出现的位置插入的。 被包含的文件和包含它的模板共享变量,就像是被复制粘贴进去的一样。 include
指令不能由被包含文件的内容所替代, 它只是当 FreeMarker 每次在模板处理期间到达 include
指令时处理被包含的文件。所以对于如果 include
在 list
循环之中的例子, 你可以为每个循环周期内指定不同的文件名。
6.2、写法
<#include path>
或
<#include path options>
path
: 要包含文件的路径;一个算作是字符串的表达式。(用其他话说, 它不用是一个固定的字符串,它也可以是像profile.baseDir + "/menu.ftl"
这样的东西。)options
: 一个或多个这样的选项:encoding=encoding
,parse=parse
encoding
: 算作是字符串的表达式parse
: 算作是布尔值的表达式(为了向下兼容,也接受一部分字符串值)ignore_missing
: 算作是布尔值的表达式
6.3、用法
-
创建
.ftl、.html、.txt
文件,里面输入任意内容。 -
在测试页面输入指令测试
<#-- 引用test.txt里面的内容 --> <#include "test.txt"> <br/> <#-- 引用test.html里面的内容 --> <#include "test.html"> <br/> <#-- 引用test.ftl里面的内容 --> <#include "test.ftl"> <br/>
-
结果:
具体使用请查看官方文档:FreeMarker官方文档。
-