目录
  1. 1. Freemarker常用
    1. 1.0.1. 正常显示一个变量
    2. 1.0.2. 数据类型
      1. 1.0.2.1. 定义字符串
      2. 1.0.2.2. 数字类型
      3. 1.0.2.3. 哈希表类型
      4. 1.0.2.4. 序列类型
      5. 1.0.2.5. 时间类型
      6. 1.0.2.6. 布尔类型
  2. 1.1. 宏的基本用法
  3. 1.2. 序列的操作
    1. 1.2.1. 序列内置函数
      1. 1.2.1.1. 迭代
      2. 1.2.1.2. 返回序列头尾值
      3. 1.2.1.3. 序列反转
      4. 1.2.1.4. 序列大小
      5. 1.2.1.5. 对象转化为字符串后顺序排序
      6. 1.2.1.6. 按序列中对象的属性value进行排序
      7. 1.2.1.7. 序列的连接
      8. 1.2.1.8. 判断序列是否包含某个元素
    2. 1.2.2. Hash的内置函数
      1. 1.2.2.1. 返回hash里的所有key
      2. 1.2.2.2. 返回hash里的所有value
    3. 1.2.3. 字符串内置函数
      1. 1.2.3.1. 从一个字符串中截取子串
      2. 1.2.3.2. 首字母大写
      3. 1.2.3.3. 首字母小写
      4. 1.2.3.4. 所有单词首字母大写
      5. 1.2.3.5. 判断某个字符串是否由某个子串结尾
      6. 1.2.3.6. 将字符串中的<、>、&和”替换为对应得<>”:&
      7. 1.2.3.7. 在字符串中查找某个子串
      8. 1.2.3.8. 返回字符串的长度
      9. 1.2.3.9. 将字符串转为小写
      10. 1.2.3.10. 将字符串转为大写
      11. 1.2.3.11. 判断字符中是否包含某个子串
      12. 1.2.3.12. 将字符串转换为数字
      13. 1.2.3.13. 替换字符串
      14. 1.2.3.14. 字符串拆分
      15. 1.2.3.15. 删除字符串首尾空格
      16. 1.2.3.16. 数字转换为字符串
      17. 1.2.3.17. 数字格式
      18. 1.2.3.18. 数值精度控制
    4. 1.2.4. 布尔值内置函数
  4. 1.3. 运算符的使用
    1. 1.3.1. 取整运算
    2. 1.3.2. 大于号>的使用
  • 2. Freemarker模板解析过程
  • 3. FreeMarker缓存处理
  • 4. Freemarker空值的处理
  • 模版引擎 FreeMarker基本使用

    Apache FreeMarke是一个_模板引擎_:一个Java库,用于根据模板和更改数据生成文本输出(HTML网页,电子邮件,配置文件,源代码等)。模板是用FreeMarker模板语言(FTL)编写的,这是一种简单的专用语言(不像PHP这样的完整编程语言)。通常,使用通用编程语言(如Java)来准备数据(发布数据库查询,进行业务计算)


    这篇文章呢就来介绍freemarker 的常见用法

    Freemarker常用

    正常显示一个变量

    <p>${name}</p>

    数据类型

    定义字符串

    <#assign temp = "happy fish"  />
    或者
    <#assign temp = 'happy fish' />
    <b>${temp}</b>

    这两种形式是相等的。字符串中可以使用转义字符””。如果字符串内有大量的特殊字符,则可以在引号的前面加上一个字母r,则字符串内的所有字符都将直接输出。例如:”It’s “quoted”” 或者 r”C:\raw\string”

    数字类型

    <#assign number = 111  />
    <b>${number}</b>

    输入不带引号的数字就可以直接指定一个数字,必须使用点作为小数的分隔符而不能是其他的分组分隔符。可以使用-或+来表明符号(+是多余的)。科学记数法暂不支持使用(1E3就是错误的),而且也不能在小数点之前不写0(.5也是错误的)。

    哈希表类型

    <#assign map = {"name":"green mouse", "price":150} />
    <b>${map.name}</b>

    键和值成对出现并以冒号分隔,最外面使用花括号,注意到名字和值都是表达式,但是用来检索的名字就必须是字符串类型的。

    序列类型

    <#assign  nums=[1,2,3,4,5,77,8,99] />
    <b>${nums[0]}</b>
    输出序列
    <#list nums as num>
    ${num}
    </#list>

    指定一个序列,使用逗号来分隔其中的每个子变量,还可以采用数字范围定义了一个连续的序列

    <#assign nums=1..99/>

    这种方式定义的序列的内容是1到99。总之,使用数字范围也可以表示一个数字集合,如1..5等同于集合[1,2, 3, 4, 5];同样也可以用5..1来表示[5, 4, 3, 2, 1]。

    时间类型

    <#assign date1 = "2018-09-22"?date("yyyy-MM-dd") />
    <#assign date2 ="16:34:43"?time("HH:mm:ss") />
    <#assign date3 = "2018-09-22 17:23:45"?datetime("yyyy-MM-dd HH:mm:ss") />
    <b>${date1},</b>
    <b>${date2},</b>
    <b>${date3}</b>

    FreeMarker支持date、time、datetime三种类型,这三种类型的值无法直接指定,通常需要借助字符串的date、time、datetime三个内建函数进行转换才可以

    布尔类型

    <#assign  flag=true  />
    <#if flag>fulinlin</#if>

    注意boolean不能输出需要转换为字符串

    <#assign  flag=true  />
    <b>${flag}?string</b>

    宏的基本用法

    <#macro one>
    <p style="font-size: x-small"> Hello Word!</p>
    </#macro>
    <@one></@one>

    如果没有体内容也可以用 <@one />

    可以在宏定义之后定义参数,宏参数是局部变量,只在宏定义中有效

    <#macro two person>
    <p style="font-size: x-small"> Hello ${person}!</p>
    </#macro>
    <@two person="fulin"></@two>

    宏的参数是FTL表达式,所以,person=fulin和上面的例子中具有不同的意义,这意味着将变量fulin的值传给person,这个值可能是任意一种数据类型,甚至是一个复杂的表达式。

    宏可以有多个参数,使用时参数的次序是无关的,但是只能使用宏中定义的参数,并且对所有参数赋值

    <#macro three person size>
    <p style="font-size: ${size}" > Hello ${person}!</p>
    </#macro>
    <@three size="26px" person="Word"></@three>

    如果其中一个没有赋值就会出错,如果想定义个缺省值怎么办呢<#macro three person size=”22px”> 这样的话,这个使用方法就是正确的。

    序列的操作

    序列内置函数

    迭代

    <#assign list=[1,123,12,1234,12345,123456] />
    <#list list as l>
    <b>${l_index + 1}.</b>
    <b>${l}</b>
    <#if l=12345><#break></#if>
    <#if l_has_next>,</#if>
    </#list>

    输出结果: 1. 1 , 2. 123 , 3. 12 , 4. 1,234 , 5. 12,345

    item_index:当前变量的索引值.
    item_has_next:是否存在下一个对象.

    返回序列头尾值

    ${list?first}<br>
    ${list?last}<br>

    序列反转

    <#list list?reverse as l>
    <b>${l}</b>
    <#if l_has_next>,</#if>
    </#list><br>

    序列大小

    ${list?size}<br>

    对象转化为字符串后顺序排序

    <#list list?sort as l>
    <b>${l}</b>
    <#if l_has_next>,</#if>
    </#list><br>

    按序列中对象的属性value进行排序

    <#list list?sort_by(value) as l>
    <b>${l}</b>
    <#if l_has_next>,</#if>
    </#list><br>

    序列的连接

    <#list ["一","二","三"] + ["四","五","六"] as x>
    ${x}
    </#list>

    输出结果如下:一二三四五六

    判断序列是否包含某个元素

    <#assign x = ["cat", 16, "fish", "fulin"]>
    "dog": ${x?seq_contains("dog")?string("yes", "no")}
    16: ${x?seq_contains(16)?string("yes", "no")}
    "16": ${x?seq_contains("16")?string("yes", "no")}

    输出结果:”dog”: yes、16: yes、”16”: no,seq_前缀在这个内建函数中是需要的,用来和contains 区分开。contains函数用来在字符串中查找子串(因为变量可以同时当作字符串和序列)

    Hash的内置函数

    返回hash里的所有key

    <#assign map={"name":"张三","age":"16"} />
    <#list map?keys as m>
    <b>${m}</b>
    <#if m_has_next>,</#if>
    </#list><br>

    返回hash里的所有value

    <#assign map={"name":"张三","age":"16"} />
    <#list map?values as m>
    <b>${m}</b>
    <#if m_has_next>,</#if>
    </#list><br>

    字符串内置函数

    从一个字符串中截取子串

    ${str?substring(1,3)}<br>

    start:截取子串开始的索引,start必须大于等于0,小于等于end
    end: 截取子串的长度,end必须大于等于0,小于等于字符串长度,如果省略该参数,默认为字符串长度。

    首字母大写

    ${str?cap_first}<br>

    首字母小写

    ${str?uncap_first}<br>

    所有单词首字母大写

    ${str?capitalize}<br>

    判断某个字符串是否由某个子串结尾

    ${str?ends_with("rd")?string}<br>

    将字符串中的<、>、&和”替换为对应得<>”:&

    ${str?html}<br>

    在字符串中查找某个子串

    ${str?index_of("d",-1)}<br>

    返回找到子串的第一个字符的索引,如果没有找到子串,则返回-1。Start参数用于指定从字符串的那个索引处开始搜索,start为数字值。如果start大于字符串长度,则start取值等于字符串长度,如果start小于0,则start取值为0。

    返回字符串的长度

    ${str?length}<br>

    将字符串转为小写

    ${str?lower_case}<br>

    将字符串转为大写

    ${str?upper_case}<br>

    判断字符中是否包含某个子串

    ${str?contains("a")?string}<br>

    将字符串转换为数字

    ${num?number}<br>

    替换字符串

    ${str?replace("o","*")}<br>

    字符串拆分

    <#list str?split("o") as m>
    <b>${m}</b>
    <#if m_has_next>,</#if>
    </#list><br>

    删除字符串首尾空格

    ${str?trim}<br>

    数字转换为字符串

    ${number?c?is_string?string}<br>

    数字格式

    ${number?string.computer}<br>
    ${number?string.percent}<br>
    ${number?string.number}<br>

    Freemarker中预订义了三种数字格式:number,currency(货币)和percent(百分比)其中number为默认的数字格式转换.

    数值精度控制

    <#assign x=2.582/>
    <#assign y=4/>
    #{x; M2}//2.58
    #{y; M2}//4
    #{x; m1M2}//2.58
    #{y; m1M2}//4.0

    mX:小数部分最小X位。MX:小数部分最大X位。

    布尔值内置函数

    foo?string("yes","no")

    如果布尔值是true,那么返回”yes”,否则返回no,string用于将布尔值转换为字符串输出true转为”true”,false转换为”false”.

    运算符的使用

    取整运算

    <#assign x=5>
    ${(x/2)?>int}//2
    ${1.1?int}//1
    ${1.999?int} //1
    ${-1.1?int}//-1

    大于号>的使用

    <#assign x = 4>
    <#if (x>5) >
    x > 5
    </#if>
    <!--或者-->
    <#assign x = 4>
    <#if x gt 5 >
    x > 5
    </#if>

    使用>=和>的时候有一点小问题。FreeMarker解释>的时候可以把它当作FTL标签的结束符。为了避免这种问题,不得不将表达式放到括号内:<#if (x > y) >,另外,可以使用lt代替<,lte代替<=,gt代替>,gte代替>=。由于历史遗留的原因,FTL也支持\lt,\lte,\gt和\gte,使用他们和使用不带反斜杠的效果一样。切记不能直接 x>5 原因是Freemarker内部的解析处理原因。

    Freemarker模板解析过程

    概念啥东西,放上面基本都不看~

    例如:一个freemarker表达式” ${hello} “,会被解析成三个部分,分别是

    <body>
    ${hello}
    </body>

    前面和后面的body标签,在freemarker中被定义为TextBlock,中间的变量定义为DollarVariable。那么目前的结构也就是RootExpression = TextBlock DollarVariable TextBlock。解释器一进来将会对RootExpression进行解析,RootExpression将会依次调用TextBlock DollarVariable TextBlock进行解析。不同类型将会做不同操作,根据传进来的Context参数进行相应赋值并输出等。
    当Template启动解释时,由Environment进入调用根元素的访问动作,根元素会依次访问所包含的TemplateElement,直到所有叶子节点访问完成,这些访问动作是通过调用Environment的visit方法控制,Environment做些相关必要操作,再根据访问的节点类型调用相应节点的访问操作。当访问到包含需要解释器的元素节点时,则会启动解释器做解释操作,根据Expression类型,调用getStringValue,并传入参数Environment,相应类型的表达式根据Environment解释得到输入字符串的值,返回并写到响应流,即解释完成。

    FreeMarker缓存处理

    FreeMarker 的缓存处理主要用于模版文件的缓存,一般来讲,模版文件改动不会很频繁,在一个流量非常大的网站中,如果频繁的读取模版文件对系统的负担还是很重的,因此 FreeMarker 通过将模版文件的内容进行缓存,来降低模版文件读取的频次,降低系统的负载。当处理某个模版时,FreeMarker直接从缓存中返回对应的 Template 对象,并有一个默认的机制来保证该模版对象是跟模版文件同步的。如果使用的时候 FreemarkerServlet 时,有一个配置项template_update_delay用来指定更新模版文件的间隔时间,相当于多长时间检测一下是否有必要重新加载模版文件,0 表示每次都重新加载,否则为多少毫秒钟检测一下模版是否更改。FreeMarker定义了一个统一的缓存处理接口CacheStorage,默认的实现是 MruCacheStorage 最近最少使用的缓存策略

    Freemarker空值的处理

    FreeMarker的变量必须赋值,否则就会抛出异常。而对于FreeMarker来说,null值和不存在的变量是完全一样的,因为FreeMarker无法理解null值。FreeMarker提供两个运算符来避免空值:

    (1)!运算符:指定缺失变量的默认值;
    (2)??运算符:判断变量是否存在。

    !运算符有两种用法:variable!或variable!defaultValue。第一种用法不给变量指定默认值,表明默认值是空字符串、长度为0的集合、或长度为0的Map对象。

    使用!运算符指定默认值并不要求默认值的类型和变量类型相同 比如说:

    <#-- ${fulin}没有定义这个变量,会报异常!-->

    ${fulin!} <#--没有定义这个变量,默认值是空字符串!-->

    ${fulin!"abc"} <#--没有定义这个变量,默认值是字符串abc!-->

    ??运算符返回布尔值,如:variable??,如果变量存在,返回true,否则返回false。一般情况下与if指令共同使用。将它和if指令合并,如下面的例子:如果user变量不存在的话将会忽略整个问候代码段:

    <#if user??><h1>Welcome ${user}!</h1></#if>

    关于多级访问的变量,比如user.money.price,书写代码:user.money.price!0,仅当user.money存在而仅仅最后一个子变量price可能不存在(这种情况下我们假设价格是0)。如果user或者money不存在,那么模板处理过程将会以“未定义的变量”错误而停止。为了防止这种情况的发生,可以这样来书写代码(user.money.price)!0。这种情况下当animals或python不存在时表达式的结果仍然是0。对于??也是同样用来的处理这种逻辑的:user.money.price??对比(user.money.price)??来看。

    文章作者: Fulin
    文章链接: http://yoursite.com/2019/07/25/yuque/%E6%A8%A1%E7%89%88%E5%BC%95%E6%93%8E%20FreeMarker%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/
    版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 FuLinLin
    打赏
    • 微信
    • 支付宝

    评论