文章目录
- 创建项目
- 引入依赖
- 创建配置文件
- 创建启动类和测试类
- 语法
- list
- Map
- if
- 运算符
- 处理空值
- 使用`??`
- 指定缺失变量默认值
- 内建函数
- 集合长度
- 数据类型
- 布尔值
- 时间类型
- 数值类型
- 字符串类型
- sequence序列类型
- hash类型
- 常见指令
- assign自定义变量指令
- json转成对象
- 实例
- list通过下标取值
- map取值通过list的对象取
创建项目
引入依赖
创建一个maven项目,然后引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wzw</groupId>
<artifactId>springboot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<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>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
创建配置文件
配置端口号和模板位置,以及跳转的后缀
server:
port: 3031
spring:
freemarker:
cache: false #关闭模板缓存
template-loader-path: classpath:/templates
suffix: .ftl
创建启动类和测试类
实体类
package com.wzw.springboot.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private Integer age;
private String phone;
private String address;
}
启动类
package com.wzw.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}
}
controller类
package com.wzw.springboot.controller;
import com.wzw.springboot.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Map;
/**
* 不要使用RestController,freemarker是需要跳转到对应的ftl,如果使用RestController,就会被转成json,跳转不过去了
*/
@Controller
@RequestMapping("/free")
public class FreemarkerController {
/**
* @param map 这个map最后会响应给用户,ftl中就可以通过这个map取到值
* @return
*/
@RequestMapping("/index")
public String hello(Map<String,Object> map){
map.put("user",new User("张三",10,"13333333333","一号胡同"));
return "hello";
}
}
创建ftl,也就是模板,因为配置文件中配置了它的位置是/templates
下,所以我们放在resources下的templates中
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ftl测试</title>
</head>
<body>
<#-- 获取map中的值-->
hello ${user.name}
</body>
</html>
然后启动测试,成功访问并取到值
语法
注释:
html的注释是<!-- -->
,而freemarker的注释是<#-- -->
,注释中的内容会被freemarker忽略
插值:
freemarker使用${}
插值,用真实值替换${}
,例如${user.name}中的值被map中的值替换
FTL指令:
freemarker会解析标签中的逻辑或表达式
文本:
仅文本信息,直接输出内容
list
数据模型中存值
@RequestMapping("/test1")
public String test1(Map<String,Object> map){
User user1 = new User("张三1", 10, "13333333333", "1号胡同");
User user2 = new User("张三2", 20, "00000000001", "2号胡同");
User user3 = new User("张三3", 30, "000000000022", "3号胡同");
User user4 = new User("张三4", 40, "00000000003", "4号胡同");
List<User> users=new ArrayList<>();
users.add(user3);
users.add(user4);
//list放在数据模型中
map.put("users",users);
HashMap<String, User> userMap=new HashMap<>();
userMap.put("user1",user1);
userMap.put("user2",user2);
//map放在数据模型中
map.put("userMap",userMap);
return "test1";
}
ftl中取值
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>test1</title>
</head>
<body>
遍历数据模型中的list数据(数据模型中key为users)
<table>
<tr>
<td>序号</td>
<td>姓名</td>
<td>年龄</td>
<td>电话</td>
<td>地址</td>
</tr>
<#list users as user>
<tr>
<#-- _index获取下标-->
<td>${user_index}</td>
<td>${user.name}</td>
<td>${user.age}</td>
<td>${user.phone}</td>
<td>${user.address}</td>
</tr>
</#list>
</table>
</body>
</html>
Map
获取数据模型中的userMap
<br/>
第一种方法,在map后 [key]
<br/>
姓名:${userMap['user1'].name}
<br/>
地址:${userMap['user1'].address}
<br/>
第二种方法,map后 .key
<br/>
姓名:${userMap.user2.name}
<br/>
地址:${userMap.user2.address}
<br/>
<hr>
遍历map中的key
<br/>
<#list userMap?keys as key>
${key}
<br/>
</#list>
遍历map中的value
<br/>
<#list userMap?values as value>
${value}
<br/>
</#list>
通过key遍历值,这里只能通过[]的方式
<br/>
<#list userMap?keys as key>
${userMap[key].name}
<br/>
</#list>
if
<#list users as user>
<tr <#if user.age==30>style="color: red"</#if> >
<#-- _index获取下标-->
<td>${user_index}</td>
<td>${user.name}</td>
<td>${user.age}</td>
<td>${user.phone}</td>
<td>${user.address}</td>
</tr>
</#list>
生效了
运算符
- 算术运算符
freemarker中支持算术运算符:+ - * / %
- 逻辑运算符
&&
并且
||
或者
!
非 - 比较运算符
=或==
判断两个值是否相等
!=
判断两个之是否不相等
>或gt
大于
>=或gte
大于等于
<或lt
小于
<=或lte
小于等于
使用大于的比较运算符<#if user.age > 30>
报错
换成<#if user.age gt 30>
或者使用括号包起来<#if (user.age > 30)>
处理空值
不要给users存储值,报错
使用??
取值时候提前判断非空
使用??
,如果存在就是true,如果不存在,就是false
<#if users??>
<#list users as user>
<tr <#if (user.age > 30)>style="color: red"</#if> >
<#-- _index获取下标-->
<td>${user_index}</td>
<td>${user.name}</td>
<td>${user.age}</td>
<td>${user.phone}</td>
<td>${user.address}</td>
</tr>
</#list>
</#if>
判断非空后,因为空值,所以没有输出,但是也没有报错了
使用 ?? 判断字符串是否为空;返回布尔类型。如果想要输出,需要将布尔类型转换成字符串 :
${(name??)?string}<br>
指定缺失变量默认值
如果一个变量不存在或者null,就要报错,使用!
指定一个默认值,如果!
后面没有设置值,就显示空
空值:${dept!}
<br/>
部门:${dept!'123'}
<br/>
部门名称:${(dept.name)!'456'}
内建函数
内建函数语法: 变量 + ? + 函数名
集合长度
users的长度${users?size}
数据类型
- 布尔型:类似Java 的 Boolean 类型,不能直接输出,要转为字符串输出
- 日期型:类似 java 的 Date 类型,不能直接输出,要转为字符串输出
- 数值型:类似 java 中的 int,float,double 等
- 三种显示形式:数值型(默认)、货币型、百分比型
- 字符型:类似java 中的字符串,有很多内置函数
- sequence :类似java 中的数组,list,set 等集合类型
- hash:类似 java 中的 Map
布尔值
controller
//boolean存值
model.put("boolValue",true);
ftl:
<h1>布尔类型</h1>
<#-- 数据类型:布尔类型
freemarker中布尔类型不能直接输出;如果输出要先转成字符串
方式一:?c
方式二:?string 或 ?string("true时的文本","false时的文本")-->
<#-- 直接输出-->
${boolValue?c}<br>
${boolValue?string}<br>
<#-- true显示yes,false显示no-->
${boolValue?string("yes","no")}<br>
时间类型
controller:
//日期存值
model.put("time",new Date());
ftl:
<h1>时间类型</h1>
<#--
数据类型:日期类型
在freemarker中日期类型不能直接输出;如果输出要先转成日期型或字符串
1. 年月日 ?date
2. 时分秒 ?time
3. 年月日时分秒 ?datetime
4. 指定格式 ?string("自定义格式")
y:年 M:月 d:日
H:时 m:分 s:秒
-->
当前时间.now:${.now}
<br/>
年 月 日<br/>${time?date}
<br/>
时 分 秒<br/>${time?time}
<br/>
日期+时间<br/>${time?datetime}
<br/>
自定义格式化:
<br/>
${time?string("yyyy年MM月")}
<br/>
${time?string("yyyy年MM月dd日 HH:mm:ss")}
数值类型
controller:
//数值类型
model.put("money",1546884512f);
model.put("age",10);
model.put("score",99.99);
ftl:
<h1>数值类型</h1>
<#--
数据类型:数值类型
freemarker可以直接输出数值类型
1. 转字符串
普通字符串 ?c
货币型字符串 ?string.currency
百分比型字符串 ?string.percent
2. 保留浮点型数值指定小数位(#表示一个小数位)
?string["0.##"]
-->
直接输出数值型:
${age} <br>
${money} <br>
${score} <br>
数值转字符串输出:
${money?c} <br>
数值转成货币类型的字符串输出:
${money?string.currency} <br>
数值转百分比类型的字符串输出:
${score?string.percent} <br>
浮点型数值保留指定小数位输出 (##表示保留两位小数):
${score?string["0.##"]} <br>
字符串类型
controller
//字符串类型
model.put("name","zhangsan");
model.put("city","hulunbeierdacaoyuan");
ftl:
<h1>字符串类型</h1>
<#--
数据类型:字符串类型
freemarker可以直接输出字符串类型
1. 截取字符串(左闭右开) ?substring(start,end)
2. 首字母小写输出 ?uncap_first
3. 首字母大写输出 ?cap_first
4. 字母转小写输出 ?lower_case
5. 字母转大写输出 ?upper_case
6. 获取字符串长度 ?length
7. 是否以指定字符开头(boolean类型) ?starts_with("xx")?string
8. 是否以指定字符结尾(boolean类型) ?ends_with("xx")?string
9. 获取指定字符的索引 ?index_of("xx")
10. 去除字符串前后空格 ?trim
11. 替换指定字符串 ?replace("xx","xx")
-->
直接输出 :
${name} - ${city} <br>
${name?string} - ${city?string} <br>
1. 截取字符串 ?substring(start,end) 下标0开始截取5个字符串:
${city?substring(0,5)} <br>
2. 首字母小写输出 ?uncap_first :
${name?uncap_first} <br>
3. 首字母大写输出 ?cap_first :
${city?cap_first} <br>
4. 字母转小写输出 ?lower_case :
${name?lower_case} <br>
5. 字母转大写输出 ?upper_case :
${name?upper_case} <br>
6. 获取字符串长度 ?length :
${name?length} <br>
7. 是否以指定字符开头(boolean类型) ?starts_with("z")?string :
${name?starts_with("z")?string} <br>
8. 是否以指定字符结尾(boolean类型) ?ends_with("n")?string :
${name?ends_with("n")?string} <br>
9. 获取指定字符的索引,找不到就是-1 ?index_of("g") :
${name?index_of("g")} <br>
10. 去除字符串前后空格显示字符串的长度 ?trim :
${name?trim?length} <br>
11. 替换指定字符串 ?replace("a","l") :
${name?replace("a","l")}<br>
sequence序列类型
controller:
//序列类型(list、set、数组)
// 数组操作
String[] stars = new String[]{"张三","李四","王五","赵六"};
model.put("names",stars);
// List操作
List<String> citys = Arrays.asList("北京","上海","广州","深圳");
model.put("citys",citys);
// JavaBean集合
List<User> userList = new ArrayList<>();
userList.add(new User("张三1", 10, "13333333333", "1号胡同"));
userList.add(new User("张三2", 20, "23333333333", "2号胡同"));
userList.add(new User("张三3", 30, "33333333333", "3号胡同"));
model.put("users",userList);
ftl:
<h1>序列类型</h1>
<#--
数据类型:序列类型 (数组、List、Set)
通过list指令输出序列
<#list 序列名 as 元素名>
${名称}
</#list>
获取序列长度 ${序列名?size}
获取序列元素下标 ${元素名?index}
获取第一个元素 ${序列名?first}
获取最后一个元素 ${序列名?last}
倒序输出 序列名?reverse
升序输出 序列名?sort
降序输出 序列名?sort?reverse
指定字段名排序 序列名?sort_by("字段名")
-->
<#-- 数组操作 -->
<#list names as name>
下标:${name?index} -- 名字:${name} <br>
</#list>
数组的长度:${names?size} <br>
<#-- 获取第一个元素 -->
第一个元素:${names?first} <br>
<#-- 获取最后一个元素 -->
最后一个元素:${names?last} <br>
<hr>
<#-- List操作 -->
<#list citys as city >
${city} <br>
</#list>
List的size:${citys?size} <br>
<#-- 倒序输出 -->
<#list citys?reverse as city >
${city} -
</#list>
<br>
<#-- 升序输出 -->
<#list citys?sort as city >
${city} -
</#list>
<br>
<#-- 降序输出 -->
<#list citys?sort?reverse as city >
${city} -
</#list>
<hr>
<#-- List<User>集合 -->
<#list users as user>
编号:${user_index}
姓名:${user.name}
年龄:${user.age}
<br>
</#list>
<#-- 按照指定字段名排序 -->
<#list users?sort_by("age") as user>
${user.name} |
</#list>
hash类型
controller:
//hash类型
// Map操作
Map<String,String> userMap = new HashMap<>();
userMap.put("zhangsan","张三");
userMap.put("lisi","李四");
userMap.put("wangwu","王五");
model.put("userMap",userMap);
ftl:
<h1>hash类型</h1>
<#--
数据类型:hash类型
key遍历输出
<#list hash?keys as key>
${key} -- ${hash[key]}
</#list>
value遍历输出
<#list hash?values as value>
${value}
</#list>
-->
<#-- key遍历输出 -->
<#list userMap?keys as key>
${key} -- ${userMap[key]} <br>
</#list>
<#-- value遍历输出 -->
<#list userMap?values as value>
${value} |
</#list>
常见指令
assign自定义变量指令
<h1>assign指令</h1>
<#--
assign 自定义变量指令
语法:
<#assign 变量名=值>
<#assign 变量名=值 变量名=值> (定义多个变量可以用空格隔开)
-->
<#assign str="hello">
${str} <br>
<#assign num=1 names=["zhangsan","lisi","wangwu"] >
通过逗号分割数组,变成字符串:
${num} -- ${names?join(",")}
json转成对象
assign
标签,作用是定义一个变量
实例
list通过下标取值
names和depts都是list
<#list depts as dept>
//当前下标
<td>${dept_index}</td>
//获取当前下标的,dept中的name值
<td>${dept.name的值}</td>
//获取names中的,跟当前dept一样的下标的name值
<td>${names[dept_index].name}</td>
</#list>
map取值通过list的对象取
map可以使用当前循环的list的对象取值,