FreeMarker模板开发指南知识点梳理

freemarker是什么? 有什么用? 怎么用? (问得好,这些都是我想知道的问题)

freemarker是什么?

  FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。

对于像我一样之前完全对freemarker没概念的来说,这种解释还是无法释疑解惑,需要说的再详尽点。

freemarker有什么用?

  模板编写为FreeMarker Template Language (FTL)。它是简单的,专用的语言。 那就意味着要准备数据在真实编程语言中来显示,比如数据库查询和业务运算, 之后模板显示已经准备好的数据。在模板中,你可以专注于如何展现数据, 而在模板之外可以专注于要展示什么数据。

  没错,这就是MVC模式。Java objects充当Controller角色,Template充当Model角色,Output显然是View角色。看到熟悉的字眼Java、html标签等等,是不是让你联想到另外一项技术——JSP,为了理解,你可以把freemarker和jsp拿来比较,只是JSP是一项技术也是一项官方标准,所以知名度会更高,两项技术各有千秋,严格来说,JSP可以在文件里掺杂写java代码并不能称得上真正的MVC模式。相比来说freemarker更为干净纯洁,性能也不错。

官网http://freemarker.org/

freemarker怎么用?

其实所有内容都在freemarker手册http://freemarker.org/docs/index.html

这里主要分为以下几个部分:模板开发指南+程序开发指南+模板语言参考+XML处理指南+附录

到目前为止,看了一遍模板开发指南,这里梳理一些主要知识点:

模板 + 数据模型 = 输出

  场景:在某系统中的欢迎界面HTML页面如下:

<html>
<head>
  <title>Welcome!</title>
</head>
<body>
  <h1>Welcome John Doe!</h1>
  <p>Our latest product:
  <a href="products/greenmouse.html">green mouse</a>!
</body>
</html>

 

  freemarker思路:鉴于登录系统的不同用户会有不同的用户名,这里不能一味写死为John snow.这时候可以使用freemarker模板,加入一个指令如${user},这个user会在java中被赋值从而显示在页面上。这种处理方式更加具有MVC的思想,模板层不需要做任何改变,后台改变这个值,模板只是负责输出。

  为模板准备的数据整体被称作为 数据模型。 模板作者要关心的是,数据模型是树形结构(就像硬盘上的文件夹和文件),在视觉效果上, 数据模型可以是:

(root)
  |
  +- user = "Big Joe"
  |
  +- latestProduct
      |
      +- url = "products/greenmouse.html"
      |
      +- name = "green mouse"

  

  有了数据模型和模板,就构成了freemarker的最终页面输出

  备注:这里的数据模型可以对比理解为页面中的DOM结构,不同的数据有不同的DOM层级关系,对于数据模型的访问也类似对于DOM元素的访问。比如要访问name这个数据(节点),需要携程(root.)latestProduct.name。

模板指令

  模板可以使用一些基本指令如if指令

<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>

  

  list指令

<#list misc.fruits>
  <ul>
    <#items as fruit>
      <li>${fruit}
    </#items>
  </ul>
</#list>

  list 指令的一般格式为: <#list sequence as loopVariable>repeatThis</#list>。

  include指令

  使用 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>

  

内建函数

内建函数很像子变量(如果了解Java术语的话,也可以说像方法), 它们并不是数据模型中的东西,是 FreeMarker 在数值上添加的。 为了清晰子变量是哪部分,使用 ?(问号)代替 .(点)来访问它们。常用内建函数的示例:

  • user?html 给出 user 的HTML转义版本, 比如 & 会由 &amp; 来代替。
  • user?upper_case 给出 user 值的大写版本 (比如 "JOHN DOE" 来替代 "John Doe")
  • animal.name?cap_first 给出 animal.name 的首字母大写版本(比如 "Mouse" 来替代 "mouse")
  • user?length 给出 user 值中 字符的数量(对于 "John Doe" 来说就是8)
  • animals?size 给出 animals 序列中 项目 的个数(我们示例数据模型中是3个)
  • 如果在 <#list animals as animal> 和对应的 </#list> 标签中:
    • animal?index 给出了在 animals 中基于0开始的 animal的索引值
    • animal?counter 也像 index, 但是给出的是基于1的索引值
    • animal?item_parity 基于当前计数的奇偶性,给出字符串 "odd" 或 "even"。在给不同行着色时非常有用,比如在 <td class="${animal?item_parity}Row">中。

