【转载】Part I. 设计人员指南---快速入门---模版 + 数据模型 = 输出

Chapter 1.  快速入门 Quick Start

模版 + 数据模型 = 输出 Template + data model = output 

FreeMarker是基于这样一个理念的:设计人员与开发人员是不同的人,他们分别擅长不同的技能。理想情况下,应该将设计人员的关注点集中到外观展现上 他们创建HTML文件、图片、和web页面的其他方面。同时,开发人员来创建产生数据的系统,再由设计人员设计的页面来显示。

问题是你经常不得不在页面上(或其他文档中)显示一些在设计期未知的信息。一个典型的电子商务应用就是基于这种动态数据的 比如库存的实时状态,美元与日元的转换汇率,顾客的订单是否已经发送等。这些数据总是在变。遇到这种情况,你需要再你的HTML(或其他文本中放一些特殊的结构;FreeMarker的输出不仅仅限于HTML),然后FreeMarker会在需要输出页面给用户时将这些代码替换成正确的数据。现在以一个非常简单的例子开始 -- 你需要在欢迎页面显示用户的名称并提示你公司的最近产品:

 

<html>

<head>

  <title>Welcome!</title>

</head>

<body>

  <h1>Welcome ${user}!</h1>

  <p>Our latest product:

  <a href="${latestProduct.url}">${latestProduct.name}</a>!

</body>

</html>  

 

 

 

 

上面的内容就是一个普通的HTML片段(除了其中的特殊代码${...})。这些代码是FreeMarker要发送输出到用户时,用来说明应该将实时的文本信息放到哪里去的。像这样的文件被叫做模版templates

那么是user, latestProduct.urllatestProduct.nam从哪儿来的呢?他们是从数据模型中复制来的。数据模型是存储在计算机内存中的内容。由开发人员写的程序创建数据模型(即数据模型由程序动态生成),这就是模版提供变化信息的机制。这些信息可能来自数据库、文件甚至是由程序生成的内容都可以。但模版作者其实并不关系数据来源。他们只是使用已有的数据模型。

我们说,输出是通过将模版和数据模型相结合创建的:

 

Template + data model = output

数据模型可能是这样:

 

  

(root)

  |

  +- user = "Big Joe"

  |

  +- latestProduct

      |

      +- url = "products/greenmouse.html"

      |

      +- name = "green mouse"  

 

 

 

(不要误会:数据模型并不是文本,这里只是提供一个数据模型的形象的样子)

打个比方,这就像是文件系统:rootlatestProduct对应于目录,user, urlname对应于文件。urlname在目录latestProduct中。但这只是一个比喻,其实并没有真正的文件和目录。

FreeMarker将上面的数据模型与示例模版合成时,web页面的访问者就会得到如下输出:

 

<html>

<head>

  <title>Welcome!</title>

</head>

<body>

  <h1>Welcome Big Joe!</h1>

  <p>Our latest product:

  <a href="products/greenmouse.html">green mouse</a>!

</body>

</html>  

 

 

 

 

数据模型  The data model 

正如你已经看到的,数据模型是基于树形结构的。这棵树可以任意复杂,并且不限深度:

 

(root)

  |

  +- animals

  |   |

  |   +- mouse

  |   |   |   

  |   |   +- size = "small"

  |   |   |   

  |   |   +- price = 50

  |   |

  |   +- elephant

  |   |   |   

  |   |   +- size = "large"

  |   |   |   

  |   |   +- price = 5000

  |   |

  |   +- python

  |       |   

  |       +- size = "medium"

  |       |   

  |       +- price = 4999

  |

  +- test = "It is a test"

  |

  +- whatnot

      |

      +- because = "don't know" 

 

其中作为目录的变量(the root, animals, mouse, elephant, python, whatnot)叫做散列hashes。哈西使用查找名来存放其它子变量。

存储单个值的变量叫做标量scalars

当你访问一个子变量时,必须使用从根root开始的、以句点.分割的路径。比如要访问老鼠mouse的价格price,从根root开始到animals,然后到mouse,再到price。所以应该这样写:animals.mouse.price。当你用特殊代码${...}包围这样的表达式,就是告诉FreeMarker输出这个节点的相应文本。比如:${ animals.mouse.price }???

