现在的位置: 首页 > 综合 > 正文

FreeMarker学习笔记(二) Freemarker模板的值与类型

2018年05月09日 ⁄ 综合 ⁄ 共 9040字 ⁄ 字号 评论关闭

1.基础知识

明白值和类型的概念对于理解数据模型是非常的重要。然而正如你所看到的,值和类型的概念并不仅限于数据模型。

(1)什么是值?

 

你所知道的值的例子,日常的数字16, 0.5就是值等等,例如数字。就计算机语言而言,值是一个宽泛的含义,值不一定是数字,看下面的数据模型:

我们说user 的值是"Big Joe"(一个字符串),today 的值是"Jul 6, 2007" (一个日期),todayHoliday 的值是false(一个布尔类型, 值为yes或no)。lotteryNumbers 的值是包含了20, 14, 42, 8, 15的序列. 可以肯定的说lotteryNumbers 的值是一个包含了多个值的序列,(例如, 当中的第二个项的值是14),但是lotteryNumbers 本身仍然是一个单值。它就像一个包含了许多其他项的盒子;整个盒子可以看作是一个值,最后但并非最不重要,我们有一个变量是cargo , 它是一个哈希表(又一个像盒子一样的东西)。因此,值就是可以保存在变量中的东西(例如, user、 cargocargo.name中保存的 )。但是值不一定非要保存在所谓的变量中,例如我们有一个值100:

<#if cargo.weight < 100






>Light cargo</#if>  






一个临时计算的结果也称为值, 当模板执行时,像20和120like 20(打印120):

${cargo.weight / 2 + 100}  






最后解释:两个数40 (货物的重量)和2相除, 产生一个新的值20。加上100,就产生了值120,然后打印120(${... } ),毫无疑问你现在应该明白什么是值了。

(2)什么是类型?

值的另一个重要的方面是它们的类型。例如user 的类型是字符串, lotteryNumbers 的类型是一个序列。值的类型非常重要,以为它很大程度决定了你怎样和在哪里使用这个值。由于除法对数字是可行的,却并不适合字符串,所以像${user / 2} 就是一个错误,但是${cargo.weight / 2} 却工作的很好,并会打印出20。假如cargo 是一个哈希数,那么使用"."像cargo.name 可以讲得过去。或者你仅可以使用<#list ... > 列出序列的。或者<#if ...> 条件一定会产生一个布尔值等。一个值可以同时为多种类型,虽然这很受使用。例如下面的mouse 就同时为字符串类型和哈希类:

FreeMarker手册- 基础知识

如果你将上面的数据模型与这个模板合并:

${mouse}       <#-- uses mouse as a string -->
${mouse.age}   <#-- uses mouse as a hash -->
${mouse.color} <#-- uses mouse as a hash -->  






将输出:

Yerri
12
brown  






(3)数据模型是哈希表

从各种数据模型的例子你可能已经意识到:标记为"(root)"就是哈希类型。 当你像这样写user ,这意味着你想将user 保存在哈希的根部。如果你这样写:root.user ,除非没有"root"变量,否则就无法工作。有些可能会困惑的是,我们的例子中的数据模型,这就是根本的散列,载有进一步的哈希和序列(lotteryNumbers 和cargo ) 。没有什么特别的理由。哈希表包含的其他变量,这些变量的值,它可以是一个字符串,一个数字,等等,当然它可以是一个散列或序列以及。因为,正如早些时候解释的那样,序列或散列只是一个值,就像一个字符串或数字。

 

2.类型

支持的类型有:

(1)标量

这是基本的简单值类型。可以是:

  • 字符串(String): It is simple text, e.g., the name of a product.

    If you want to give a string value directly in the template, rather than use a variable that comes from the data model, you write the text between quotation marks, e.g., "green mouse" or 'green mouse' . (More details regarding the syntax can be found later .)

  • 数字(Number): For example the price of a product. Whole numbers and non-whole numbers are not distinguished; there is only a single number type. So for example 3/2 will be always 1.5, and never 1. Just like if you are using a calculator.

    If you want to give a numerical value directly in the template, then you write for example: 150 or -90.05 or 0.001 . (More details regarding the syntax can be found later .)

  • 布尔类型(Boolean): A boolean value represents a logical true or false (yes or no). For example, if a the visitor has been logged in or not. Typically you use booleans as the condition of the if directive, like <#if loggedIn >... </#if> or <#if price == 0>... </#if> ; in the last case the result of the price == 0 part is a boolean value.

    In the templates you can directly specify a boolean with the reserved words true and false .

  • 日期(Date): A date variable stores date/time related data. It has three variations:

    • A date with day precision (often referred simply as "date") as April 4, 2003

    • Time of day (without the date part), as 10:19:18 PM. Time is stored with millisecond precision.

    • Date-time (sometimes called "time stamp") as April 4, 2003 10:19:18 PM. The time part is stored with millisecond precision.

    Unfortunately, because of the limitations of the Java platform, FreeMarker sometimes can't decide which parts of the date are in use (i.e., if it is date-time, or a time of day, etc.). The solution for this problem is an advanced topic that will be discussed later .

    It is possible to define date values directly in templates, but this is an advanced topic that will be explained later .