一些内建函数需要参数来指定行为,比如:

  • animal.protected?string("Y", "N") 基于 animal.protected 的布尔值来返回字符串 "Y" 或 "N"。
  • animal?item_cycle(‘lightRow‘,‘darkRow‘) 是之前介绍的 item_parity 更为常用的变体形式。
  • fruits?join(", ") 通过连接所有项,将列表转换为字符串, 在每个项之间插入参数分隔符(比如 "orange,banana")
  • user?starts_with("J") 根据 user 的首字母是否是 "J" 返回布尔值true或false。

内建函数应用可以链式操作,比如user?upper_case?html 会先转换用户名到大写形式,之后再进行HTML转义。(这就像可以链式使用 .(点)一样)

处理不存在的变量

  freemarker对于null的把关很严格,如果一个变量为null则会抛出异常,停止对于当前模板的编译和显示。所以对于不存在的变量的处理显得格外重要,主要有两种方式:

  1. 添加默认值设置

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

  这里表示当user变量如果不存在或为空的时候,就取默认值“visitor”显示在页面上,这里的“!”表示用于设置默认值

  2. 通过条件判断

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

  这里表示如果users存在才显示if指令里面的内容,否则跳过不执行。注意这里的"??"表示条件判断的符号

数据类型

  freemarker支持的数据类型有:

    1.标量:字符串(如"hello")+数字(如123)+布尔值(如true,false)+日期/时间(如May 15,2016)

    2.容器:哈希表(类似java中的HashMap)+序列(类似数组)+集合

    3.子程序:方法和函数+用户自定义指令

