<导航

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:将字符串中的<、>、&和"替换为对应得<>&quot:&amp
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

https://mp.weixin.qq.com/s/OApDoXM4e7QR13j-aBqmPQ

 

posted @ 2022-11-28 23:14  字节悦动  阅读(2664)  评论(0编辑  收藏  举报