ftl_ftl input 默认值 - CSDN
精华内容
参与话题
  • FTL 入门

    千次阅读 2018-12-05 18:09:58
    项目中不用jsp了,开始使用ftl,故找来相关文章以供学习 1.概念 FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具。 它不是...

    项目中不用jsp了,开始使用ftl,故找来相关文章以供学习
    1.概念
    FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具。
    它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。

    FreeMarker是免费的,基于Apache许可证2.0版本发布。
    其模板编写为FreeMarker Template Language(FTL),属于简单、专用的语言。需要准备数据在真实编程语言中来显示,比如数据库查询和业务运算, 之后模板显示已经准备好的数据。
    在模板中,主要用于如何展现数据, 而在模板之外注意于要展示什么数据。

    与JSP相比,FreeMarker的一个优点在于不能轻易突破模板语言开始编写Java代码,因此降低了领域逻辑漏进视图层的危险几率。
    但缺点是需要一点附加配置来将其平稳地集成到应用程序中,一些IDE(集成开发环境)可能并不完全支持它,当然还有开发者或设计者也许需要学习一门陌生的模板语言。
    相关的JAR文件将要添加到WEB-INF/lib(在需要的时候,它们包含在Spring中)。

    2.原理说明
    2.1 举例
    假设在一个应用系统中需要一个HTML页面如下:

    Welcome!

    Welcome Big Joe!

    Our latest product: green mouse!

    页面中的用户名(即上面的“Big Joe”)是登录这个网页的访问者的名字, 并且最新产品的数据应该来自于数据库才能随时更新。 所以,不能直接在HTML页面中输入“Big Joe”、“greenmouse”及链接, 不能使用静态HTML代码。

    可以使用要求输出的模板来解决,模板和静态页面是相同的,只是它会包含一些FreeMarker将它们变成动态内容的指令:

    Welcome!

    Welcome ${user}!

    Our latest product: ${latestProduct.name}!

    2.2 原理
    模板文件存放在Web服务器上,当有人来访问这个页面,FreeMarker就会介入执行,然后动态转换模板,用最新的数据内容替换模板中${…}的部分,之后将结果发送到访问者的Web浏览器中。
    访问者的Web浏览器就会接收到例如第一个HTML示例那样的内容(也就是没有FreeMarker指令的HTML代码),访问者也不会察觉到服务器端使用的FreeMarker。
    PS:存储在Web服务器端的模板文件是不会被修改的;替换也仅仅出现在Web服务器的响应中。
    (root)
    |
    ± user = “Big Joe”
    |
    ± latestProduct
    |
    ± url = “products/greenmouse.html”
    |
    ± name = “green mouse”

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

    3.2指令详解
    3.2.1 if else
    <#if condition>

    <#elseif condition2>

    <#elseif condition3>

    <#else>

    </#if>
    if、elseif和else指令可以用来条件判断是否越过模板的一个部分。
    condition必须计算成布尔值,否则错误将会中止模板处理。
    elseif和else必须出现在if内部(也就是在if的开始标签和结束标签之间)。
    if中可以包含任意数量的elseif(包括0个),而结束时else也是可选的。

    3.2.2 list
    假设 users 包含[‘Joe’, ‘Kate’, ‘Fred’] 序列:
    <#list users as user>

    ${user}
    </#list>

    输出:

    Joe

    Kate

    Fred
    list指令执行在list开始标签和list结束标签(list中间的部分)之间的代码,对于在序列(或集合)中每个值指定为它的第一个参数。
    对于每次迭代,循环变量将会存储当前项的值。循环变量仅仅存在于list标签体内。
    而且从循环中调用的宏/函数不会看到它(就像它只是局部变量一样)。
    <#list>与<#else>、<#sep>组合是可选的,而且仅从FreeMarker 2.3.23版本开始支持。

    3.2.3 include
    将版权信息单独存放在页面文件 copyright_footer.html 中:


    Copyright (c) 2000 Baidu Inc,
    All Rights Reserved.

    当需要用到这个文件时,可以使用 include 指令来插入:

    Test page

    Test page

    Blah blah... <#include "/copyright_footer.html">

    include可以在模板中插入另外一个FreeMarker模板文件(由路径参数指定)。 被包含模板的输出格式是在include标签出现的位置插入的。被包含的文件和包含它的模板共享变量,就像是被复制粘贴进去的一样。 include指令不能由被包含文件的内容所替代,它只是当FreeMarker每次在模板处理期间到达include指令时处理被包含的文件。 所以对于如果include在list循环之中的例子,可以为每个循环周期内指定不同的文件名。

    3.3 内建函数

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

    常用内建函数的示例:
    user?html给出user的HTML转义版本,比如&会由&来代替。
    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”。
    在给不同行着色时非常有用,比如在中。

    一些内建函数需要参数来指定行为,比如:
    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转义,和链式使用.(点)一样。

    3.4 空变量
    数据模型中经常会有可选的变量(有时并不存在)。
    除了一些人为原因导致失误外,FreeMarker不能引用不存在的变量,除非明确地告诉它当变量不存在时如何处理。

    如下两种典型的处理方法:
    这部分对程序员而言:一个不存在的变量和一个是null值的变量,对于FreeMarker来说是一样的,所以这里所指的“丢失”包含这两种情况。
    不论在哪里引用变量,都可以指定一个默认值来避免变量丢失这种情况,通过在变量名后面跟着一个 !(感叹号)和默认值。

    像下面的这个例子,当user不存在于数据模型时,模板将会将user的值表示为字符串 “visitor”。(当 user 存在时,模板就会表现出 ${user} 的值):

    Welcome ${user!"visitor"}!

    也可以在变量名后面通过放置??来询问一个变量是否存在。将它和if指令合并,那么如果user变量不存在的话将会忽略整个问候的代码段:

    <#if user??>

    Welcome ${user}!


    </#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)??来看。

    展开全文
  • FTL详细资料

    千次阅读 2018-09-04 17:10:58
    FTL产生过程 如果仅仅是SSD的使用者,一定不会在意在SSD内部居然还存在一个复杂的软件层Flash Translation Layer(FTL)。其实就是这个FTL才是SSD固态硬盘的软件核心技术。正因为有了FTL,NAND Flash才能被当成硬盘...

    FTL产生过程

    如果仅仅是SSD的使用者,一定不会在意在SSD内部居然还存在一个复杂的软件层Flash Translation Layer(FTL)。其实就是这个FTL才是SSD固态硬盘的软件核心技术。正因为有了FTL,NAND Flash才能被当成硬盘来使用;文件系统才可以直接把SSD当成普通块设备来使用。由于FTL是SSD设计厂商最为重要的核心技术,因此,没有一家厂商愿意透露这方面的技术信息,并且也一直没有业内的技术规范、标准存在。

    FTL的重要程度在于决定了一个SSD的使用寿命、性能和可靠性。一旦FTL出现问题,那么就会导致数据读写发生错误,更为严重的是SSD盘无法被访问。优秀的FTL不仅能够提升Flash存储的使用寿命,而且还可以最优化读写性能。因此,在Flash固态存储中,FTL是一个最为重要的管理NAND Flash的软件层。

    在学术界,这十年来有很多文章在讨论如果实现一个高效的FTL,例如,在有限硬件资源的环境下如何实现mapping?如何实现buffer的管理?如何实现高效的Garbage Collection?如何实现磨损均衡Wear-leveling?如何实现NAND Flash芯片之间的数据冗余(RAID on Chip)?很多算法的提出非常具有建设性和现实意义,对工业界具有很好的指导价值。

    这里主要想谈一下FTL内部mapping的机制。从文章《采用NAND Flash设计存储设备的挑战在哪里?》了解到基于NAND Flash研制存储设备是有很多挑战的,最大的问题在于NAND Flash不能像内存那样随意的写入。NAND Flash在Page页写入之前必须要将Page页所在的Block块擦除。如果研制SSD的时候严格按照这个准则,那么设计开发出来的SSD是不能用的。其一,按照这种方式进行写操作,写入的性能将会很差,其bottleneck限制在块擦除上(块擦除时间在ms级);其二,不断的对同一Block块进行擦除操作,那么该块将会在短时间内磨损写坏,并且极易导致存储在该块上的数据丢失。因此,在设计SSD时最主要的任务就是解决NAND Flash的这种“写时擦除”问题。

    技术是相通的,在90年代提出的Log-structured File System(LFS)思想和NAND Flash简直是天生一对。当初设计Log-Structured File System最主要的想法是利用机械磁盘出色的顺序写性能,避免糟糕的随机写问题。Log-structured File System在机械硬盘的时代有一定的应用局限性,问题在于采用log数据布局的方式之后,读性能变得很差。因此,只有在大块数据读写(对象存储)的环境下,log-structured File System才变得合情合理。在NAND Flash介质上,不存在机械硬盘随机读写的问题,因此,log-structured的数据布局方式不会引入任何性能问题,反而能够解决NAND Flash的“写时擦除”问题。

    采用Log-structured的方式之后,NAND Flash可以采用out-of-place的数据更新方式。所有的数据更新都不会写入原来的page页,而是重映射写入一个新的Page页。在这个思路的引导,很显然所有NAND Flash的存储资源可以按照物理Page页的方式管理起来,而用户可见的空间则是一个连续逻辑Page页连接起来的地址空间。FTL的一个关键任务就是建立逻辑Page和物理Page之间的映射关系,并且在数据写入时重新分配物理Page页。在这种机制的支撑下,SSD的写性能可以大为提高,写延迟可以控制在200us的级别。

    引入log-structured的机制之后,逻辑page和物理page之间存在映射关系,FTL负责物理page页的分配。考虑到每个Block块都是有擦除寿命的,因此,如果想要提升SSD的整体使用寿命,那么需要将块擦除次数均衡到所有块上去。这个工作就交给了FTL中的块分配器。均衡擦除次数这个工作其实是挺麻烦的事情,其最大的挑战在于记录每个块的擦写次数,并且这些信息需要持久化存储。

    众所周知,log-structured数据布局方式最大的问题在于垃圾回收(garbage collection),由于page页从来不会被in-place-update,因此,当一个page被重映射之后,老的page页就会变成无效,等待Garbage Collection回收该页。在NAND Flash中,GC最大的挑战在于以块为单元进行擦除,而不是Page页。换句话说,GC需要将一个Block块中的所有Page页同时回收,这个限制导致GC在回收一个Block的时候会进行数据迁移操作。过多的数据迁移操作会影响SSD的使用寿命,并且会影响到整体的读写性能。因此,优化Garbage Collection成了FTL最头疼的一个问题。最容易想到的一个优化方法是将冷热数据分开存储到不同的Block块中,这样在数据回收的时候,可以尽最大可能减少有效数据的迁移。

    Log-structured File System为NAND Flash的FTL设计提供了一个非常好的思路。但是,要想在SSD这样一个硬件资源非常有限的平台上实现FTL的所有功能还是很有挑战的。举个例子,log-structured的方式是需要进行Page页映射的,映射操作需要建立映射表。如果内存太小,那么对映射表的大小就提出了需求。假设一个SSD具有1TB的容量,那么如果采用4KB Page映射的方式,每个page映射需要4字节描述,那么至少需要1GB的内存容量来存放映射表。在嵌入式系统中,1GB的内存容量是庞大的。因此,为了避免过多的占用内存容量,拍脑袋可以想到Block映射的方式。假设一个Block容纳128个Page页,那么一下子可以将映射表容量缩减到原来的1/128。但是这种Block映射的方式效率实在太低,会导致大量的数据迁移,从而缩短了SSD的使用寿命。

    A. LBA和PBA究竟是对应page还是block?

    解答:如果我们把LBA和PBA都设置成page大小,这也叫做page-level mapping,这和我们写入颗粒一致,很灵活。但这么小的粒度会带来一个问题:逻辑对应表太大!想象一下,我们有个64GB的Die,每个page只有4KB,我们的对应表需要64*1024*1024 * 4 /4 = 64MB!这个绝对不能接受。那么按照block,也就是block-level mapping呢? 会不会好些呢?至少占用空间好了很多,但是因为写入时不清楚page情况,往往要整块擦除,效能会大大下降。有没有更好的办法呢?实际使用中常用的是log-block mapping,它从我们现代的log文件系统中学到经验,也充分利用了page和block的不同特性。

    所以,为了减小映射表的容量,一个比较可行的方式是采用Hybrid映射方式。

    Hybrid-level mapping的思想是将映射操作分成两级。第一级是data-log,所有数据首先写入log,当log写满之后,再将log中的数据合并至data-block;第二级是data-block,用来存放从log中合并过来的数据。对于data-log,由于数量有限,因此可以采用page-level mapping的方式;对于data-block,由于存储容量比较大,因此,可以采用block-level mapping的方式。Hybrid-level mapping可以很好的平衡内存使用和mapping效率之间关系,因此,学术界也对此提出了很多优化的方法。

    wKiom1OfBEji-swLAAEWz_4dq3Y721.jpg

    其中,一个比较有意思的方法是locality aware的hybrid-level mapping思想,其原理如上图所示。从结构上讲,其大致可以分成传统Hybrid-level mapping的双层结构。写入的数据首先进入data-log。不同的地方是,data-log被分成了random-log-buffer和sequential-log-buffer。写入的数据根据locality-detector被分流至random-log-buffer或者sequential-log-buffer。其中random-log-buffer采用page页映射的方式,sequential-log-buffer直接采用block映射的方法,这样可以进一步降低内存使用量。当log-buffer中的数据满了之后,需要合并到data-block。合并的方法和传统的相同,被分成switch、partial-merge和full-merge。

    FTL是NAND Flash存储的底层核心技术之一,由于NAND Flash本身存在很多问题,导致FTL的设计、实现都会存在很多的挑战。上面只是简单的阐述了一下FTL中mapping的一些棘手问题和一些解决思路,抛砖引玉,揭开了神秘面纱,往里面瞅上了一眼。这一看其实会发现,FTL虽小,但是难度丝毫不比一个文件系统小。


    FTL详细介绍

    和传统磁盘相比,Nand Flash存储设备存储延迟低、功耗低、更高的存储密度、抗震型号更好和噪声低。但是,由于Nand Flash的特性影响(读写擦的单位不一致,每个块有P/E次数限制),Nand Flash不能直接通过简单的接口转换就拿来使用。所以我们需要在Nand Flash上增加一个管理软件FTL(Flash Translation Layer)进行管理,对外就是一个黑盒子,上层应用可以通过逻辑地址来对这个黑盒子进行访问。

    图1

    如上图,上层应用通过逻辑地址来访问存储设备,FTL把不同的逻辑地址映射到Nand Flash中的不同位置,FTL简单来说,主要就是映射管理。

    固态存储相对于传统磁盘的一些特点:

    1. 异处更新(out-of-place Update)。正如之前所说,Nand Flash编程操作只能把存储单元从1变为0,所以在重新编程之前需要进行擦除操作。而且编程以页为单位,擦除以块为单位(一个块包括多个页)。如果使用同处更新(in-place update),就是把同逻辑地址重复更新到同样的位置上,那么每一次更新,都需要先进行一次擦除操作。由于擦除操作耗费时间和对Flash有损伤,所以一般FTL使用异处更新,把更新的数据映射到一个新的位置上。

      如下图,上层应用先写逻辑地址0、1,FTL把数据映射到Nand Flash的物理块0、1页上,然后上层应用又写逻辑地址0,此时物理块0第0页不能重新编程,所以FTL把数据存放在物理块0的第2页上。

      图2

    2. P/E次数有限制。之前有提到,Nand Flash每个块是有擦除次数限制的,在擦除一定次数后,这个块会变得不稳定,编程进去的数据容易出错,甚至会擦除失败。

    3. 性能更好。和传统机械硬盘不同,Flash存储是没有机械设备的,比如说不需要寻道,对所有的地址访问开销都一样,特别是在随机读性能上,SSD远远好于传统机械硬盘。按这个道理,Flash设备随机访问和顺序访问的速度是一样,但现实上,Flash支持Cache操作,在顺序访问中可以提前把下一个页的数据读取放到内部寄存器中,可以更快响应读请求。所以在顺序访问上速度要比随机访问要快的。

    4. 读、写速度不一致。如之前文章描述的,把电子从浮动门中吸进去(写操作)比检测浮动门电场状态(读操作)要耗时。所以FTL在管理时,尽量减少写和擦除的操作。

    FTL功能

    1. 地址映射管理。闪存设备对外是一个黑盒子,里面集成了Nand Flash和FTL等,上层应用使用逻辑地址来访问,FTL把逻辑地址映射到不同物理地址上,管理着每个逻辑地址最新的数据存放的物理位置,如图1。
    2. 垃圾回收。随着数据的写入,闪存设备上有些块的部分数据已经无效了,需要把有效的数据从块上搬走,然后擦除用来接收新的数据。
    3. 磨损均衡和坏块管理。因为每个块的P/E次数是有限的,某些块可能被重复使用而损坏了,而有些块数据很少被访问,所以一直没有进行操作过。为了避免这种情况,FTL加入磨损均衡的功能,大致是通过控制垃圾回收和空块池的管理,从而平衡每个块的使用次数,最理想是所有块一起达到磨损阈值。
      由于Flash本身就存在部分坏块,在使用的过程中部分块会变坏,所以FTL在管理的时候需要避开这些无用块,把使用后变得不稳定块上的数据及时拷贝到稳定位置。

    FTL研发关注点

    1. 映射管理性能。映射分为两种:逻辑地址到物理地址映射,成为直接映射;物理地址到逻辑地址映射,称为逆映射。大部分时候使用的都是直接映射,直接映射可以可能保存在SRAM中,也可能存放在Flash中。逆映射需要通过扫描Flash来建立映射关系,因为逆映射关系存放在Flash页的冗余空间中。可见,映射关系存放在SRAM中时获取对应关系速度是最快的,但由于SRAM资源比较紧张,所以会把所有映射关系存放在Flash中,软件只会加载使用的那段映射关系。逆映射需要扫描Flash来建立映射关系,所以速度最慢,一般用于特殊情况映射关系的恢复,比如说操作过程中断电了,或者某张映射表格所在的物理页坏了,需要重建。
      映射影响着我们数据的存放,比如说需要区分顺序数据和随机数据,随机数据可能区分为热数据、冷数据。如果把热数据和冷数据存放在同一个块中,由于热数据更新频繁,导致物理块有效页利用率不高,把此块进行垃圾回收时,要把其中冷数据有效页拷贝到其它地方,导致写放大。如果冷热数据区分开,可以避免在垃圾回收中回收到冷数据。
      映射管理是FTL中最重要的一点。
    2. 垃圾回收效率。垃圾回收需要考虑到冷热数据、磨损平衡和读写延迟。回收过程中把热数据和冷数据混合在一个块中,会导致冷数据的频繁读、写,加剧Flash损耗和影响性能。而且,热数据会被经常更新,在垃圾回收流程中应该避免回收热数据块。所以垃圾回收流程,需要综合考虑几大方面。
    3. 读写延迟。 读写延迟主要是指上层应用发送读写指令,设备处理、回复数据的时间。理想情况是,收到指令,软件在RAM中找到映射关系,返回数据。事实上影响的因素很多,比如说存在后台操作,在指令执行中间,软件可能进行垃圾回收,不能及时响应命令,如果垃圾回收流程控制不好,会造成上面这种情况,写速度波动很大,给人感觉就是在打CS,时而流畅,时而卡顿。
    4. SRAM需求。SRAM价格比较高昂,所以一般产品会严格控制SRAM的大小。如果SRAM足够大,可以把映射信息都保存在SRAM上,也把Flash中的数据都读取到SRAM上,性能是最好的(此外最好得有个备用电源或者超级大电容,意外掉电时可以把SRAM中被更新的数据写回Flash~)。事实上SRAM大小远远不够的,所以有块管理算法、混合管理算法和把映射关系存放在Flash中的方案,缓存上层应用数据也要考虑把部分冷数据回写到Flash中。
    5. Flash并行操作。闪存设备底层,每片Flash可以进行Multi Plane操作,多片Flash间同时操作,也可能有多通道可以并行操作。这些操作可以大大加速对Flash的访问速度,有点类似于RAID技术。 以上提到的FTL基本功能是相互关联的。比如说,上层应用写数据到某个逻辑地址上,地址映射管理在空块池中获取一个物理块来接收数据,然后触发了垃圾回收。垃圾回收在选择物理块的时候需要考虑到块的磨损情况、是否坏块,在回收这个块的时候需要使用并行操作,提高回收速率。
    6. 异常处理。在Nand应用场景中,比如说SSD、U盘、eMMC,均存在一些突然断电的情况。如何在突发掉电的情况后恢复数据,保持映射关系正常。比如说,RAM中缓存着最新的映射关系,没有保存在Flash中,此时掉电后,如何在下次上电后把RAM中的映射关系恢复;如何保证当前找到的映射表格是最新的等等。还有规避Flash特性造成的错误,如驻留错错误(Data Retention)、Disturb。

    关于FTL的疑惑:

    1、F2FS是否绕过了FTL层直接操作的NAND flash?因为F2FS中提供了类似FTL层的GC、磨损均衡、映射等操作??

    自我解答:我认为F2FS自带了FTL的功能,不需要传统的FTL的转换,可以直接操作raw flash设备。
    因为F2FS是为flash文件系统专门设计的,而对于传统的磁盘文件系统不是为Flash而设计的,如果直接在Flash上运行会很快使Flash局部老化而丢失数据,或崩溃。另外由于FLASH的块比较大,如果直接映射成块设备的话,空间利用率低。

    FTL的作用就是解决负载均衡与提供适合传统文件系统的,大小合适(如512字节)的块设备。
    如图所示
    这里写图片描述

    展开全文
  • Freemaker FTL指令常用标签及语法

    万次阅读 多人点赞 2017-12-10 15:14:34
    Freemaker FTL指令常用标签及语法
    FTL指令常用标签及语法
    

    注意:使用freemaker,要求所有标签必须闭合,否则会导致freemaker无法解析。

    freemaker注释:<#-- 注释内容 -->格式部分,不会输出

    ---------------------------------- 基础语法 ----------------------------------

    1、字符输出

    ${emp.name?if_exists}      // 变量存在,输出该变量,否则不输出
    ${emp.name!}            // 变量存在,输出该变量,否则不输出
    
    ${emp.name?default("xxx")}     // 变量不存在,取默认值xxx 
    ${emp.name!"xxx"}          // 变量不存在,取默认值xxx

    常用内部函数:

    ${"123<br>456"?html}      // 对字符串进行HTML编码,对html中特殊字符进行转义
    ${"str"?cap_first}        // 使字符串第一个字母大写 
    ${"Str"?lower_case}        // 将字符串转换成小写 
    ${"Str"?upper_case}        // 将字符串转换成大写
    ${"str"?trim}              // 去掉字符串前后的空白字符

    字符串的两种拼接方式拼接:

    ${"hello${emp.name!}"}     // 输出hello+变量名
    ${"hello"+emp.name!}       // 使用+号来连接,输出hello+变量名

    可以通过如下语法来截取子串:

    <#assign str = "abcdefghijklmn"/>
    
    // 方法1
    ${str?substring(0,4)}  // 输出abcd
    
    // 方法2
    ${str[0]}${str[4]}    // 结果是ae
    ${str[1..4]}        // 结果是bcde
    
    // 返回指定字符的索引
    ${str?index_of("n")}

    2、日期输出

    ${emp.date?string('yyyy-MM-dd')} //日期格式

    3、数字输出(以数字20为例)

    ${emp.name?string.number}     // 输出20
    ${emp.name?string.currency}    // ¥20.00 
    ${emp.name?string.percent}     // 20%
    ${1.222?int}            // 将小数转为int,输出1
    
    <#setting number_format="percent"/>    // 设置数字默认输出方式('percent',百分比)
    <#assign answer=42/>             // 声明变量 answer 42
    #{answer}             // 输出 4,200%
    ${answer?string}         // 输出 4,200%
    ${answer?string.number}   // 输出 42
    ${answer?string.currency}  // 输出 ¥42.00
    ${answer?string.percent}  // 输出 4,200%
    #{answer}            // 输出 42
    
    数字格式化插值可采用#{expr;format}形式来格式化数字,其中format可以是:
    mX:小数部分最小X位
    MX:小数部分最大X位
    如下面的例子:
    <#assign x=2.582/>
    <#assign y=4/>
    #{x; M2}    // 输出2.58
    #{y; M2}    // 输出4
    #{x; m2}    // 输出2.58
    #{y; m2}    // 输出4.0
    #{x; m1M2}  // 输出2.58
    #{x; m1M2}  // 输出4.0

    4、申明变量

    <#assign foo=false/> // 声明变量,插入布尔值进行显示,注意不要用引号
    ${foo?string("yes","no")} // 当为true时输出"yes",否则输出"no"

    申明变量的几种方式

    <#assign name=value> 
    <#assign name1=value1 name2=value2 ... nameN=valueN> 
    <#assign same as above... in namespacehash>
    
    <#assign name> 
    capture this 
    </#assign>
    
    <#assign name in namespacehash> 
    capture this 
    </#assign>

    5、比较运算符

    表达式中支持的比较运算符有如下几个:
    = 或 == :判断两个值是否相等.
    != :判断两个值是否不等.
    > 或 gt :判断左边值是否大于右边值
    >= 或 gte :判断左边值是否大于等于右边值
    < 或 lt :判断左边值是否小于右边值
    <= 或 lte :判断左边值是否小于等于右边值

    6、算术运算符

    FreeMarker表达式中完全支持算术运算,
    FreeMarker支持的算术运算符包括:+, - , * , / , %
    注意:
    (1)、运算符两边必须是数字
    (2)、使用+运算符时,如果一边是数字,一边是字符串,就会自动将数字转换为字符串再连接,如:${3 + "5"},结果是:35

    7、逻辑运算符

    逻辑运算符有如下几个:
    逻辑与:&&
    逻辑或:||
    逻辑非:!
    逻辑运算符只能作用于布尔值,否则将产生错误

    8、FreeMarker中的运算符优先级如下(由高到低排列):

    ①、一元运算符:!
    ②、内建函数:?
    ③、乘除法:*, / , %
    ④、加减法:- , +
    ⑤、比较:> , < , >= , <= (lt , lte , gt , gte)
    ⑥、相等:== , = , !=
    ⑦、逻辑与:&&
    ⑧、逻辑或:||
    ⑨、数字范围:..
    实际上,我们在开发过程中应该使用括号来严格区分,这样的可读性好,出错少

    9、if 逻辑判断(注意:elseif 不加空格)

    <#if condition>
    ...
    <#elseif condition2>
    ...
    <#elseif condition3>
    ...
    <#else>
    ...
    </#if>

    if 空值判断

    // 当 photoList 不为空时
    <#if photoList??>...</#if> 
    
    值得注意的是,${..}只能用于文本部分,不能用于表达式,下面的代码是错误的:
    <#if ${isBig}>Wow!</#if>
    <#if "${isBig}">Wow!</#if>
    
    // 正确写法
    <#if isBig>Wow!</#if> 

    10、switch (条件可为数字,可为字符串)

    <#switch value> 
    <#case refValue1> 
    ....
    <#break> 
    <#case refValue2> 
    ....
    <#break> 
    <#case refValueN> 
    ....
    <#break> 
    <#default> 
    .... 
    </#switch>

    11、集合 & 循环

    // 遍历集合:
    <#list empList! as emp> 
        ${emp.name!}
    </#list>
    
    // 可以这样遍历集合:
    <#list 0..(empList!?size-1) as i>
        ${empList[i].name!}
    </#list>
    
    // 与jstl循环类似,也可以访问循环的状态。
    
    empList?size    // 取集合的长度
    emp_index:     // int类型,当前对象的索引值 
    emp_has_next:     // boolean类型,是否存在下一个对象
    
    // 使用<#break>跳出循环
    <#if emp_index = 0><#break></#if>
    
    // 集合长度判断 
    <#if empList?size != 0></#if> // 判断=的时候,注意只要一个=符号,而不是==
    
    <#assign l=0..100/>    // 定义一个int区间的0~100的集合,数字范围也支持反递增,如100..2
    <#list 0..100 as i>   // 等效于java for(int i=0; i <= 100; i++)
      ${i}
    </#list>
    
    // 截取子集合:
    empList[3..5] //返回empList集合的子集合,子集合中的元素是empList集合中的第4-6个元素
    
    // 创建集合:
    <#list ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"] as x>
    
    // 集合连接运算,将两个集合连接成一个新的集合
    <#list ["星期一","星期二","星期三"] + ["星期四","星期五","星期六","星期天"] as x>
    
    // 除此之外,集合元素也可以是表达式,例子如下:
    [2 + 2, [1, 2, 3, 4], "whatnot"]
    
    // seq_contains:判断序列中的元素是否存在
    <#assign x = ["red", 16, "blue", "cyan"]> 
    ${x?seq_contains("blue")?string("yes", "no")}    // yes
    ${x?seq_contains("yellow")?string("yes", "no")}  // no
    ${x?seq_contains(16)?string("yes", "no")}        // yes
    ${x?seq_contains("16")?string("yes", "no")}      // no
    
    // seq_index_of:第一次出现的索引
    <#assign x = ["red", 16, "blue", "cyan", "blue"]> 
    ${x?seq_index_of("blue")}  // 2
    
    // sort_by:排序(升序)
    <#list movies?sort_by("showtime") as movie></#list>
    
    // sort_by:排序(降序)
    <#list movies?sort_by("showtime")?reverse as movie></#list>
    
    // 具体介绍:
    // 不排序的情况:
    <#list movies as moive>
      <a href="${moive.url}">${moive.name}</a>
    </#list>
    
    //要是排序,则用
    <#list movies?sort as movie>
      <a href="${movie.url}">${movie.name}</a>
    </#list>
    
    // 这是按元素的首字母排序。若要按list中对象元素的某一属性排序的话,则用
    <#list moives?sort_by(["name"]) as movie>
      <a href="${movie.url}">${movie.name}</a>
    </#list>
    
    //这个是按list中对象元素的[name]属性排序的,是升序,如果需要降序的话,如下所示:
    <#list movies?sort_by(["name"])?reverse as movie>
      <a href="${movie.url}">${movie.name}</a>
    </#list>

    12、Map对象

    // 创建map
    <#assign scores = {"语文":86,"数学":78}>
    
    // Map连接运算符
    <#assign scores = {"语文":86,"数学":78} + {"数学":87,"Java":93}>
    
    // Map元素输出
    emp.name       // 全部使用点语法
    emp["name"]    // 使用方括号

    13、FreeMarker支持如下转义字符:

    \" :双引号(u0022)
    \' :单引号(u0027)
    \\ :反斜杠(u005C)
    \n :换行(u000A)
    \r :回车(u000D)
    \t :Tab(u0009)
    \b :退格键(u0008)
    \f :Form feed(u000C)
    \l :<
    \g :>
    \a :&
    \{ :{
    \xCode :直接通过4位的16进制数来指定Unicode码,输出该unicode码对应的字符.

    如果某段文本中包含大量的特殊符号,FreeMarker提供了另一种特殊格式:可以在指定字符串内容的引号前增加r标记,在r标记后的文件将会直接输出.看如下代码:
    ${r"${foo}"} // 输出 ${foo}
    ${r"C:/foo/bar"} // 输出 C:/foo/bar

    14、include指令

    // include指令的作用类似于JSP的包含指令:
    <#include "/test.ftl" encoding="UTF-8" parse=true>
    
    // 在上面的语法格式中,两个参数的解释如下:
    encoding="GBK"  // 编码格式
    parse=true    // 是否作为ftl语法解析,默认是true,false就是以文本方式引入,注意:在ftl文件里布尔值都是直接赋值的如parse=true,而不是parse="true"

    15、import指令

    // 类似于jsp里的import,它导入文件,然后就可以在当前文件里使用被导入文件里的宏组件
    <#import "/libs/mylib.ftl" as my>
    // 上面的代码将导入/lib/common.ftl模板文件中的所有变量,交将这些变量放置在一个名为com的Map对象中,"my"在freemarker里被称作namespace

    17、compress 压缩

    // 用来压缩空白空间和空白的行 
    <#compress> 
        ... 
    </#compress>
    <#t> // 去掉左右空白和回车换行 
    
    <#lt>// 去掉左边空白和回车换行 
    
    <#rt>// 去掉右边空白和回车换行 
    
    <#nt>// 取消上面的效果

    18、escape,noescape 对字符串进行HTML编码

    // escape指令导致body区的插值都会被自动加上escape表达式,但不会影响字符串内的插值,只会影响到body内出现的插值,使用escape指令的语法格式如下:
    <#escape x as x?html> 
      First name: ${firstName} 
    <#noescape>Last name: ${lastName}</#noescape> 
      Maiden name: ${maidenName} 
    </#escape>
    
    // 相同表达式
    First name: ${firstName?html} 
    Last name: ${lastName} 
    Maiden name: ${maidenName?html}

    ---------------------------------- 高级语法 ----------------------------------

    1、global全局赋值语法

    <#global name=value> 
    
    <#global name1=value1 name2=value2 ... nameN=valueN> 
    
    <#global name> 
      capture this 
    </#global>
    
    // 利用这个语法给变量赋值,那么这个变量在所有的namespace中是可见的,如果这个变量被当前的assign语法覆盖如<#global x=2><#assign x=1>在当前页面里x=2将被隐藏,或者通过${.globals.x} 来访问

    2、setting 语法

    // 用来设置整个系统的一个环境 
    locale // zh_CN 中文环境
    number_format 
    boolean_format 
    date_format , time_format , datetime_format 
    time_zone 
    classic_compatible
    // 例1:
    <#setting number_format="percent"/>    // 设置数字默认输出方式('percent',百分比)
    
    // 例2:
    // 假如当前是匈牙利的设置,然后修改成美国
    ${1.2} // 输出1,2
    <#setting locale="en_US"> 
    ${1.2} // 输出1.2,因为匈牙利是采用", "作为十进制的分隔符,美国是用". "

    3、macro宏指令

    例子1:

    <#-- 定义宏 -->
    <#macro test foo bar="Bar" baaz=-1> 
      Text: ${foo}, ${bar}, ${baaz}
    </#macro>
    
    <#-- 使用宏 -->
    <@test foo="a" bar="b" baaz=5*5/>  // 输出:Text: a, b, 25
    <@test foo="a" bar="b"/>        // 输出:Text: a, b, -1
    <@test foo="a" baaz=5*5-2/>     // 输出:Text: a, Bar, 23
    <@test foo="a"/>                   // 输出:Text: a, Bar, -1

    例子2:

    <#-- 定义一个循环输出的宏 -->
    <#macro list title items> 
      ${title}
      <#list items as x>
        *${x}
      </#list> 
    </#macro> 
    
    <#-- 使用宏 -->
    <@list items=["mouse", "elephant", "python"] title="Animals"/>
    // 输出Animals *mouse *elephant *python

    例子3:

    <#-- 嵌套宏 -->
    <#macro border>
      <table>
        <#nested>
      </table>
    </#macro>
    
    <#-- 嵌套宏使用 -->
    <@border>
      <tr><td>hahaha</td></tr>
    </@border> 
    输出结果:
    <table>
      <tr><td>hahaha</td></tr>
    </table>

     

    例子4:在nested指令中使用循环变量时,可以使用多个循环变量,看如下代码:

    <#-- 循环嵌套宏 -->
    <#macro repeat count>
      <#list 1..count as x>
        <#nested x, x/2, x==count> // 使用nested指令时指定了三个循环变量
      </#list>
    </#macro>
    
    <#-- 使用宏 -->
    <@repeat count = 4; c, halfc, last>
      ${c}. ${halfc}<#if last> Last!</#if>
    </@repeat>
    // 输出结果:
    // 1. 0.5
    // 2. 1
    // 3. 1.5
    // 4. 2 Last!

    freemarker 宏嵌套nested 的使用:
    http://blog.sina.com.cn/s/blog_7e5699790100z59g.html


    4、结束macro指令

    // return指令用于结束macro指令
    <#-- 创建宏 -->
    <#macro book>
      spring
      <#return>
      j2ee
    </#macro>
    
    <#-- 使用宏 -->
    <@book />
    // 上面的代码输出:spring,而j2ee位于return指令之后,不会输出.

     

    FreeMarker 工具类:

    http://files.cnblogs.com/files/duke-cui/FreeMarkerUtil.rar

     

    THE END !!!!

    展开全文
  • .ftl文件 是什么文件

    千次阅读 2017-12-18 22:50:34
    1、Freemarker模板的文件后缀名 2、Freemarker其实是一种比较简单的网页展示技术,说白了就是网页模板和数据模型的结合体。这种结合模式的好处就是,分离了网页界面设计人员和编程人员的工作,让他们各司其职。...
    1、Freemarker模板的文件后缀名
    2、Freemarker其实是一种比较简单的网页展示技术,说白了就是网页模板和数据模型的结合体。这种结合模式的好处就是,分离了网页界面设计人员和编程人员的工作,让他们各司其职。
    据个人理解,Freemarker大致的工作方式是,网页模板里面嵌入了数据模型中的数据、Freemarker自定义流程控制语言、Freemarker自定义的操作函数等等,在装载网页的时候,Freemarker模板自动从数据模型中提取数据,并解释整个网页为我们熟知的HTML页面。
    在B/S程式设计中,常常有美工和程序员二个角色,他们具有不同专业技能:美工专注于表现——创建页面、风格、布局、效果等等可视元素;而程序员则忙于创建程式的商业流程,生成设计页面要显示的数据等等。
    很多时候,要显示的资料在设计的时候并不存在,它们一般是在运行时由程式产生的,比如执行“价格不高于800NT的USB Disk”查询的返回结果。这种技术需求产生了JSP等Scriptlet,JSP十分强大,但是也常常被滥用,并导致一些不良的后果,将逻辑和表现混合在一起。,破坏了美工和程序员职责的正常分解使JSP页面难以阅读和维护。
    模板引擎就是为了解决上面的问题而产生的。在设计HTML的时候,我们加入一些特定指令来指定要插入哪些数据,这些加了特殊指令的HTML或者其他文本,我们称为模板(Template)。而模板引擎会在输出页面时,用适当的数据替代这些代码
    模板和嵌入JSP的HTML是不同的,模板指令只有很有限的编程能力,可以避免混入商业逻辑。
    总结
    简单的说,FreeMarker就是一种用Java编写的模板引擎,它根据模板输出多种规格的文本。特别指出的是,FreeMarker与Web应用框架无关,它同样可以应用在非Web应用程序环境中,而且,FreeMarker并不是只能生成HTML页面,它也可以生成各种文本,如XML/RTF/Java源代码等。
    Freemarker是一个非常优秀的模版引擎,这个模版引擎可用于任何场景,FreeMarker负责将数据模型中的数据合并到模版中,从而生成标准输出。

    FreeMarker特别适应与MVC模式的Web应用,通常有Java程序准备要显示的数据,由FreeMarker模版引擎来生成页面,而FreeMarker模版则提供页面布局支持,从而能更好地规范MVC架构,保证视图逻辑和业务逻辑分离。

    文章来源:http://blog.csdn.net/rangqiwei/article/details/8513482

    展开全文
  • 快速生成 .ftl 文件

    千次阅读 2019-09-09 14:40:43
    使用freemarker会以 .ftl 文件为模板,刚开始不知道怎么搞每次还得复制一个别人写的然后进行修改,后来度娘可以直接生成ftl文件于是记录下来: 解决方法: 首先创建一个world文档并编辑成自己需要的模板,然后点击...
  • .ftl文件简介及语法

    万次阅读 2016-05-24 14:21:54
    1、Freemarker模板的文件后缀名 2、Freemarker其实是一种比较简单的网页展示技术,说白了就是网页模板和数据模型的结合体。这种结合模式的好处就是,分离了网页界面设计人员和编程人员的工作,让他们各司其职。...
  • 最近在项目中,出现了一个bug,一开始用的??来判断是否为空,但是报错了,改成?has_content就没错了。 在网上查找原因后,总结如下: 原解答地址: ... ?? tells if the l...
  • FTL简介

    2020-03-29 06:19:19
    SSD-FTL简介 参考资料《深入浅出SSD》 FTL 1.全称 Flash Translation Layer,闪存转换层 2.作用 完成Host逻辑地址空间到闪存(Flash)物理地址空间的映射; FTL算法的优劣,决定了SSD的性能,可靠性,耐用性等,它是...
  • ftl模板文件换行

    万次阅读 2018-10-18 16:39:13
    解决JAVA生成word时,模板中换行符替换,代码如下: ${(suggestion?html?replace('\r\n','&lt;w:br/&gt;') )!}      
  • ftl模板文件编辑器

    万次阅读 2018-01-24 12:00:49
    ftl模板文件编辑器最近博主在研究模板引擎Freemarker生成Word文件相关知识,博主采用的Eclipse进行开发,使用自带的JSP框架来编辑ftl文件,在编辑ftl文件之前,如果你的Eclipse没有指定ftl的编辑方式,会提示让你...
  • 使IDEA支持ftl扩展名

    千次阅读 2009-02-05 12:31:28
    使IDEA支持ftl扩展名 IDEA默认打开后缀名为ftl的文件时,设计视图显示灰色,无法直接预览ftl文件样式; 需要进行以下修改 在File Types中的HTML files中添加*.ftl注册类型. ...
  • 1.编辑好word模板 2.将word模板另存为xml格式 3.将xml模板文件后缀名改为.ftl 4.搜索关键字,补入 或其它freemarker标签
  • 如何使用eclipse建立ftl文件

    千次阅读 热门讨论 2017-07-22 17:18:01
    今天学习spring结合freemarker,建立.ftl文件的时候报错: 然后就上网搜了一下如何建立.ftl文件,记录一下,以后不用找了。 点击Window,选择Reference,弹出如下框 找到:General--Editors--File ...
  • *.ftl文件中文乱码的解决办法:

    千次阅读 2016-07-07 17:34:28
    在struts使用freemarker时候,ftl的中文显示乱码,解决办法:Window->Preferences->Workspace->Text file encoding 配置 Text file encoding为 utf-8,再把相应ftl中文再改一次。
  • 0) >
  • freemarker中include与import的区别

    万次阅读 2016-02-05 14:20:48
    问题显示:   在inc1.ftl与inc2.ftl中的内容分别是: 与 接着我在hello.ftl模版中用...接着我们在hello.ftl用include将inc1.ftl与inc2.ftl同时进行包含进来 ${username} 此刻获取的值是:张学友   总结
  • 将html转换成freemarker中的ftl模板,求代码,求模板
  • eclipse 如何安装freemaker ftl 插件

    万次阅读 2016-08-25 22:44:49
    freemarker模板文件使用jboss tools下提供的FreeMarker IDE, 在线安装的方法是: Help –> Install New Software  点击and,再出来的对话框中的Location中输入: ...
  • 菜鸟一枚,ftl文件可以用什么工具进行可视化修改。用word修改后${xmmc_}会变成xmmc
  • *.ftl文件中文乱码的问题:

    万次阅读 2012-11-28 12:44:47
    今天终于实现了利用ext提供的表单,函数,将数据库中的内容通过Json显示在页面中,然后将页面修改之后的内容利用FromPanel的...可是成功之后,却发现一个很让人难受的问题:ftl文件的页面显示中文出现乱码。 Myecl
1 2 3 4 5 ... 20
收藏数 27,453
精华内容 10,981
关键字:

ftl