还有一个重要的变量:序列sequences。序列与散列类似,都可以包含子变量,但是没有相应的查找名,而是使用序列存储子变量,可以通过数字下标访问子变量。比如,在下面的数据模型中,animalswhatnot.fruits都是序列:

 

(root)

  |

  +- animals

  |   |

  |   +- (1st)

  |   |   |

  |   |   +- name = "mouse"

  |   |   |

  |   |   +- size = "small"

  |   |   |

  |   |   +- price = 50

  |   |

  |   +- (2nd)

  |   |   |

  |   |   +- name = "elephant"

  |   |   |

  |   |   +- size = "large"

  |   |   |

  |   |   +- price = 5000

  |   |

  |   +- (3rd)

  |       |

  |       +- name = "python"

  |       |

  |       +- size = "medium"

  |       |

  |       +- price = 4999

  |

  +- whatnot

      |

      +- fruits

          |

          +- (1st) = "orange"

          |

          +- (2nd) = "banana"  

 

要访问序列的子变量,需要使用类似于数组的下标机制,将下标放到中括号中。下标从0开始,第二个变量的下标是1,以此类推。所以要获得第一个动物的名字,使用animals[0].name。要获得whatnot.fruits中的第二个条目(这里是字符串"banana"),使用whatnot.fruits[1]

标量可以存储不同类型的值。最常用的类型有:

  • 字符串:文本、字符序列。要在FreeMarker中使用字符串,必须使用引号,如"mouse" 'mouse'
  • 数字:就是数值。字符串"50"与数值50是完全不同的。前者是两个字符(尽管读音与数字相同),而后者是一个可以用于数学计算的数字值。所以,不要用引号包围数字!这会使FreeMarker将该量作为字符串处理。合法的数字有:0, 4999, -273, 3.14

总结:

  • 数据模型可以视作是层次结构的 --  就像是树。
  • 标量scalar存储单值。可以存储字符串或数字(还有别的东西,稍后介绍)。
  • 散列hash是用于存储其它变量的容器,并具有查找名。
  • 序列sequence是一种按顺序存储其它变量的容器。可以通过数字下标进行访问。


 

 

模版  The template 

最简单/常见的模版是HTML文件。当客户端访问页面时,FreeMarker就会将该HTML原封不动的发送到客户端。但如果你想获得动态效果,就会在HTML中特定位置放置一些FreeMarker可以识别的东西:

<!--[if !supportLists]-->·         <!--[endif]-->占位符${...}FreeMarker会在输出中使用括号中内容相对应的实际值来替换它。