模板构成

  • 文本:文本会照着原样来输出。
  • 插值:这部分的输出会被计算的值来替换。插值由 ${ and } 所分隔(或者 #{ and },这种风格已经不建议再使用了)。
  • FTL 标签:FTL标签和HTML标签很相似,但是它们却是给FreeMarker的指示, 而且不会打印在输出内容中。
  • 注释:注释和HTML的注释也很相似,但它们是由 <#-- 和 -->来分隔的。注释会被FreeMarker直接忽略, 更不会在输出内容中显示。

  备注:FTL是区分大小写的。

     插值 仅仅可以在 文本 中使用:

      用户所犯的一个常见错误是将插值放在了不需要/不应该使用的地方。 插值  在文本区中有效。(比如, <h1>Hello ${name}!</h1>) 还有在字符串值中 (比如, <#include "/footer/${company}.html">)。 典型的 错误 使用是 <#if ${big}>...</#if>, 这会导致语法错误。简单写为 <#if big>...</#if>即可。 而且, <#if "${big}">...</#if> 也是 错误的, 因为它将参数值转换为字符串,但是 if 指令只接受布尔值, 那么这将导致运行时错误。

       注释 可以放在 FTL 标签 和 插值中。

值域

  值域表达式的通用形式是( start 和 end 可以是任意的结果为数字表达式):

  • start..end: 包含结尾的值域。比如 1..4 就是 [1, 2, 3, 4]
  • start..<end 或 start..!end: 不包含结尾的值域。比如 1..<4 就是 [1, 2, 3]
  • start..*length: 限定长度的值域,比如 10..*4 就是 [10, 11, 12, 13]

freemarker也支持算数运算(+,-,*,/,%),比较运算(==,!=),逻辑运算(||,&&,!)等

自定义指令

  自定义指令可以使用 macro 指令来定义。

  宏是有一个变量名的模板片段。可以在模板中使用宏作为自定义指令, 这样就能进行重复性的工作。例如,创建一个宏变量来输出大字号的‘‘Hello Joe!‘‘:

<#macro greet>
  <font size="+2">Hello Joe!</font>
</#macro>

  

  macro 指令自身不输出任何内容, 它只是用来创建宏变量,所以就会有一个名为 greet 的变量。在 <#macro greet> 和 </#macro> 之间的内容 (称为 宏定义体) 将会在使用该变量作为指令时执行。可以在FTL标记中通过 @代替#来使用自定义指令。 使用变量名作为指令名。而且,自定义指令的 结束标记 也是需要的。那么, 就可以这样来使用 greet

<@greet></@greet>

  或者<@greet/>

在模板中定义变量

在模板中可以定义三种类型的变量:

  • ‘‘简单‘‘变量: 它能从模板中的任何位置来访问,或者从使用 include 指令引入的模板访问。可以使用 assign 指令来创建或替换这些变量。因为宏和方法只是变量,那么 macro 指令 和 function 指令 也可以用来设置变量,就像 assign 那样。
  • 局部变量:它们只能被设置在 宏定义体内, 而且只在宏内可见。一个局部变量的生命周期只是宏的调用过程。可以使用 local指令 在宏定义体内创建或替换局部变量。
  • 循环变量:循环变量是由如 list 指令自动创建的,而且它们只在指令的开始和结束标记内有效。宏 的参数是局部变量而不是循环变量。
  • 全局变量:这是一个高级话题了, 并且这种变量最好别用。即便它们属于不同的命名空间, 全局变量也被所有模板共享,因为它们是被 import进来的, 不同于 include 进来的。那么它们的可见度就像数据模型那样。 全局变量通过 global指令来定义。

  备注:局部变量也会隐藏(不是覆盖)同名的‘‘简单‘‘变量。 循环变量也会隐藏(不是覆盖)同名的‘‘简单‘‘变量。例如:

<#assign x = "plain">
1. ${x}  <#-- we see the plain var. here -->
<@test/>
6. ${x}  <#-- the value of plain var. was not changed -->
<#list ["loop"] as x>
    7. ${x}  <#-- now the loop var. hides the plain var. -->
    <#assign x = "plain2"> <#-- replace the plain var, hiding does not mater here -->
    8. ${x}  <#-- it still hides the plain var. -->
</#list>
9. ${x}  <#-- the new value of plain var. -->

<#macro test>
  2. ${x}  <#-- we still see the plain var. here -->
  <#local x = "local">
  3. ${x}  <#-- now the local var. hides it -->
  <#list ["loop"] as x>
    4. ${x}  <#-- now the loop var. hides the local var. -->
  </#list>
  5. ${x}  <#-- now we see the local var. again -->
</#macro>

  

  输出为:

1. plain
  2. plain
  3. local
    4. loop
  5. local
6. plain
    7. loop
    8. loop
9. plain2

  

命名空间

  如果想创建可以重复使用的宏,函数和其他变量的集合, 通常用术语来说就是引用 。 使用多个命名空间是必然的。只要考虑你在一些项目中, 或者想和他人共享使用的时候,你是否有一个很大的宏的集合。 但要确保库中没有宏(或其他变量)名和数据模型中变量同名, 而且也不能和模板中引用其他库中的变量同名是不可能的。 通常来说,变量因为名称冲突时也会相互冲突。 所以要为每个库中的变量使用不同的命名空间。

  我们来建立一个简单的库。假设你需要通用的变量 copyright 和 mail (在你有疑问之前,宏 当作是 变量):

<#macro copyright date>
  <p>Copyright (C) ${date} Julia Smith. All rights reserved.</p>
</#macro>

<#assign mail = "[email protected]">

 

   把上面的这些定义存储在文件 lib/my_test.ftl 中 (目录是存放模板的位置)。假设想在 aWebPage.ftl 中使用这个模板。如果在aWebPage.ftl 中使用 <#include "/lib/my_test.ftl">, 那么就会在主命名空间中创建两个变量,这样就不是很好, 因为想让它们只在同一个命名空间‘‘My Test Library‘‘中。所以就不得不使用 import指令 来代替 include 了。乍一看,这个指令和 include 很相似,但是它会为 lib/my_test.ftl 创建一个空的命名空间,然后在那里执行。lib/my_test.ftl 会发现它自己在一个新的环境中,那里只有数据模型的变量可以找到 (因为它们在哪儿都是可见的),然后会在这个环境中创建两个变量。现在来看这很不错, 但是如果想访问aWebPage.ftl 中的两个变量, 而它们使用的是主命名空间,就不能看到其他命名空间中的变量。 解决方法是 import 指令不仅仅创建命名空间,而且要通过 import 的调用者(本例中的主命名空间)创建一个新的哈希表变量, 这就成为进入新的命名空间的大门。那么aWebPage.ftl 就像下面这样:

<#import "/lib/my_test.ftl" as my> <#-- the hash called "my" will be the "gate" -->
<@my.copyright date="1999-2002"/>
${my.mail}

  

至此,梳理了关于模板开发指南部分的知识点。

如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。

  
时间: 2024-10-11 12:49:46

FreeMarker模板开发指南知识点梳理的相关文章

freemarker 模板开发入门

数据模型 scalars标量:从根 root 开始指定它的路径,每级之间用点来分隔. 如:whatnot.fruits sequences 序列:使用数组的方括号方式来访问一个序列的子变量. 如:animals[0].name,whatnot.fruits[1] 总结: 数据模型可以被看做是树状结构的. 标量存储单一的值,这种类型的值可以是字符串,数字,日期/时间或者是布尔值. 哈希表是存储变量和与其相关且有唯一标识名称变量的容器. 序列是存储有序变量的容器.存储的变量可以通过数字索引来检索,索

1+x 证书 Web 前端开发 MySQL 知识点梳理

官方QQ群 1+x 证书 Web 前端开发 MySQL 知识点梳理 http://blog.zh66.club/index.php/archives/199/ 原文地址:https://www.cnblogs.com/zhsh666/p/11967921.html

freeMarker(八)——程序开发指南之配置(Configuration)

1.基本内容 配置(configuration)就是 freemarker.template.Configuration 对象, 它存储了常用(全局,应用程序级)的设置,定义了想要在所有模板中可用的变量(称为共享变量). 而且,它会处理 Template 实例的新建和缓存. 应用程序典型的用法是使用一个独立的共享 Configuration 实例.更精确来说, 典型的做法是每一个独立开发的组件(比如项目,模块等)都有一个 Configuration 实例,它在内部使用FreeMarker, 每一

使用express4.x版、Jade模板以及mysql重写《nodejs开发指南》微博实例

最近阅读<nodejs开发指南>一书,书是不错的,然而其微博代码示例用的是express3.x,用些过时了,运行代码出现不少bug(我电脑安的是express4.x),于是用express4.x+jade模板重写一遍(原代码使用的是ejs模板).因为想体验一下node结合MySQL开发,于是将mongodb改为mysql.下面进入正文 1.安装express框架与生成器: 2.进入网站目录,创建项目: 3.安装中间件与依赖项: package.json如下 单独安装时记得加上--save,便于

ECMALL模板解析机制.MVC架构分析及文件目录说明.二次开发指南手册(转)

ECMALL模板解析语法与机制 http://www.nowamagic.net/architecture/archt_TemplateSyntaxAndAnalysis.php ECMALL模块开发指南 http://wenku.baidu.com/view/785b8a1ea76e58fafab003a6.html ECMall 结构图 http://wenku.baidu.com/view/3e9d9921bcd126fff7050b10.html ECMall 数据库表结构 全面讲解 h

开发指南专题专题一: JEECG微云快速开发平台前言

JEECG微云快速开发平台-前言 1. 前言 1.1. 技术背景 随着WEB UI 框架(EasyUI/Jquery UI/Ext/DWZ)等的逐渐成熟,系统界面逐渐实现统一化,代码生成器也可以生成统一规范的界面! 代码生成+手工MERGE半智能开发将是新的趋势,生成的代码可节省50%工作量,快速提高开发效率! 1.2. 平台介绍 JEECG [J2EE  Code Generation] 是一款基于代码生成器的微信快速开发平台,采用代码生成+手工MERGE半智能开发模式, 可以帮助解决Java

Freemaker_入门+深入+开发指南+学习笔记

freemaker的基本语法 freemaker的基本语法:<# ... > 中存放所有freemaker的内容,之外的内容全部原样输出.<@ ... /> 是函数调用两个定界符内的内容中,第一个符号表示指令或者函数名,其后的跟随参数.freemaker提供的控制包括如下: <#if condition><#elseif condition><#else></#if> 条件判断<#list hash_or_seq as var&

开发指南专题五:JEECG微云快速开发平台代码生成器

开发指南专题五:JEECG微云快速开发平台代码生成器 1.1. Maven开发环境搭建 在搭建jeecg的maven开发环境之前,需要先配置好本机的maven环境,并在eclipse中安装好m2eclipse插件. 1. maven版本的工程目录,代码结构如图311所示. 2. 针对本机开发环境(这里以eclipse为例),调整依赖包和项目属性 首先在工程上右键->properties,在builders选项卡中删除掉不存在或不需要的builders,如图312所示. 然后进入Java Bu

开发指南专题五:JEECG微云高速开发平台代码生成器

开发指南专题五:JEECG微云高速开发平台代码生成器 1.1. Maven开发环境搭建 在搭建jeecg的maven开发环境之前,须要先配置好本机的maven环境,并在eclipse中安装好m2eclipse插件. 1. maven版本号的project文件夹,代码结构如图311所看到的. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhhbmdkYWlzY290dA==/font/5a6L5L2T/fontsize/400/fill/I0JBQ