插值

本章将介绍 FreeMarker 插值(${}),插值指将指定的变量中的值插入到模板中,然后输出文本。

概览

插值的使用格式是:

${expression}

这里的 expression 可以是所有种类的表达式,比如:${100 + x}

插值是用来计算表达式的具体值,然后将值转换为文本 (字符串)。插值仅仅可以在两种位置使用:

  • 文本区,比如 <h1>Hello ${name}!</h1>

  • 字符串表达式,比如 <#include "/footer/${company}.html">

【注意

(1)表达式的结果必须是字符串;数字、日期/时间/日期时间值可以被插值自动转换为字符串。其它类型的值,比如:布尔值,序列,必须 "手动地" 转换成字符串,否则就会发生错误,中止模板执行。

(2)一个常犯的错误是在不能使用插值的地方使用了它。 例如:在 if 指令中使用插值,如:<#if ${big}>...</#if>,这是语法上的错误。只要简单写为 <#if big>...</#if>即可。 而且 <#if "${big}">...</#if> 也是错误的,因为这样参数就是字符串类型了,但是 if 指令的参数要求是布尔值,所以就会发生运行时错误。

插入字符串

如果插值在文本区 (也就是说,不在字符串表达式中),如果 escape 指令起作用了,那么将被插入的字符串会被自动转义。如果要生成 HTML,那么强烈建议你利用它来阻止跨站脚本攻击和非格式良好的HTML页面。这里有一个示例:

<#escape x as x?html>
   ...
  <p>Title: ${book.title}</p>
  <p>Description: <#noescape>${book.description}</#noescape></p>
  <h2>Comments:</h2>
  <#list comments as comment>
    <div class="comment">      ${comment}
    </div>
  </#list>
   ...
</#escape>

这个示例展示了当生成HTML时,最好将完整的模板放入到 escape 指令中。那么,如果 book.title 包含 &, 在输出中它就会被替换成 &amp;,而页面还会保持为格式良好的HTML。如果用户注释包含如 <iframe> (或其它元素)的标记,那么就会被转义成 &lt;iframe&gt; 的样子,使他们没有任何危险。但有时在数据模型中真的需要HTML,我们假设上面的 book.description 在数据库中的存储是HTML格式的,那么此时不得不使用 noescape 来取消 escape 的转义,不包含 escape, 模板就会像这样了:

  ...
  <p>Title: ${book.title?html}</p>
  <p>Description: ${book.description}</p>
  <h2>Comments:</h2>
  <#list comments as comment>
    <div class="comment">
      ${comment?html}
    </div>
  </#list>
  ...

这和之前示例的效果是一样的,但是这里可能会忘记 ?html 等内建函数,那么这就会有安全上的问题了。 在之前的示例中,你可能忘记 noescape 等内建函数,也会造成不良的输出,但是起码是没有安全隐患的。

插入数字

如果表达式是数字类型,那么数值将根据默认格式转换成字符串。这也许会包含最大的小数,数字分组和相似处理的问题。通常程序员应该设置默认的数字格式;而模板设计者不需要处理它(但是可以使用 number_format 来设置)。 可以使用内建函数 string 为一个插值来重写默认数值格式。

小数的分隔符通常(其他类似的符号也是这样,如分组符号)是根据所在地的标准(语言,国家)来确定的,这也需要程序员来设置。例如这个模板:

${1.5}

如果当前本地化设置为英语时,将会输出:

1.5

而当前地区为德国时,将会输出:

1,5

这是因为德国人使用逗号作为小数点。

【注意】

可以看出,插值的打印都是给用户看的,而不是给“计算机”的。有时候这样并不好,比如要打印数据库记录的主键,用来作为URL中的一部分或HTML表单的隐藏域来作为提交内容,或者要打印 CSS/JavaScript 中的数字,因为这些值都是给计算机程序去识别的而不是给用户看的。很多程序对数字格式的要求非常严格,它们只能理解一部分简单的美式数字格式。那样的话,可以使用内建函数 c (代表''计算机'')来解决这个问题,比如:

<a href="/shop/productdetails?id=${product.id?c}">Details...</a>

插入日期/时间

如果表达式的值是时间日期类型,那么日期中的数字将会按照默认格式来转换成文本。 通常程序员应该设置默认格式,而页面设计者无需处理这一点。如果需要的话,可以参考 date_format, time_format 和 datetime_format 的 setting 指令设置。当然,也可以使用内建函数 string 来覆盖单独插值的默认格式。

<p>当前日期:${currentDate?string("yyyy-MM-dd HH:mm:ss.SSS")}</p>

输出结果:

<p>当前日期:2020-06-27 22:26:52.225</p>

【注意】

为了将日期显示成文本,FreeMarker 必须知道日期中的哪一部分在使用,也就是说,如果仅仅日期部分 (年,月,日) 使用或仅仅时间部分 (时,分,秒,毫秒) 使用或两部分都用。不幸的是,由于Java平台技术的限制,自动探测一些变量是不现实的。 这时可以找程序员对数据模型中可能出问题的变量进行处理。如果找出时间日期变量的哪部分在使用是不太可能的话,就必须使用 FreeMarker 内建函数 date,time 和 datetime 来识别 ( 比如 ${lastUpdated?datetime} ),否则就会出现错误停止执行。例如:

<p>${currentDate?datetime}</p>

<p>${currentDate?date}</p>

<p>${currentDate?time}</p>

输出结果:

<p>2020-6-27 22:33:29</p>

<p>2020-6-27</p>

<p>22:33:29</p>

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号