创建一个maven项目,然后引入依赖
4.0.0 org.springframework.boot spring-boot-starter-parent 2.4.4 com.wzw springboot 0.0.1-SNAPSHOT springboot Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-freemarker org.springframework.boot spring-boot-starter-web org.projectlombok lombok com.squareup.okhttp3 okhttp commons-io commons-io 2.7 org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin
配置端口号和模板位置,以及跳转的后缀
server:port: 3031
spring:freemarker:cache: false #关闭模板缓存template-loader-path: classpath:/templatessuffix: .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 map){map.put("user",new User("张三",10,"13333333333","一号胡同"));return "hello";}
}
创建ftl,也就是模板,因为配置文件中配置了它的位置是/templates
下,所以我们放在resources下的templates中
ftl测试 <#-- 获取map中的值-->hello ${user.name}
然后启动测试,成功访问并取到值
注释:
html的注释是,而freemarker的注释是
<#-- -->
,注释中的内容会被freemarker忽略
插值:
freemarker使用${}
插值,用真实值替换${}
,例如${user.name}中的值被map中的值替换
FTL指令:
freemarker会解析标签中的逻辑或表达式
文本:
仅文本信息,直接输出内容
数据模型中存值
@RequestMapping("/test1")public String test1(Map 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 users=new ArrayList<>();users.add(user3);users.add(user4);//list放在数据模型中map.put("users",users);HashMap userMap=new HashMap<>();userMap.put("user1",user1);userMap.put("user2",user2);//map放在数据模型中map.put("userMap",userMap);return "test1";}
ftl中取值
test1 遍历数据模型中的list数据(数据模型中key为users)序号 姓名 年龄 电话 地址 <#list users as user><#-- _index获取下标-->${user_index} ${user.name} ${user.age} ${user.phone} ${user.address} #list>
获取数据模型中的userMap
第一种方法,在map后 [key]
姓名:${userMap['user1'].name}
地址:${userMap['user1'].address}
第二种方法,map后 .key
姓名:${userMap.user2.name}
地址:${userMap.user2.address}
遍历map中的key
<#list userMap?keys as key>${key}
#list>遍历map中的value
<#list userMap?values as value>${value}
#list>通过key遍历值,这里只能通过[]的方式
<#list userMap?keys as key>${userMap[key].name}
#list>
<#list users as user>style="color: red"#if> ><#-- _index获取下标-->${user_index} ${user.name} ${user.age} ${user.phone} ${user.address} #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> 30)>style="color: red"#if> ><#-- _index获取下标-->${user_index} ${user.name} ${user.age} ${user.phone} ${user.address} #list>#if>
判断非空后,因为空值,所以没有输出,但是也没有报错了
使用 ?? 判断字符串是否为空;返回布尔类型。如果想要输出,需要将布尔类型转换成字符串 :${(name??)?string}
如果一个变量不存在或者null,就要报错,使用!
指定一个默认值,如果!
后面没有设置值,就显示空
空值:${dept!}
部门:${dept!'123'}
部门名称:${(dept.name)!'456'}
内建函数语法: 变量 + ? + 函数名
users的长度${users?size}
controller
//boolean存值model.put("boolValue",true);
ftl:
布尔类型
<#-- 数据类型:布尔类型freemarker中布尔类型不能直接输出;如果输出要先转成字符串方式一:?c方式二:?string 或 ?string("true时的文本","false时的文本")--><#-- 直接输出-->${boolValue?c}
${boolValue?string}
<#-- true显示yes,false显示no-->${boolValue?string("yes","no")}
controller:
//日期存值model.put("time",new Date());
ftl:
时间类型
<#--数据类型:日期类型在freemarker中日期类型不能直接输出;如果输出要先转成日期型或字符串1. 年月日 ?date2. 时分秒 ?time3. 年月日时分秒 ?datetime4. 指定格式 ?string("自定义格式")y:年 M:月 d:日H:时 m:分 s:秒-->当前时间.now:${.now}
年 月 日
${time?date}
时 分 秒
${time?time}
日期+时间
${time?datetime}
自定义格式化:
${time?string("yyyy年MM月")}
${time?string("yyyy年MM月dd日 HH:mm:ss")}
controller:
//数值类型model.put("money",1546884512f);model.put("age",10);model.put("score",99.99);
ftl:
数值类型
<#--数据类型:数值类型freemarker可以直接输出数值类型1. 转字符串普通字符串 ?c货币型字符串 ?string.currency百分比型字符串 ?string.percent2. 保留浮点型数值指定小数位(#表示一个小数位)?string["0.##"]-->直接输出数值型:${age}
${money}
${score}
数值转字符串输出:${money?c}
数值转成货币类型的字符串输出:${money?string.currency}
数值转百分比类型的字符串输出:${score?string.percent}
浮点型数值保留指定小数位输出 (##表示保留两位小数):${score?string["0.##"]}
controller
//字符串类型model.put("name","zhangsan");model.put("city","hulunbeierdacaoyuan");
ftl:
字符串类型
<#--数据类型:字符串类型freemarker可以直接输出字符串类型1. 截取字符串(左闭右开) ?substring(start,end)2. 首字母小写输出 ?uncap_first3. 首字母大写输出 ?cap_first4. 字母转小写输出 ?lower_case5. 字母转大写输出 ?upper_case6. 获取字符串长度 ?length7. 是否以指定字符开头(boolean类型) ?starts_with("xx")?string8. 是否以指定字符结尾(boolean类型) ?ends_with("xx")?string9. 获取指定字符的索引 ?index_of("xx")10. 去除字符串前后空格 ?trim11. 替换指定字符串 ?replace("xx","xx")-->直接输出 :${name} - ${city}
${name?string} - ${city?string}
1. 截取字符串 ?substring(start,end) 下标0开始截取5个字符串:${city?substring(0,5)}
2. 首字母小写输出 ?uncap_first :${name?uncap_first}
3. 首字母大写输出 ?cap_first :${city?cap_first}
4. 字母转小写输出 ?lower_case :${name?lower_case}
5. 字母转大写输出 ?upper_case :${name?upper_case}
6. 获取字符串长度 ?length :${name?length}
7. 是否以指定字符开头(boolean类型) ?starts_with("z")?string :${name?starts_with("z")?string}
8. 是否以指定字符结尾(boolean类型) ?ends_with("n")?string :${name?ends_with("n")?string}
9. 获取指定字符的索引,找不到就是-1 ?index_of("g") :${name?index_of("g")}
10. 去除字符串前后空格显示字符串的长度 ?trim :${name?trim?length}
11. 替换指定字符串 ?replace("a","l") :${name?replace("a","l")}
controller:
//序列类型(list、set、数组)// 数组操作String[] stars = new String[]{"张三","李四","王五","赵六"};model.put("names",stars);// List操作List citys = Arrays.asList("北京","上海","广州","深圳");model.put("citys",citys);// JavaBean集合List 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:
序列类型
<#--数据类型:序列类型 (数组、List、Set)通过list指令输出序列<#list 序列名 as 元素名>${名称}#list>获取序列长度 ${序列名?size}获取序列元素下标 ${元素名?index}获取第一个元素 ${序列名?first}获取最后一个元素 ${序列名?last}倒序输出 序列名?reverse升序输出 序列名?sort降序输出 序列名?sort?reverse指定字段名排序 序列名?sort_by("字段名")--><#-- 数组操作 --><#list names as name>下标:${name?index} -- 名字:${name}
#list>数组的长度:${names?size}
<#-- 获取第一个元素 -->第一个元素:${names?first}
<#-- 获取最后一个元素 -->最后一个元素:${names?last}
<#-- List操作 --><#list citys as city >${city}
#list>List的size:${citys?size}
<#-- 倒序输出 --><#list citys?reverse as city >${city} -#list>
<#-- 升序输出 --><#list citys?sort as city >${city} -#list>
<#-- 降序输出 --><#list citys?sort?reverse as city >${city} -#list>
<#-- List集合 --><#list users as user>编号:${user_index} 姓名:${user.name} 年龄:${user.age}
#list><#-- 按照指定字段名排序 --><#list users?sort_by("age") as user>${user.name} |#list>
controller:
//hash类型// Map操作Map userMap = new HashMap<>();userMap.put("zhangsan","张三");userMap.put("lisi","李四");userMap.put("wangwu","王五");model.put("userMap",userMap);
ftl:
hash类型
<#--数据类型: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]}
#list><#-- value遍历输出 --><#list userMap?values as value>${value} |#list>
assign指令
<#--assign 自定义变量指令语法:<#assign 变量名=值><#assign 变量名=值 变量名=值> (定义多个变量可以用空格隔开)--><#assign str="hello">${str}
<#assign num=1 names=["zhangsan","lisi","wangwu"] >通过逗号分割数组,变成字符串:${num} -- ${names?join(",")}
assign
标签,作用是定义一个变量
names和depts都是list
<#list depts as dept>//当前下标${dept_index} //获取当前下标的,dept中的name值${dept.name的值} //获取names中的,跟当前dept一样的下标的name值${names[dept_index].name}
#list>
map可以使用当前循环的list的对象取值,