<!--[if !supportLists]-->·         <!--[endif]-->FTL标签(FreeMarker Template Language tagsFTL标签与HTML标签相似,但它们是FreeMarker的内容,并不会打印到输出中。FTL标签名以井号#开头,以便于HTML标签区分开来。(其实还可以用 @代替#,后续章节会解释

<!--[if !supportLists]-->·         <!--[endif]-->注释Comments:与HTML注释类似,只是由<#-- -->来界定(而不是<!—-->)。这两个界定符之间的任何内容都会被FreeMarker忽略,并且不会打印到输出中。

任何既不是FTL标签也不是占位符或注释的内容都被当作普通文本来处理,并且不会被FreeMarker解析,而直接打印到输出中。

FTL标签也称为“指令”directives。就像是HTML标签也被叫做HTML元素,比如<table></table>也叫做table元素。如果你感觉二者没有区别,可以把“FTL标签”和“指令”作为同义词。

指令的例子  Examples of directives 

尽管FreeMarker有很多的指令,但这个小例子只使用最常用的指令中的三个。

if指令  The if directive 

使用if指令可以根据条件跳过模版的一个部分。比如,假设在第一个例子very first example中,你想将你的老板于其它用户区分开来,假设你老板的名字叫Big Joe

 

<html>
<head>
  <title>Welcome!</title>
</head>
<body>
  <h1>
    Welcome ${user}<#if user = "Big Joe">, our beloved leader</#if>!
  </h1>
  <p>Our latest product:
  <a href="${latestProduct.url}">${latestProduct.name}</a>!
</body>
</html>  

 

在模版中,你告诉FreeMarker字符串“, our beloved leader”只有在变量user的是值是字符串"Big Joe"时才显示。通常,如果条件condition的值为false时,在<#if condition></#if>标签中的内容。

注意:这里使用了两种不同语法的元素。等号=的左边,使用了一个变量,右边使用了字符串。也可以这样写(使用基于散列样例的数据模型):

 

<#if animals.python.price < animals.elephant.price>
  Pythons are cheaper than elephants today.
</#if>  

 

使用<#else>标签可以制定当条件为假时要做什么:

 

<#if animals.python.price < animals.elephant.price>
  Pythons are cheaper than elephants today.
<#else>
  Pythons are not cheaper than elephants today.
</#if>  

 

如果python的价格比大象elephant的价格低,会输出”Pythons are cheaper than elephants today.”,否则输出“Pythons are not cheaper than elephants today.”。

list指令  The list directive 

当你想列举一些内容的时候,应该使用list指令。如果将这个模版与前面的序列样例数据模型合并:

 

 

 

<p>We have these animals:
<table border=1>
  <tr><th>Name<th>Price
  <#list animals as being>
  <tr><td>${being.name}<td>${being.price} Euros
  </#list>
</table>  

 

会输出:

<p>We have these animals:
<table border=1>
  <tr><th>Name<th>Price
  <tr><td>mouse<td>50 Euros
  <tr><td>elephant<td>5000 Euros
  <tr><td>python<td>4999 Euros
</table>  

 

list指令的通用格式是:

<#list SequenceVar as variable>repeatThis</#list>

<#list 序列变量 as 变量>重复内容</#list>

repeatThis重复内容 部分就是当在给定的序列变量SequenceVar中的每个条目被遍历(从第一个开始)时所要重复的内容。每重复一次,变量variable就会持有当前条目的值。这个变量只存在于<#list ...></#list>内,并且不会重写/覆盖任何位于数据模型中的同名变量。

再来一个例子,将前面数据模型中的水果列出来:

 

<p>And BTW we have these fruits:
<ul>
<#list whatnot.fruits as fruit>
 <li>${fruit}
</#list>
<ul>  

 

注意:你应该已经熟悉whatnot.fruits了,它是对数据模型中的变量的引用

include指令  The include directive 

使用include指令可以将外部文件导入模版(译注:与htmljsp中的include类似)

比如,如果你要在多个页面显示相同的版权信息。可以创建一个只包含版权声明的文件,然后将其插入你需要显示版权声明的任何地方。假设将版权声明放到copyright_footer.html中:

<hr>
<i>
Copyright (c) 2000 <a href="http://www.acmee.com">Acmee Inc</a>,
<br>
All Rights Reserved.
</i>  

 

在任何需要的地方使用include指令插入即可:

 

<html>
<head>
  <title>Test page</title>
</head>
<body>
  <h1>Test page</h1>
  <p>Blah blah...
<#include "/copyright_footer.html">
</body>
</html>  

 

会输出:

<html>
<head>
  <title>Test page</title>
</head>
<body>
  <h1>Test page</h1>
  <p>Blah blah...
<hr>
<i>
Copyright (c) 2000 <a href="http://www.acmee.com">Acmee Inc</a>,
<br>
All Rights Reserved.
</i>
</body>
</html>  

 

如果修改copyright_footer.html,就会在所有的页面中看到新的版权声明。

结合使用多个指令  Using directives together 

你可以在一个页面中使用任意数量的指令,也可以自由的嵌套指令。比如下面的例子会列出所有的动物并将大型动物的名称以粗体显示:

<p>We have these animals:
<table border=1>
  <tr><th>Name<th>Price
  <#list animals as being>
  <tr>
    <td>
      <#if being.size = "large"><b></#if>
      ${being.name}
      <#if being.size = "large"></b></#if>
    <td>${being.price} Euros
  </#list>
</table>  

 

注意:由于FreeMarker不对FTL标签外部的文本进行解析,所以占位符和注释不会将上面的<b></b>视为嵌套错误的标签。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值