zoukankan      html  css  js  c++  java
  • FreeMarker

    https://baike.baidu.com/item/freemarker
     
    FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页、电子邮件配置文件源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。
    FreeMarker是免费的,基于Apache许可证2.0版本发布。其模板编写为FreeMarker Template Language(FTL),属于简单、专用的语言。需要准备数据在真实编程语言中来显示,比如数据库查询和业务运算, 之后模板显示已经准备好的数据。在模板中,主要用于如何展现数据, 而在模板之外注意于要展示什么数据 [1]  。

    发展历史

    编辑
    LOGOLOGO
    FreeMarker最初的设计,是被用来在MVC模式的Web开发框架中生成HTML页面的,没有被绑定到Servlet或HTML或任意Web相关的东西上,它也可以用于非Web应用环境中。
    1999年末,FreeMarker的第一个版本出现在SourceForge网站上,它最初是由Benjamin Geer和Mike Bayer编写,他们定义了FreeMarker最基本的语法。FreeMarker 1获得了LGPL(宽通用公共许可证)的许可,其版权归属于Benjamin Geer。此外,Nicholas Cull、Holger Arendt等人对该项目也做出了主要贡献。
    在2002年初,Jonathan Revusky用JavaCC重写了FreeMarker的核心代码(语法编译),虽然对FreeMarker 1尽量做到向后兼容,但几乎是完全重写了。Attila Szegedi对FreeMarker 2也有重要影响,除了重构和优化一些核心的API应用程序编程接口),Attila还作为主要编写者实现了FreeMarker对日期、时间的支持,写出的freemarker.ext*包完成对javabeanJythonXML的映射,以及HTTP servletJSP和Ant的集成。Dániel Dékány主要负责文档以及项目的维护(截至2011年,Dániel Dékány仍是该项目的主要维护者) [2]  。
    2002年3月18日,FreeMarker的第一个发布候选版2.0 RC1发布 [3]  ,又经过了2个候选版的BUG修复之后,正式版的Free Marker2.0于2002年4月18日发布 [4]  。2002年10月17日,FreeMarker 2.1 发布,该版本并不能与2.0版本兼容,所以使用者如果不是新建工程的话,需要重新审视已有的代码和模版 [5]  。
    由于项目没有法律实体,FreeMarker的2.0.x和2.1.x的版权仍归属Benjamin Geer。而在2002年12月制作2.2版本时,Benjamin Geer出于对自由开源许可的理解,将代码库版权转给Visigoth Software Society(西班牙的一个非营利性软件协会)和共同创办人Jonathan Revusky [2]  。
    2003年3月27日,FreeMarker 2.2 发布,这个版本引入了一些非常重要的新特性,但是有一些功能却不能逆向兼容 [6]  。在2.2的版本中,可能最重要的新特性就是namespace支持,这使得FreeMarker成为了合适大规模项目的工具,因为它允许不同页面分享的变量没有任何名称空间冲突。同时,宏也变得更加强大,因为他们可以调用可选目标,并且宏现作为一流的变量,可以传递给其他宏使用。此外2.2中另一个吸引人的特性为,FreeMarker可以利用由第三方所写的JSP标记库 [7]  。在此之后,2.3版本之前,共更新了8个版本 [6]  。
    2004年6月15日,FreeMarker 2.3 发布,此版本对2.2系列进行了质量上的改进,以及引入了大量的新功能。最主要的改进点在于可以定义函数(方法)模版,插入字符串变量,支持宏参数和更为智能的默认对象包装。但2.3并不支持2.2.x的向后兼容,所以仅供新项目使用 [8]  。
    2005年1月4日的2.3.1版本到10月10日2.3.4版本主要是编写和维护一些新特性,以及BUG错误修复。2006年3月11日发布的2.3.5版本,因为发现严重错误而被撤回 [9]  ,在后续的2.3.6版本中修复。2.3.7时出了一个测试版本用于BUG修正和FreemarkerServlet的改进,其正式版中新增substring用于处理空的或缺失的变量 [10]  。
    模板引擎的执行流程模板引擎的执行流程
    2006年7月9日发布2.3.8版本,提高了对JSP 2.0的兼容性 [11]  。
    2007年1月23日发布2.3.9版本,包含了对JDK 1.5枚举和通过BeansWrapper公共类字段的支持 [12] 。
    2007年4月20的2.3.10版本到2009年12月10日的2.3.16版本都是一些小性能改进和BUG修复。
    2011年5月17日,FreeMarker 2.3.17 发布,该版本主要进行了安全性的修复并扩充了一些内建函数[13]  。
    2011年5月22日,FreeMarker 2.3.18 发布,修复jar包相关的bug [14]  。
    2012年2月29日,FreeMarker 2.3.19 发布,该版本修复了两个重要的bug,另外新增对JSON字符串进行处理的方法json_string等小改动 [15]  。
    2013年6月27日,FreeMarker 2.3.20 发布,主要对于使用IDE工具的修改 [16]  。
    2014年10月12日,FreeMarker 2.3.21 发布,对Java版本的最低要求从1.2变为1.4。由于旧的BSD风格许可不被OSI所承认,且Visigoth Software Society停滞不前,其许可变更为Apache 2.0版,所有者转为Attila Szegedi、Daniel Dekany和Jonathan Revusky(FreeMarker 2的主要开发者) [2]  。
    2015年3月1日,FreeMarker 2.3.22 发布,在FTL模板和Java方面做了一些更改 [17]  。
    2015年7月1日,FreeMarker经过投票进入了Apache Incubator,其项目授予给Apache软件基金会 [2]  。
    2015年7月5日,FreeMarker 2.3.23 发布,在FTL模板和Java上做了大量修改。尤其增加了list中items和else的字指令,使常见遍历任务更简单 [18]  。
    2015年9月2日,FreeMarker的主代码库从GitHub导入到Apache软件基金会的基础设施中发展 [2]  。
    2018年3月21日,FreeMarker在Apache Incubator中升级为顶级项目 [2]  。

    工作原理

    编辑
    假设在一个应用系统中需要一个HTML页面如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <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>
    页面中的用户名(即上面的“Big Joe”)是登录这个网页的访问者的名字, 并且最新产品的数据应该来自于数据库才能随时更新。所以,不能直接在HTML页面中输入“Big Joe”、“greenmouse”及链接, 不能使用静态HTML代码。可以使用要求输出的模板来解决,模板和静态页面是相同的,只是它会包含一些FreeMarker将它们变成动态内容的指令:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <html>
        <head>
            <title>Welcome!</title>
        </head>
        <body>
            <h1>Welcome ${user}!</h1>
            <p>Our latest product:
            <a href="${latestProduct.url}">${latestProduct.name}</a>!
        </body>
    </html>
    模板文件存放在Web服务器上,当有人来访问这个页面,FreeMarker就会介入执行,然后动态转换模板,用最新的数据内容替换模板中${...}的部分,之后将结果发送到访问者的Web浏览器中。访问者的Web浏览器就会接收到例如第一个HTML示例那样的内容(也就是没有FreeMarker指令的HTML代码),访问者也不会察觉到服务器端使用的FreeMarker。(存储在Web服务器端的模板文件是不会被修改的;替换也仅仅出现在Web服务器的响应中。)
    为模板准备的数据整体被称作为数据模型。数据模型是树形结构(就像硬盘上的文件夹和文件),在视觉效果上, 数据模型可以是(这只是一个形象化显示,数据模型不是文本格式,它来自于Java对象):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    (root)
      |
      +- user = "Big Joe"
      |
      +- latestProduct
          |
          +- url = "products/greenmouse.html"
          |
          +- name = "green mouse"
    早期版本中,可以从数据模型中选取这些值,使用user和latestProduct.name表达式即可。类比于硬盘的树形结构,数据模型就像一个文件系统,“(root)”和latestProduct就对应着目录(文件夹),而user、url和name就是这些目录中的文件。
    总体上,模板和数据模型是FreeMarker来生成输出所必须的组成部分:模板 + 数据模型 = 输出 [19]  。

    基本语法

    编辑
    • ${...}:FreeMarker将会输出真实的值来替换大括号内的表达式,这样的表达式被称为interpolation(插值)。
    • 注释:注释和HTML的注释也很相似,但是它们使用<#-- and -->来标识。不像HTML注释那样,FTL注释不会出现在输出中(不出现在访问者的页面中),因为FreeMarker会跳过它们。
    • FTL标签(FreeMarker模板的语言标签):FTL标签和HTML标签有一些相似之处,但是它们是FreeMarker的指令,是不会在输出中打印的。这些标签的名字以#开头。(用户自定义的FTL标签则需要使用@来代替#) [20] 

    指令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <#if condition>
        ...
    <#elseif condition2>
        ...
    <#elseif condition3>
        ...
    <#else>
        ...
    </#if>
    if、elseif和else指令可以用来条件判断是否越过模板的一个部分。condition必须计算成布尔值,否则错误将会中止模板处理。elseif和else必须出现在if内部(也就是在if的开始标签和结束标签之间)。if中可以包含任意数量的elseif(包括0个),而结束时else也是可选的 [21]  。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    假设 users 包含['Joe''Kate''Fred'] 序列:
    <#list users as user>
        <p>${user}
    </#list>
     
    输出:
        <p>Joe
        <p>Kate
        <p>Fred
    list指令执行在list开始标签和list结束标签(list中间的部分)之间的代码,对于在序列(或集合)中每个值指定为它的第一个参数。对于每次迭代,循环变量将会存储当前项的值。循环变量仅仅存在于list标签体内。而且从循环中调用的/函数不会看到它(就像它只是局部变量一样)。<#list>与<#else>、<#sep>组合是可选的,而且仅从FreeMarker 2.3.23版本开始支持 [22]  。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    将版权信息单独存放在页面文件 copyright_footer.html 中:
    <hr>
    <i>
        Copyright (c) 2000 <a href="http://www.baidu.com">Baidu 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>
    include可以在模板中插入另外一个FreeMarker模板文件(由路径参数指定)。被包含模板的输出格式是在include标签出现的位置插入的。被包含的文件和包含它的模板共享变量,就像是被复制粘贴进去的一样。include指令不能由被包含文件的内容所替代,它只是当FreeMarker每次在模板处理期间到达include指令时处理被包含的文件。所以对于如果include在list循环之中的例子,可以为每个循环周期内指定不同的文件名 [23]  。

    内建函数

    常用处理常用处理
    内建函数很像子变量(也像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序列中项目的个数
    • 如果在<#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转义,和链式使用.(点)一样 [20]  。

    空变量

    数据模型中经常会有可选的变量(有时并不存在)。除了一些人为原因导致失误外,FreeMarker不能引用不存在的变量,除非明确地告诉它当变量不存在时如何处理,如下两种典型的处理方法:
    这部分对程序员而言:一个不存在的变量和一个是null值的变量,对于FreeMarker来说是一样的,所以这里所指的“丢失”包含这两种情况。
    不论在哪里引用变量,都可以指定一个默认值来避免变量丢失这种情况,通过在变量名后面跟着一个 !(感叹号)和默认值。像下面的这个例子,当user不存在于数据模型时,模板将会将user的值表示为字符串 “visitor”。(当 user 存在时,模板就会表现出 ${user} 的值):
    1
    <h1>Welcome ${user!"visitor"}!</h1>
    也可以在变量名后面通过放置??来询问一个变量是否存在。将它和if指令合并,那么如果user变量不存在的话将会忽略整个问候的代码段:
    1
    2
    3
    <#if user??>
        <h1>Welcome ${user}!</h1>
    </#if>
    关于多级访问的变量,比如 animals.python.price,书写代码:animals.python.price!0当且仅当animals.python永远存在,而仅仅最后一个子变量price可能不存在时是正确的(这种情况下假设价格是0)。如果 animals或python不存在,那么模板处理过程将会以“未定义的变量”错误而停止。为了防止这种情况的发生, 可以如下这样来编写代码 (animals.python.price)!0。这种情况就是说animals或python不存在时,表达式的结果是 0。对于??也是同样用来的处理这种逻辑的;将animals.python.price??对比(animals.python.price)??来看 [20]  。

    性能特点

    编辑
    模板并没有包含程序逻辑来查找当前的访问者是谁,或者去查询数据库获取最新的产品。显示的数据是在FreeMarker之外准备的,通常是一些“真正的”编程语言(比如Java)所编写的代码。模板作者无需知道这些值是如何计算出的。事实上,这些值的计算方式可以完全被修改,而模板可以保持不变,而且页面的样式也可以完全被修改而无需改动模板。当模板作者(设计师)和程序员不是同一人时,显示逻辑和业务逻辑相分离的做法是非常有用的,即便模板作者和程序员是一个人,这么来做也会帮助管理应用程序的复杂性。保证模板专注于显示问题(视觉设计,布局和格式化)是高效使用模板引擎的关键 [19]  。
    MyEclipse工具下的编辑界面MyEclipse工具下的编辑界面
    1. 通用性
      能够生成各种文本:HTMLXMLRTF、Java源代码等等。
      易于嵌入到产品中:轻量级;不需要Servlet环境。
      插件式模板载入器:可以从任何源载入模板,如本地文件、数据库等等。
      可以按所需生成文本:保存到本地文件;作为Email发送;从Web应用程序发送它返回给Web浏览器。
    2. 模板语言
      所有常用的指令:include、if/elseif/else、循环结构
      在模板中创建和改变变量。
      几乎在任何地方都可以使用复杂表达式来指定值。
      命名的宏,可以具有位置参数和嵌套内容。
      名字空间有助于建立和维护可重用的宏库,或者将一个大工程分成模块,而不必担心名字冲突。
      输出转换块:在嵌套模板片段生成输出时,转换HTML转义、压缩、语法高亮等等;可以定义自己的转换。
    3. 通用数据模型
      FreeMarker不是直接反射到Java对象,Java对象通过插件式对象封装,以变量方式在模板中显示。
      可以使用抽象(接口)方式表示对象(JavaBeanXML文档、SQL查询结果集等等),告诉模板开发者使用。方法,使其不受技术细节的打扰。
    xml配置xml配置
    4. 为Web准备
      在模板语言中内建处理典型Web相关任务(如HTML转义)的结构。
      能够集成到Model2 Web应用框架中作为JSP的替代。
      支持JSP标记库。
      为MVC模式设计:分离可视化设计和应用程序逻辑;分离页面设计员和程序员。
    5. 智能的国际化和本地化
      字符集智能化(内部使用UNICODE)。
      数字格式本地化敏感。
      日期和时间格式本地化敏感。
      非US字符集可以用作标识(如变量名)。
      多种不同语言的相同模板。
    6. XML处理能力
      <#recurse> 和<#visit>指令(2.3版本)用于递归遍历XML树。
      在模板中清楚和直接的访问XML对象模型 [24]  。

    评价

    编辑
    在所有采用网页静态化手段的网站中,FreeMarker使用的比例大大的超过了其他的一些技术。HTML静态化也是某些缓存策略使用的手段,对于系统中频繁使用数据库查询但是内容更新很小的应用,可以使用FreeMarker将HTML静态化。比如一些网站的公用设置信息,这些信息基本都是可以通过后台来管理并存储在数据库中,这些信息其实会大量的被前台程序调用,每一次调用都会去查询一次数据库,但是这些信息的更新频率又会很小,因此也可以考虑将这部分内容进行后台更新的时候进行静态化,这样就避免了大量的数据库访问请求,从而也就提高了网站的性能 [25]  。
    JSP相比,FreeMarker的一个优点在于不能轻易突破模板语言开始编写Java代码,因此降低了领域逻辑漏进视图层的危险几率。但缺点是需要一点附加配置来将其平稳地集成到应用程序中,一些IDE(集成开发环境)可能并不完全支持它,当然还有开发者或设计者也许需要学习一门陌生的模板语言。相关的JAR文件将要添加到WEB-INF/lib(在需要的时候,它们包含在Spring中) [26]  。
  • 相关阅读:
    Ubuntu16.04 + OpenCV源码 + Qt5.10 安装、配置
    DML和DQL
    初识MySql
    表单校验
    使用jQuery操作DOM
    jQuery中的事件与动画
    jQuery选择器
    初识jQuery
    JavaScript对象及初识OOP
    JavaScript操作DOM对象
  • 原文地址:https://www.cnblogs.com/linus-tan/p/11022335.html
Copyright © 2011-2022 走看看