zoukankan      html  css  js  c++  java
  • FreeMarker笔记 第四章 其它

    4.1 自定义指令

    4.1.1 简介

    自定义指令可以使用macro指令来定义。Java程序员若不想在模板中实现定义指令,而是在Java语言中实现指令的定义,这时可以使用freemarker.template.TemplateDirectiveModel类来扩展,后边会讲。

    4.1.2 基本内容

    宏是有一个变量名的模板片段。你可以在模板中使用宏作为自定义指令,这样就能进行重复性的工作。例如,创建一个宏变量来打印大号的”hello Joe!“;

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

    可以在FTL标记中通过@代替#来使用自定义指令。

    <@greet></@greet>
    4.1.3 参数

    我们仅在greet宏中定义一个变量,person;

    <#macro greet person>
        <font size="+2">Hello ${person}!</font>
    </#macro>

    那么可以这样使用宏:

    <@greet person="Fred"/>and<@greet person="Batman"/>

    可以去掉双引号, <@greet person=Fred/>

    多个参数时,可以设置默认值,要不然的话使用的时候必须指定对应的多个参数:

    <#macro greet person color="black">
        <font size="+2" color="${color}">Hello ${person}!</font>
    </#macro>

    那么就可以这样使用了

    <@greet person="Fred"/>
    实例

    /FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/macro.ftl

    
        <h2>没有参数</h2>
        <p>
            <#macro greet>
                <font size="+2">Hello Joe!</font>
            </#macro>
            <@greet/>
        </p>
        <h2>有参数</h2>
        <p>
            <#macro greet person>
                <font size="+2">Hello ${person}!</font>
            </#macro>
            <@greet person="Fred"/> and <@greet person="Bob"/>
        </p>
        <h2>多个参数时,可以设定默认值</h2>
        <p>
            <#macro greet person color="black">
                <font size="+2" color="${color}">Hello ${person}!</font>
            </#macro>
            <@greet person="Fred"/> and <@greet person="Bob" color="red"/>
        </p>
    

    输出:

    2014-09-09_162226

    4.1.4 嵌套内容

    自定义指令可以嵌套内容,和预定义指令相似:<#if ...>nested content</#if>。比如,下面这个例子中是创建了一个可以为嵌套的内容画出边框;

    <#macro border>
        <table border=4 cellspacing=0 cellpadding=4>
            <tr>
                <td>
                    <#nested>
                </td>
            </tr>
        </table>
    </#macro>

    <#nested>标签执行位于开始和结束标签之间的模板代码块,例如:

    <@border>The bordered text</@border>

    输出:

    <table border=4 cellspacing=0 cellpadding=4>
        <tr>
            <td>
                The bordered text
            </td>
        </tr>
    </table>

    <#nested>指令可以被执行多次;

    <#macro do_thrice>
        <#nested>
        <#nested>
        <#nested>
    </#macro>

    使用时:

    <@do_thrice>anything</@do_trice>

    输出:

    anything
    anything
    anything

    如果不使用nested指令,那么嵌套的内容就会被执行,如果不小心写成这样:

    <@greet person="Joe">
        Anything.
    </@greet>

    输出是:

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

    嵌套的内容被忽略了,因为greet没有使用nested指令;

    嵌套内容可以是其他FTL指令,包含其他自定义指令也是可以的。

    <@border>
        <ul>
            <@do_thrice>
                <li><@greet person="Joe"></li>
            </@do_thrice>
        </ul>
    </@border>

    在嵌套的内容中,宏的局部变量是不可见的;

    <#macro repeat count>
        <#local y="test">
        <#list 1..count as x>
            ${y} ${count}/${x} : <#nested>
        </#list>
    </#macro>
    <@repeat count=3>${y!"?"} ${x!"?"} ${count!"?"}</@repeat>

    将会输出:

    test 3/1: ? ? ?
    test 3/2: ? ? ?
    test 3/3: ? ? ?

    不同的局部变量的设置是为每个宏自己调用的,所以不会导致混乱;

    <#macro test foo>${foo} (<#nested>) ${foo}</#macro>
    <@test foo="A"><@test foo="B"><@test foo="C"/></@test></@test>

    输出:

    A (B (C () C) B) A
    4.1.5 宏与循环变量

    循环变量的名字是已经给定了,变量值的设置由指令本身完成。

    <#macro do_thrice>
        <#nested 1>
        <#nested 2>
        <#nested 3>
    </#macro>
    <p>
        <#--自定义循环变量需要用;代替as-->
        <@do_thrice ; x>
            do_something : ${x}
        </@do_thrice>
    </p>

    输出:

    do_something : 1 do_something : 2 do_something : 3 

    例子:/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/nested.ftl

    <h3>宏与循环变量</h3>
    <#macro do_thrice>
        <#nested 1>
        <#nested 2>
        <#nested 3>
    </#macro>
    <p>
        <#--自定义循环变量需要用;代替as-->
        <@do_thrice ; x>
            do_something : ${x}
        </@do_thrice>
    </p>

    一个宏可以使用多个循环变量(变量的顺序是很重要的):

    <#macro repeat count>
        <#list 1..count as x>
            <#nested x, x/2, x==count>
        </#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-hello-web/src/main/webapp/WEB-INF/ftl/4/nested.ftl

    
        <h3>一个宏可以使用多个循环变量</h3>
        <#macro repeat count>
            <#list 1..count as x>
                <#nested x, x/2, x==count><br>
            </#list>
        </#macro>
        <p>
            <@repeat count=4 ; c, half, last>
                ${c}. ${half} <#if last> Last!</#if>
            </@repeat>
        </p>
    

    如果分号后指定的变量少了或多了,多出的会忽略掉;

        @repeat count=4 ; c, half>
            ${c}. ${half}
        </@repeat>
    4.1.6 自定义指令和宏进阶

    你也可以在FTL中定义方法,参见function指令;

    也许你对命名空间感兴趣。命名空间可以帮助你组织和重用你经常使用的宏;

    4.2 在模板中定义变量

    可以访问一个在模板里定义的变量,就像是访问数据模型根上的变量一样。这个变量比定义在数据模型中的同名参数具有更高的优先级。如果你恰巧定义了一个名为“foo”的变量,而在数据模型中也有一个名为“foo”的变量,那么模板中的变量就会将数据模型根上的变量隐藏(而不是覆盖!)。

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

    • 简单变量:它能从模板中的任何位置访问,或者从使用include指令引入的模板访问。可以使用assignmacro指令来创建或替换这些变量。
    • 局部变量:它们只能被设置在宏定义体内,而且只在宏内可见。一个局部变量的生命周期只是宏的调用过程。可以使用local来创建或替换局部变量。
    • 循环变量:循环变量是由指令(如list)自动创建的,而且它们只在指令的开始和结束标记内有效。宏的参数是局部变量而不是循环变量。

    使用assign创建和替换变量;

    /FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/variable.ftl

    
        <h3>简单变量</h3>
        <p>
            <#assign x=1> <#--创建变量x-->
            ${x}<br>
            <#assign x=x+3> <#--替换变量x-->
            ${x}
        </p>
    

    输出:

    简单变量
    1
    4 

    局部变量也会隐藏(而不是)同名的简单变量。循环变量也会隐藏(不是覆盖)同名的局部变量和简单变量。

    实例:/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/variable.ftl

    
        <#macro test>
            2. ${x}<br>
            <#local x="local">
            3. ${x}<br>
            <#list ["loop"] as x>
                4. ${x}<br>
            </#list>
            5. ${x}<br>
        </#macro>
        <p>
            <#assign x="plain">
            1. ${x}<br>
            <@test/>
            6. ${x}<br>
            <#list ["loop"] as x>
                7. ${x}<br>
                <#assign x="plain2"> <#--在这里替换了简单变量x-->
                8. ${x}<br>
            </#list>
            9. ${x}
        </p>
    

    输出:

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

    内部循环可以隐藏外部循环的变量;

    实例:/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/variable.ftl

    
            <#list ["loop 1"] as x>
                ${x}<br>
                <#list ["loop 2"] as x>
                    ${x}<br>
                    <#list ["loop 3"] as x>
                        ${x}<br>
                    </#list>
                    ${x}<br>
                </#list>
                ${x}<br>
            </#list>
    

    输出:

    loop 1
    loop 2
    loop 3
    loop 2
    loop 1

    有时发生一个变量隐藏数据模型中的同名变量,但是如果想访问数据模型中的变量,就可以使用特殊变量globals

    实例:/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/variable.ftl

    
            <#assign user="Cindy">
            ${user}, ${.globals.user}   
    

    /FreeMarker-hello-web/src/main/java/org/yejq/fre/service/Exercises.java

    
        public void testVariable(Model model){
            model.addAttribute("user", "lucy");
        }
    

    测试:http://localhost/test/4/variable/testVariable,输出结果:

    Cindy, lucy

    4.3 命名空间

    4.3.1 简介

    如果想创建可以重复使用的宏、函数和其他变量的集合,通常用术语来说就是引用library库,使用命名空间是必然的;

    4.3.2 创建一个库

    实例:/FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/lib/my_test.ftl

    
    <#macro copyright date>
        <p>Copyright (C) ${date} Julia Smith. All rights reserved.</p>
    </#macro>
    <#assign mail="jsmith@acme.com">
    

    /FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/namespace.ftl

    
        <h3>使用import导入</h3>
        <p>
            <#import "../lib/my_test.ftl" as my>
            <@my.copyright date="2014-2016"/>
            ${my.mail}
        </p>
    

    输出:

    使用import导入
    
    Copyright (C) 2014-2016 Julia Smith. All rights reserved.
    
    jsmith@acme.com 

    测试不同的命名空间;

    /FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/lib/my_test.ftl

    
    <#macro copyright date>
        <p>Copyright (C) ${date} Julia Smith. All rights reserved.
        <br>Mail: ${mail}   
        </p>
    </#macro>
    <#assign mail="jsmith@acme.com">
    

    /FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/namespace.ftl

    
        <h3>演示不同的命名空间</h3>
        <p>
            <#import "../lib/my_test.ftl" as my>
            <#assign mail="fred@acme.com">
            <@my.copyright date="2014-2016"/>
            ${my.mail}<br>
            ${mail}
        </p>
    

    测试:http://localhost/test/4/namespace/null

    4.3.3 在引入的命名空间上编写变量

    /FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/namespace.ftl

    
            <#import "../lib/my_test.ftl" as my>
            ${my.mail}<br>
            <#assign mail="jsmith@other.com" in my>
            ${my.mail}
    

    http://localhost/test/4/namespace/null,输出:

    jsmith@acme.com
    jsmith@other.com 
    4.3.4 命名空间和数据模型

    数据模型中的变量在任何位置都是可见的。如果在数据模型中有一个名为user的变量,那么lib/my_test.ftl也能访问TA。

    /FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/lib/my_test.ftl

    
    <#macro copyright date>
        <p>Copyright (C) ${date} ${user} Julia Smith. All rights reserved.
        <br>Mail: ${mail}   
        </p>
    </#macro>
    <#assign mail="${user}@acme.com">
    

    /FreeMarker-hello-web/src/main/java/org/yejq/fre/service/Exercises.java

    
        public void testNamespace(Model model){
            model.addAttribute("user", "lucy");
        }
    

    /FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/namespace.ftl

    
        <h3>数据模型中的变量在任何位置都是可见的</h3>
        <p>
            <#import "../lib/my_test.ftl" as my>
            <@my.copyright date="2014-2015"/>
        </p>
    

    测试:http://localhost/test/4/namespace/testNamespace?11,输出结果:

    Copyright (C) 2014-2015 lucy Julia Smith. All rights reserved. 
    Mail: lucy@acme.com 
    4.3.5 命名空间的生命周期

    命名空间由使用的import指令中所写的路径来识别。如果想多次import这个路径,那么只会为第一次的import引用创建命名空间执行模板。后边相同的路径的import只是创建一个哈希表当做访问相同命名空间的“门”。

    /FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/namespace.ftl

    
        <h3>命名空间的声明周期</h3>
        <p>
            <#import "/lib/my_test.ftl" as my>
            <#import "/lib/my_test.ftl" as foo>
            <#import "/lib/my_test.ftl" as bar>
            <#--只会在第一次创建命名空间执行模板,之后相同路径的import只是创建哈希表当做访问相同命名空间的"门"-->
            ${my.mail}, ${foo.mail}, ${bar.mail}<br>
            <#assign mail="jsmith@other.com" in my>
            ${my.mail}, ${foo.mail}, ${bar.mail}<br>
            <#--其中一个命名空间的值修改了,所有都相应修改,就像java里边的对象引用修改一样-->
            <#assign mail="jsmith@foo.com" in foo>
            ${my.mail}, ${foo.mail}, ${bar.mail}
        </p>
    

    访问:http://localhost/test/4/namespace/null,输出:

    命名空间的声明周期
    
    jsmith@acme.com, jsmith@acme.com, jsmith@acme.com
    jsmith@other.com, jsmith@other.com, jsmith@other.com
    jsmith@foo.com, jsmith@foo.com, jsmith@foo.com 

    还要注意命名空间是不分层次的,它们相互之间是独立存在的。那么,如果在命名空间N1中import命名空N2,那N2也不在N1中,N1只是通过哈希表访问N2。这和主命名空间中importN2,然后直接访问命名空间N2是一样的过程。

    每一次模板的执行过程,它都有一个私有的命名空间的集合。每一次模板执行工作都是一个分离且有序的过程,它们仅仅存在一段很短的时间,同时页面用以呈现内容,然后就和所有填充过的命名空间一起消失了。

    4.3.6 为他人编写库

    http://freemarker.org/libraries.html

    标准库路径的格式:

    /lib/yourcompany.com/your_library.ftl

    如果你的公司的主页是www.example.com,那么;

    /lib/example.com/widget.ftl
    /lib/example.com/commons/string.ftl

    一个重要的规则是路径不应该包含大写字母,winForm改成win_form;

    4.4 空白处理

    4.4.1 简介

    来看看这个模板;

    2014-09-14_103810

    按照Freemarker规则输出后是:

    2014-09-14_103928

    这么多多余的空白是很令人头疼,而且增加处理后的HTML文件大小也是没必要的;

    FreeMarker提供了以下工具来处理这个问题:

    • 忽略某些文件的空白的工具(解析阶段空白就被移除了)
      • 剥离空白:这个特性会自动忽略FTL标签周围的空白。这个特性可以通过模板来随时使用和禁用;
      • 微调指令:t, rtlt,使用这些指令可以明确告诉FreeMarker去忽略某些空白;
      • FTL参数strip_text:这将从模板中删除所有顶级文本。对模板来说很有用,它包含某些定义的宏,因为它可以移除宏定义和其他顶级指令中的换行符,这样可以提高模板的可读性;
    • 从输出移除空白的工具(移除临近的空白)
      • compress指令
    4.4.2 剥离空白

    它会自动忽略两种典型的空白:

    • 缩进空白和行末尾的尾部空白;如果这行上包含<#if ...>x,那么空白不会忽略,因为x不是标签。而一行上有<#if ...> <#list ...>,这样也不会忽略空白,因为标签之间的空格是嵌入空白;
    • 加在这些指令之间的空白会被忽略:macro,function,assign,global,local,ftl,import;

    使用剥离空白之后,上面的例子输出是:

    2014-09-14_104013

    剥离空白功能可以在ftl指令在模板中开启或关闭。默认开启。开启剥离空白不会降低模板执行的效率,剥离空白的操作在模板加载时就已经完成了。

    剥离空白可以为单独的一行关闭,就是使用nt指令;

    4.4.3 使用compress指令

    和剥离空白相反,这个工作是直接基于生产的输出内容,而不是对模板进行的。它会强势地移除缩进,空行和重复的空格/制表符;

    对于下边这段代码:

    /FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/compress.ftl

    
        <h2>使用compress指令,在输出的内容中移除缩进,空行和空格/制表符</h2>
        <p>
            <#compress>
                <#assign users = [{"name":"Joe", "hidden":false},
                                {"name":"James Bond", "hidden":true},
                                {"name":"Julia", "hidden":false}]>
                list of users:<br>
                <#list users as user>
                    <#if !user.hidden>
                        - ${user.name}<br>
                    </#if>
                </#list>
            </#compress>
        </p>
    

    输出:

            <h2>使用compress指令,在输出的内容中移除缩进,空行和空格/制表符</h2>
        <p>
            list of users:<br>
    - Joe<br>
    - Julia<br> </p>

    由于向下兼容性,名称为compress的用户自定义指令是存在的,有个single_line的属性,如果设置为true,那么会移除其中的换行符;

    
        <h3>@compress的属性single_line</h3>
        <p>
            <@compress single_line=true>
                <#assign users = [{"name":"Joe", "hidden":false},
                                {"name":"James Bond", "hidden":true},
                                {"name":"Julia", "hidden":false}]>
                list of users:<br>
                <#list users as user>
                    <#if !user.hidden>
                        - ${user.name}<br>
                    </#if>
                </#list>
            </@compress>
        </p>
    

    貌似不起作用,反而#compress是single_line;

    4.5 替换(方括号)语法

    版本2.3.4之后才有;

    在指令和注释中使用[]代替<>

    [#list ...]...[/list]
    [@mymacro .../]
    [#-- the comment --]

    为了使用这种语法从而代替默认语法,那么就需要用[#ftl]来开始模板。

    /FreeMarker-hello-web/src/main/webapp/WEB-INF/ftl/4/ftl.ftl

    
    [#ftl]
    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8" />
        <title>Document</title>
    </head>
    <body>
        <h3>替换语法</h3>
        <p>
            [#assign users = [{"name":"Joe", "hidden":false},
                                {"name":"James Bond", "hidden":true},
                                {"name":"Julia", "hidden":false}]]
            list of users:<br>
            [#list users as user]
                [#if !user.hidden]
                    - ${user.name}<br>
                [/#if]
            [/#list]
        </p>
    </body>
    </html>
    

    测试:http://localhost/test/4/ftl/null

     

    项目

    1. P1:https://github.com/yejq/FreeMarker-hello-java.git
    2. P2:https://github.com/yejq/FreeMarker-hello-web.git
  • 相关阅读:
    OO第二单元架构随笔
    OO第二单元小结
    OO第一单元小结
    OO第四单元总结
    oo第三单元总结
    OO第二单元总结
    OO第一单元总结
    OO第四单元及课程总结
    OO第三单元总结
    OO第二单元总结
  • 原文地址:https://www.cnblogs.com/yejq/p/3982967.html
Copyright © 2011-2022 走看看