Freemarker语法
一、Freemarker取值
基础语法种类
- 注释:即<#-- -->,介于其之间的内容会被freemarker忽略
- 插值:即 ${..} 部分,freemarker会用真实的值代替${..}
- FTL指令:<# >FTL指令</#> ,和HTML标记类似,名字前加#予以区分,Freemarker会解析标签中的表达式或逻辑。
- 文本,仅文本信息,这些不是freemarker的注释、插值、FTL指令的内容会被freemarker忽略解析,直接输出内容。
<#--${属性名}--> <h1>${title}</h1> <#--${属性名.子属性}--> <h2>${user.name}</h2> <#--${xxx!默认值}设置当xxx为空或者不存在时显示对应的默认值--> <h2>${user.address!'未登记地址'}</h2> <#--利用?string()内置函数进行格式化输出--> <h2>${user.salary?string('¥0.00')}</h2> <h2>${user.birthday?string('yyyy年MM月dd日')}</h2>
二、Freemarker判断与循环
1.分支判断
<#if 条件1>
条件1成立执行代码
<#elseif 条件2>
条件2成立执行代码
<#elseif 条件3>
条件3成立执行代码
<#else>
</#if>
代码示例如下:
<#if user.salary <= 1000> <#--user == null--> <h3>低收入人群需要政策补贴</h3> <#elseif (user.salary > 1000 && user.salary < 10000)> <h3>中等收入人群鼓励创业</h3> <#else> <h3>高收入人群要多做公益</h3> </#if> <!-- ??代表属性是否存在,对象存在返回true,不存在返回false --> <#if manager??> manager已存在 <#else > manager不存在 </#if> <#--freemarker三目运算符--> ${(user.salary<1500)?string("低收入人群" , "高收入人群")}
三、list循环迭代
<ul> <#--#list 数据源 as 迭代变量--> <#list users as u> <li>${u_index + 1}-${u.username}-${u.name}</li> </#list> </ul>
四、内置函数
五、指令
1、集合指令
模板:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Hello World!</title> </head> <body> <#-- list 数据的展示 --> <b>展示list中的stu数据:</b> <br> <br> <table> <tr> <td>序号</td> <td>姓名</td> <td>年龄</td> <td>钱包</td> </tr> <#list stus as stu> <tr> <td>${stu_index+1}</td> <td>${stu.name}</td> <td>${stu.age}</td> <td>${stu.money}</td> </tr> </#list> </table> <hr> <#-- Map 数据的展示 --> <b>map数据的展示:</b> <br/><br/> <a href="###">方式一:通过map['keyname'].property</a><br/> 输出stu1的学生信息:<br/> 姓名:${stuMap['stu1'].name}<br/> 年龄:${stuMap['stu1'].age}<br/> <br/> <a href="###">方式二:通过map.keyname.property</a><br/> 输出stu2的学生信息:<br/> 姓名:${stuMap.stu2.name}<br/> 年龄:${stuMap.stu2.age}<br/> <br/> <a href="###">遍历map中两个学生信息:</a><br/> <table> <tr> <td>序号</td> <td>姓名</td> <td>年龄</td> <td>钱包</td> </tr> <#list stuMap?keys as key > <tr> <td>${key_index}</td> <td>${stuMap[key].name}</td> <td>${stuMap[key].age}</td> <td>${stuMap[key].money}</td> </tr> </#list> </table> <hr> </body> </html>
${k_index}: index:得到循环的下标,使用方法是在stu后边加"_index",它的值是从0开始
数据模型:
@GetMapping("/list") public String list(Model model){ //------------------------------------ Student stu1 = new Student(); stu1.setName("小强"); stu1.setAge(18); stu1.setMoney(1000.86f); stu1.setBirthday(new Date()); //小红对象模型数据 Student stu2 = new Student(); stu2.setName("小红"); stu2.setMoney(200.1f); stu2.setAge(19); //将两个对象模型数据存放到List集合中 List<Student> stus = new ArrayList<>(); stus.add(stu1); stus.add(stu2); //向model中存放List集合数据 model.addAttribute("stus",stus); //------------------------------------ //创建Map数据 HashMap<String,Student> stuMap = new HashMap<>(); stuMap.put("stu1",stu1); stuMap.put("stu2",stu2); // 3.1 向model中存放Map数据 model.addAttribute("stuMap", stuMap); return "02-list"; }
注意:如果使用的是ModelAndView,那么假设在resources目录下的templates文件夹中新建了一个
index.ftl
(请注意这里的index就是你在modelAndView.setViewName("index")
中设置的逻辑视图名称,这个需要保持一致)。
2、if指令
freemarker在解析时遇到if会进行判断,条件为真则输出if中间的内容,否则跳过内容不再输出。
格式:<#if ></if>
使用list指令中测试数据模型,判断名称为小红的数据字体显示为红色。
<table> <tr> <td>姓名</td> <td>年龄</td> <td>钱包</td> </tr> <#list stus as stu > <#if stu.name='小明'> <tr style="color: red"> <td>${stu_index}</td> <td>${stu.name}</td> <td>${stu.age}</td> <td>${stu.money}</td> </tr> <#else > <tr> <td>${stu_index}</td> <td>${stu.name}</td> <td>${stu.age}</td> <td>${stu.money}</td> </tr> </#if> </#list> </table>
结果:
字符串和数字比较
在freemarkder中进行了简化,字符串的比较方法和数字做到完全一样,比如:
<#if str == "success"> xxx </#if> <#if str !== 25> xxx </#if>
数据类型转换
字符串转数字
${'3.1415'?number}
结果:3.1415
数字转字符串
${3.1415?string("number")}
${3.1415?string("currency")}
${3.1415?string("percent")}
结果:
¥3.1415
¥3.1415
314.15%
int
可以获取数值的整数部分,举个例子:
<div>${3.1415926?int}</div>
结果:
3
size
可以获取序列中元素的个数,举个例子:
<div>${userMap?size}</div>
结果:
3
字符串转date
${"1999-09-21"?date("yyyy-MM-dd")}
结果:1999-09-21
字符串转time
${"12:12:12"?time("HH:mm:ss")}
结果:12:12:12
字符串转datetime
${"1999-09-21 12:12:12"?datetime("yyyy-MM-dd HH:mm:ss")}
结果:1999-09-21 12:12:12
布尔值转字符串
${true?"真":"假"}
结果:真
3、空值处理
FreeMarker对空值的处理非常严格
FreeMarker的变量必须有值,没有被赋值的变量就会抛出异常。
因为FreeMarker未赋值的变量强制出错可以杜绝很多潜在的错误,如:缺失潜在的变量命名,或者其他变量错误。这里所说的空值,实际上也包括那些并不存在的变量,对于一个Java的 null值而言,我们认为这个变量是存在的,只是它的值为null,但对于FreeMarker模板而言,它无法理解null值,null值和不存在的变量完全相同。
- if_exists:如果存在, 返回该变量值,否者不输出
- ??:判断某个变量是否存在,??总是返回一个布尔值,用法为:variable??。如果该变量存在,返回true,否则返回false
- !:指定缺失变量的默认值。用法为:${variable!}或${variable!defaultValue两种:
- 不指定默认值,表明默认值是空字符串,长度为0的集合,或者长度为0的Map对象
- 使用!指定默认值时,并不要求默认值的类型和变量类型相同。
示例:
- 模板代码
${username?if_exists} <#if username ??> 存在 <#else> 不存在 </#if> ${username123!"默认值"}
3.1 判断某变量是否存在使用 “??”
用法为:variable??,如果该变量存在,返回true,否则返回false
例:为防止stus为空报错可以加上判断如下:
<#if stus??> <#list stus as stu> ...... </#list> </#if>
3.2 缺失变量默认值使用 “!”
使用!要以指定一个默认值,当变量为空时显示默认值
例: ${name!''}表示如果name为空显示空字符串。
如果是嵌套对象则建议使用()括起来
例: ${(stu.bestFriend.name)!''}表示,如果stu或bestFriend或name为空默认显示空字符串。
4、将json字符串转成对象
一个例子:
其中用到了 assign标签,assign的作用是定义一个变量。
assign指令用于在页面上定义一个变量。可以直接一个简单类型,等同于给一个变量赋值;也可以定义个对象类型,取值的时候,根据对象名.属性名,跟JS中一样
<#assign text="{'bank':'工商银行','account':'10101920201920212'}" /> <#assign data=text?eval /> 开户行:${data.bank} 账号:${data.account}
遍历JSON
示例一
假设服务器端传递过来的orderItemVO
的数据为:
{"buy": "官方标本", "suit": "优惠套装1", "color": "黑羽", "zhiBao": "2年碎屏199元", "version": "8GB+128GB", "zengZhi": "1年碎屏换屏99"}
解析:
<#assign item = orderItemVO?eval> ${item.buy} ${item.suit} ${item.color} ${item.zhiBao} ${item.version} ${item.zengZhi}
示例二
假设服务器端传递过来的orderItemVOList
的数据为:
[{"value":"1","text":"已下单但未付款"},{"value":"2","text":"已付款"},{"value":"3","text":"已发货"},{"value":"4","text":"已签收"},{"value":"3","text":"已评价"},{"value":"4","text":"已追加评价"}][{"value":"1","text":"已下单但未付款"},{"value":"2","text":"已付款"},{"value":"3","text":"已发货"},{"value":"4","text":"已签收"},{"value":"3","text":"已评价"},{"value":"4","text":"已追加评价"}]
解析:
<#assign array = orderItemVOList?eval> <#list array as item> value:${value} text:${text} <br> </#list>
六、语法总结
1、字符串
语法
substring(start,end):从字符串中截取子串
start:截取子串开始的索引,start必须大于等于0,小于等于end
end: 截取子串的长度,end必须大于等于0,小于等于字符串长度,如果省略该参数,默认为字符串长度。
cap_first :将字符串中的第一个单词的首字母变为大写。
uncap_first:将字符串中的第一个单词的首字母变为小写。
capitalize:将字符串中的所有单词的首字母变为大写
ends_with 判断某个字符串是否由某个子串结尾,返回布尔值。注意:布尔值必须转换为字符串才能输出
index_of(substring,start):在字符串中查找子串的第一个字符的索引,如果没有找到子串,则返回-1。
Start:参数用于指定从字符串的那个索引处开始搜索,start为数字值。如果start大于字符串长度,则start取值等于字符串长度,如果start小于0, 则start取值为0。
length:返回字符串的长度
lower_case:将字符串转为小写
upper_case:将字符串转为大写
contains :判断字符中是否包含某个子串。返回布尔值。注意:布尔值必须转换为字符串才能输出
number:将字符串转换为数字
replace:将字符串中的一部分从左到右替换为另外的字符串。
split:使用指定的分隔符将一个字符串拆分为一组字符串
trim:删除字符串首尾空格
html:将字符串中的<、>、&和"替换为对应得<>":&
date,time,datetime将字符串转换为日期,注意:如果指定的字符串格式不正确将引发错误
示例
模板:
字符串连接:${str1 + str2} 字符串截取:${(str)?substring(3,6)} 字符串长度:${(str)?length} 字符串大写:${(str)?upper_case} 字符串小写:${(str)?lower_case} 字符串常指定字符的位置:${(str)?index_of('w')} 字符串常最后一个指定字符的位置:${(str)?last_index_of('o')} 字符串截取:${key?substring(3)} 字符串截取:${key?substring(0,key?index_of('_'))} 字符串拆分:${pics?split(",")} 字符串替换:${(str)?replace('o','xx')} 字符串尾字符判断:${str?ends_with("0ER")?string} 返回结果为true 字符串转数字:${"3.1414"?number+22} 字符串转义:${"a>b b<c x&y"?html} 字符串转换为日期: ${date1?date("yyyy-MM-dd")} ${date2?time("HH:mm:ss")} ${date3?datetime("yyyy-MM-dd HH:mm:ss")}
2、日期
语法:
date: 只显示日期,不显示时间.
如c r e a t e T i m e ? d a t e 或 {createTime?date} 或createTime?date或{createTime?date(‘yyyy-MM-dd’)}
time: 只显示时间,不显示日期
如c r e a t e T i m e ? t i m e 或 {createTime?time} 或createTime?time或{createTime?time(‘hh:mm:ss’)}
datetime: 时间和日期同时显示
如c r e a t e T i m e 或 {createTime} 或createTime或{createTime?datetime(‘yyyy-MM-dd hh:mm:ss’)}或${createTime?string(‘yyyy-MM-dd hh:mm:ss’)}
示例:
模板文件
输出完整的日期时间部分:${now?datetime}
输出日期部分:${now?date}
输出时间部分: ${now?time}
使用日期格式化样式输出完整的日期时间值
${now?string("yyyy-MM-dd HH:mm:ss zzzz")}
${now?string("EEE, MMM d, ''yy")}
${now?string("EEEE, MMMM dd, yyyy, hh:mm:ss a '('zzz')'")}
3、数字格式化
模板文件
整数取实际的位数,小数部分保留二位
${num2?string('###.00')}
${num3?string('#.00')}
如果小数点后不足三位,用 0 代替:
${num1?string('0.000')}
如果小数点后多余两位,就只保留两位,否则输出实际值:
${num2?string('#.##')}
整数部分每三位用 , 分割,并且保证小数点后保留两位,不足用 0 代替:
${num3?string(',###.00')}
整数部分每三位用 , 分割,并且小数点后多余三位就只保留三位,不足三位就取实际位数,可以不不包含小数点
${num3?string(',###.###')}
整数部分如果不足三位(000),前面用0补齐,否则取实际的整数位
${num1?string('000.00')}
内建函数c
map.put("point", 102920122);
point是数字型,使用${point}会显示这个数字的值,不并每三位使用逗号分隔。 如果不想显示为每三位分隔的数字,可以使用c函数将数字型转成字符串输出 ${point?c}
<br> ${point} <br> ${point?c}
PS:如果参数是bigDecimal类型的小数,ftl模板默认四舍五入到小数点后三位小数。 如果想保留完整的小数位数,也可以用c函数处理。
参考文章:
https://www.jianshu.com/p/b15eb14e73dc
https://blog.csdn.net/weixin_42624574/article/details/125681561
https://blog.csdn.net/lianghecai52171314/article/details/104134125