FreeMarker
FreeMarker
模板引擎,视图的模板是固定的,将模板中的数据修改后返回
模板 + 数据模型 = 输出
Hello World
SpringBoot整合FreeMarker
导包
1
2
3
4
5
6
7
8
9<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13spring:
freemarker:
charset: UTF-8
# 指定模板文件后缀 freemarker template langurage
suffix: .ftl
# 指定模板所在路径
template-loader-path: classpath:/templates
cache: false
allow-request-override: false
check-template-location: true
content-type: text/html
expose-request-attributes: true
expose-session-attributes: true编写Controller
1
2
3
4
5
6
7
8
9
10
11
12
13@Controller
public class HelloController {
@GetMapping("/hello")
public String hello(Model model) {
HashMap<String, Object> map = new HashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
model.addAttribute("myMap", map);
model.addAttribute("name", "World");
return "hello";
}
}在
resources/templates
下编写模板hello.ftl
1
2
3
4
5
6
7
8
9
10
11<!DOCTYPE html>
<html>
<head>
<title>Hello FreeMarker</title>
</head>
<body>
<h1>Hello ${name}!</h1>
<p>Value for key1: ${myMap["key1"]}</p>
<p>Value for key2: ${myMap["key2"]}</p>
</body>
</html>
运行,访问
localhost:8080/hello
单独使用
导包、配置
编写模板
welcome.ftl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<!DOCTYPE html>
<html>
<head>
<title>Welcome</title>
</head>
<body>
<h1>Welcome ${name}!</h1>
<p>Today is ${date?string("yyyy-MM-dd")}</p>
<ul>
<#list items as item>
<li>${item}</li>
</#list>
</ul>
</body>
</html>使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public class FmTest {
@Test
public void test() throws Exception {
Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
// 设置模板所在路径和编码
cfg.setClassLoaderForTemplateLoading(getClass().getClassLoader(), "/templates/");
cfg.setDefaultEncoding("UTF-8");
Map<String, Object> data = new HashMap<>();
data.put("name", "John");
data.put("date", new Date());
data.put("items", Arrays.asList("Apple", "Banana", "Orange"));
// 获取模板
Template template = cfg.getTemplate("welcome.ftl");
Writer out = new StringWriter();
// 给数据渲染模板,输出到writer中
template.process(data, out);
String rendered = out.toString();
System.out.println(rendered);
}
}
语法
插值/表达式
使用${..}
来引入变量,如:${name}
字符串
\
需要转义,或者在字符串前面加r
1 |
|
字符串拼接
1 |
|
字符串截取
1 |
|
数字
以钱的形式展示
1
2<#assign num=99>
<div>${num?string.currency}</div>百分数
1
<div>${num?string.percent}</div>
布尔
1 |
|
集合
直接定义然后输出
1
2
3<#list ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"] as x>
${x}<br/>
</#list>集合的元素可以是表达式、map
1
2
3
4
5
6
7
8
9
10<#list [2+2,"javaboy"] as x>
${x} <br/>
</#list>
<#list {"a":"a","b":"b"}?keys as x>
${x}
</#list>
<#list {"a":"a","b":"b"}?values as x>
${x}
</#list>
运算符
算数运算
= 或者 == 判断两个值是否相等。
!= 判断两个值是否不等。
>
或者 gt 判断左边值是否大于右边值。>=
或者 gte 判断左边值是否大于等于右边值。<
或者 lt 判断左边值是否小于右边值。<=
或者 lte 判断左边值是否小于等于右边值。1
2
3
4
5
6
7
8
9
10<div>
<#assign age=99>
<#if age=99>age=99</#if>
<#if age gt 99>age gt 99</#if>
<#if age gte 99>age gte 99</#if>
<#if age lt 99>age lt 99</#if>
<#if age lte 99>age lte 99</#if>
<#if age!=99>age!=99</#if>
<#if age==99>age==99</#if>
</div>
逻辑运算
逻辑与
&&
逻辑或
||
逻辑非
!
1
2
3
4
5
6<div>
<#assign age=99>
<#if age=99 && 1==1> age=99 && 1==1 </#if>
<#if age=99 || 1==0> age=99 || 1==0 </#if>
<#if !(age gt 99)> !(age gt 99) </#if>
</div>
空值处理
!
指定空值的默认值,后面不写东西则为空字符串??
判断某个变量是否存在1
2
3
4
5<div> ${aaa!"bbb"} </div>
<div> ${aaa!} </div>
<div>
<#if aaa??> bbb </#if>
</div>
变量
通过Model传值
1 |
|
1 |
|
内置函数和指令
常见内置函数
string函数:将一个非字符串值转换为字符串
number函数:将一个字符串或其他类型的值转换为数字
size函数:返回一个序列(如列表、数组、字符串等)的大小
1
<div>${users?size}</div>
default函数:返回第一个非空值
length函数:返回字符串的长度
upper_case函数:将字符串转换为大写形式
1
<div>${"hello"?upper_case}</div>
lower_case函数:将字符串转换为小写形式
1
<div>${"HELLO"?lower_case}</div>
cap_first函数:首字母大写
1
<div>${"hello"?cap_first}</div>
trim:去掉前后空格
1
<div>${" hello "?trim}</div>
日期转换
1
<div>${birthday?string("yyyy-MM-dd")}</div>
常见内置指令
#if指令:用于条件判断,根据条件判断结果执行相应的操作
1
2
3
4
5
6
7
8<div>
<#assign age=23>
<#if (age>60)>老年人
<#elseif (age>40)>中年人
<#elseif (age>20)>青年人
<#else> 少年人
</#if>
</div>#list指令:用于遍历集合(如数组、列表)并对其中每个元素执行操作
#assign指令:用于给变量赋值
#macro指令:用于定义宏(类似于函数)
1
2
3
4
5
6
7
8
9
10<#macro book bs>
<table border="1">
<#list bs as b>
<tr>
<td>${b}</td>
</tr>
</#list>
</table>
</#macro>
<@book ["三国演义","水浒传"]/>可以使用
<#nested>
作为占位符,调用宏的时候标签里的内容会填充到占位符的位置1
2
3
4
5
6
7
8
9
10
11
12
13<#macro book bs>
<table border="1">
<#list bs as b>
<tr>
<td>${b}</td>
</tr>
</#list>
</table>
<#nested>
</#macro>
<@book ["三国演义","水浒传"]>
<h1>hello javaboy!</h1>
</@book>#include指令:用于在模板中引入其他模板
1
<#include "./about.ftl">
#import指令:导入外部的模板
about.ftl
1
2
3
4
5
6
7
8
9
10<#macro book bs>
<table border="1">
<#list bs as b>
<tr>
<td>${b}</td>
</tr>
</#list>
</table>
<#nested>
</#macro>hello.ftl
1
2
3
4
5<#import "./about.ftl" as about>
<@about.book ["三国演义","水浒传"]>
<h1>hello javaboy!</h1>
</@about.book>#noparse指令:框起来的FreeMarker语法不会被渲染
常见内置变量
- .now:返回当前时间
- .size:返回一个序列(如列表、数组、字符串等)的大小
- .length:返回字符串的长度
SpringBoot整合FreeMarker
自动配置
首先导包
1 |
|
在org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration
为FreeMarker的自动配置类
1 |
|
@ConditionalOnClass({Configuration.class, FreeMarkerConfigurationFactory.class})
:当导入FreeMarker后,就会存在
Configuration
和FreeMarkerConfigurationFactory
这两个类,自动配置类也就生效了@Import({FreeMarkerServletWebConfiguration.class,
:剩下的配置在类
FreeMarkerServletWebConfiguration
中1
2
3
4
5
6
7
8
9
10@Configuration(
proxyBeanMethods = false
)
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, FreeMarkerConfigurer.class})
@AutoConfigureAfter({WebMvcAutoConfiguration.class})
class FreeMarkerServletWebConfiguration extends AbstractFreeMarkerConfiguration {
...@ConditionalOnWebApplication(type = Type.SERVLET)
:配置在web环境下生效@AutoConfigureAfter({WebMvcAutoConfiguration.class})
:自动化配置在WebMvcAutoConfiguration之后完成这个配置类主要提供了
Configuration
和freeMarkerViewResolver
。Configuration
有一些基本配置,如编码、模板所在位置等;freeMarkerViewResolver
是视图解析器,配置有后缀等属性这个配置类的构造方法注入了
FreeMarkerProperties
,里面有一些默认的配置信息1
2
3
4
5
6
7
8public class FreeMarkerProperties extends AbstractTemplateViewResolverProperties {
public static final String DEFAULT_TEMPLATE_LOADER_PATH = "classpath:/templates/";
public static final String DEFAULT_PREFIX = "";
public static final String DEFAULT_SUFFIX = ".ftlh";
private Map<String, String> settings = new HashMap();
private String[] templateLoaderPath = new String[]{"classpath:/templates/"};
private boolean preferFileSystemAccess;
...
主要配置
1 |
|
使用
创建User类
1 |
|
创建UserController
1 |
|
创建index.ftl视图
1 |
|
运行,访问localhost:8080/index
静态输出文件
步骤:
- 指定模板文件
- 准备数据
- 将数据和模板结合,输出
1 |
|
1 |
|