Bear in mind that FreeMarker distinguishes strings from numbers and booleans, so the string "150" and the number 150 are totally different. A number holds a numerical value. A boolean holds a logical true or false. A string holds an arbitrary sequence of characters.

(2)容器

These are the values whose purpose is to contain other variables; they are just containers. The contained variables are often referred as subvariables . The container types are:

  • 哈希(Hash): Associates a unique lookup name with each of its subvariables. The name is an unrestricted string. A hash doesn't define an ordering for the subvariables in it. That is, there is no such thing as the first subvariable, and the second subvariable, etc.; the variables are just accessed by name.

  • 序列(Sequence): Associates an integer number with each of its subvariables. The first subvariable is associated with 0, the second with 1, the third to 2, and so on; the subvariables are ordered. These numbers are often called the indexes of the subvariables. Sequences are usually dense, i.e., all indexes up to the index of the last subvariable have an associated subvariable, but it's not strictly necessary. The type of the subvariable values need not be the same.

  • 集合(Collection): A collection, from the viewpoint of the template author, is a restricted sequence. You cannot access its size or retrieve its subvariables by index, but they can be still listed with the list directive .

Note that since a value can have multiple types , it is possible for a value to be both a hash and a sequence, in which case it would support index-based access as well as access by lookup name. However, typically a container will be either a hash or a sequence, not both.

As the value of the variables stored in hashes and sequences (and collections) can be anything, it can be a hash or sequence (or collection) as well. This way you can build arbitrarily deep structures.

The data-model itself (or better said the root of it) is a hash.

(3)子程序

a.方法和函数

A value that is a method or a function is used to calculate another value, influenced by the parameters you give to it.

For programmer types: Methods/functions are first-class values, just like in functional programming languages. This means that functions/methods can be the parameters or return values of other functions/methods, you can assign them to variables, and so on.

Suppose that programmers have put the method variable avg in the data-model that can be used to calculate the average of numbers. If you give the 3 and 5 as parameters when you access avg , then you get the value 4.

The usage of methods will be explained later , but perhaps this example helps to understand what methods are:

The average of 3 and 5 is: ${avg(3, 5)}
The average of 6 and 10 and 20 is: ${avg(6, 10, 20)}
The average of the price of a python and an elephant is:
${avg(animals.python.price, animals.elephant.price)} 

this will output:

The average of 3 and 5 is: 4
The average of 6 and 10 and 20 is: 12
The average of the price of a python and an elephant is:
4999.5 

What is the difference between a method and a function? As far as the template author is concerned, nothing. Well not really nothing, as methods typically come from the data-model (as they reflect the methods of Java objects ), and functions are defined in templates (with the function directive -- an advanced topic), but both can be used on the same way.

b.用户自定义指令

A value of this type can be used as user-defined directive (with other words, as FreeMarker tag). An user-defined directive is a subroutine, something like a little reusable template fragment. But this is an advanced topic that will be explained later in its own chapter.

For programmer types: user-defined directives (such as macros), are first-class values too, just like functions/methods are.

Just to get an idea about user-defined directives (so just ignore this if you won't understand), assume we have a variable, box , whose value is a user-defined directive that prints some kind of fancy HTML message box with a title bar and a message in it. The box variable could be used in the template like this (for example):

<@box
 title="Attention!">
Too much copy-pasting may leads to
maintenance headaches.
</@box

c.函数/方法 vs 用户自定义指令

This is for advanced users again (so ignore it if you don't understand). It's a frequent dilemma if you should use a function/method or an user-defined directive to implement something. The rule of thumb is: Implement the facility as user-defined directive instead of as function/method if:

  • ... the output (the return value) is markup (HTML, XML, etc.). The main reason is that the result of functions are subject to automatic XML-escaping (due to the nature of ${... } ), while the output of user-defined directives are not (due to the nature of <@... > ; its output is assumed to be markup, and hence already escaped).

  • ... it's the side-effect that is important and not the return value. For example, a directive whose purpose is to add an entry to the server log is like that. (In fact you can't have a return value for a user-defined directive, but some kind of feedback is still possible by setting non-local variables.)

  • ... it will do flow control (like for example list or if directives do). You just can't do that with a function/method anyway.

The Java methods of FreeMarker-unaware Java objects are normally visible as methods in templates, regardless of the nature of the Java method. That said, you have no choice there.

(4)混合类型

Nodes

Node variables represent a node in a tree structure, and are used mostly with XML processing , which is an advanced, and specialized topic.

Still, a quick overview for advanced users : A node is similar to a sequence that stores other nodes, which are often referred as the children nodes. A node stores a reference to its container node, which is often referred as the parent node. The main point of being a node is the topological information; other data must be stored by utilizing that a value can have multiple types. Like, a value may be both a node and a number, in which case it can store a number as the "pay-load". Apart from the topological information, a node can store some metainformation as well: a node name, a node type (string), and a node namespace (string). For example, if the node symbolizes a h1 element in an XHTML document, then its name could be "h1" , it's node type could be "element" , and it's namespace could be "http://www.w3.org/1999/xhtml" . But it's up to the designer of the data-model if what meaning these metainformations have, and if they are used at all. The way of retrieving the topological and metainformations is described in a later chapter (that you don't have to understand at this point).

抱歉!评论已关闭.