FreeMarker入门一

FreeMarker入门一

FreeMarker的官网,它提供了良好的中文文档。也可参考教程Java Web扩展-Freemarker

中文文档翻译请参考在线手册

为了方便写FreeMarker,可安装FreeMarker插件和定义一个FreeMarkerUtil

1.FreeMarker插件安装
在官网的Editor and IDE plugins一节,找到安装说明

2.FreeMarkerUtil类定义一些方便的方法,如获取模板和获取writer
获取模板:

    public static Template geTemplate(String name)
    {
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_26);
        try {
            //设置要加载模板的文件系统目录
            cfg.setDirectoryForTemplateLoading(new File("src/ftl"));
            Template template = cfg.getTemplate(name);
            return template;
        } catch (IOException  e) {
            e.printStackTrace();
        }
        return null;
    }

获取writer

    public static Writer getWrite(String name)
    {
        try {
            Writer writer = new FileWriter(new File(name));
            return writer;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

定义了之后,就可以很方便的生成HTML了

        Template template = FreeMarkerUtil.geTemplate("basic.ftl");
        Writer writer = FreeMarkerUtil.getWrite("basic.html");
        try {
            //使用提供的数据模型执行模板,将生成的输出写入到所提供的输出中
            template.process(root, writer);
            writer.flush();
        } catch (TemplateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

入门

模板 + 数据模型 = 输出

模板

模板FreeMarker Template Language (FTL),模板文件以ftl为后缀,其组成:

  • 文本: 包含HTML标签和静态文本内容,会原样输出
  • 插值(interpolation):这部分输出会被计算的值替换,使用${}这种语法
  • FTL标签:FTL标签也被称为 指令,标签的名字以 # 开头,是不会在输出中打印的(用户自定义的FTL标签则需要使用 @ 来代替 #)
  • 注释:使用 <#----> 来标识。而HTML注释会输出在文档中

数据模型

数据模型的基本结构是树状的:

  • hashes(哈希表或哈希):哈希表存储其他变量(被称为 子变量),可通过名称来查找
  • scalars(标量):存储单值的变量
  • sequences(序列):它们像哈希表那样存储子变量,但是子变量没有名字,它们只是列表中的项

数据类型和变量使用

模板中支持的数据类型有:
这里使用assign来声明简单的变量,局部变量可以由 local 指令创建

  • 标量

    • 字符串

      <#assign name="小王">
      ${name}
      
    • 数字

      <#assign num=10>
      ${num}
      
    • 布尔值,注意使用?c进行转换

      <#assign b=true>
      ${b?c}
      
    • 日期

  • 容器

    • 哈希表,子变量通过名称来查找

      <#assign map={"name": "小王", "age": 20}>
      ${map.name}
      ${map.age}
      

      还可以通过${map["age"]}这种形式,支持有特殊字符

    • 序列,子变量通过一个整数来标识

      <#assign seqs=[1, 2, 3, 4, 5]>
      ${seqs[1]}
      

      上面的seqs=[1, 2, 3, 4, 5]可以使用seqs=1..5来表示1到5

运算符

算数运算符

+ 可以用来进行字符串的拼接,也可以进行序列的拼接

<#assign name="abc">
${name+"def"}
<#assign num=10+"a">
${num}

如下${num?int}把小数转换为整数

<#assign num=10/3>
${num}<#-- 3.333 -->
<#assign num=10/3>
${num?int}<#-- 3 -->
比较运算符
  • lt等同于<
  • lte等同于<=
  • gt等同于>
  • gte等同于>=

字符串比较是否相同可直接使用==

<#assign eq = "a" == "a">
${eq?c}
空值处理运算符

如下的定义:

<#assign n={"name": "tom"}>
${n.age}

获取n.age的值,但是没有定义这个key,所以会报错。
可使用${n.age!20}来处理,表示如果n.age存在就获取,不存在就是默认值20

插值

插值是用来插入具体指然后转换为文本(字符串),语法就是${}
注意插值的结果必须是字符串,数字或者日期类型

指令

条件指令
<#assign score=80>
<#if score lt 60>
差
    <#elseif score lt 80>
中
    <#elseif score lt 90>
良好
    <#else>
优秀
</#if>

switch

<#assign level="A">
<#switch level>
  <#case "A">
     A
     <#break>
  <#case "B">
     B
     <#break>
  <#case "C">
     C
     <#break>
  <#default>
     Default
</#switch>
循环指令

对序列循环

<#assign nums=[1, 3, 4, 5]>
<#list nums as num>
    ${num_index}, ${num}, ${num_has_next?c}
</#list>

${num_index}获取索引
num_has_next是一个bool值,表示是否有下一个值

上面的例子,其遍历结果是:

0, 1, true
1, 3, true
2, 4, true
3, 5, false

另一种使用方式是,对某个范围进行遍历

<#assign maxnum = 10>
<#list 1..maxnum as num>
${num}
<#if num==6>
    <#break>
</#if>
</#list>

<#break>用来终止循环

包含指令

语法为:

<#include path>

path 参数可以是如 "foo.ftl""../foo.ftl" 一样的相对路径,或者是如 "/foo.ftl" 这样的绝对路径。 相对路径是相对于使用 import 指令的模板文件夹。 绝对路径是相对于程序员在配置 FreeMarker 时定义的基路径 (通常指代”模板的根路径”)。

*/foo.ftl这种添加*的路径会一层层往上找

include指令可以在一个模板中插入另一个模板的内容。
对于模板和引入的模板,它们的变量是可以共享的

如下的head.ftl模板

<h1>${title}</h1>

head.ftl模板导入到include.ftl模板中

<#assign title="这是标题">
<#include "head.ftl">

这是自身的内容
其它指令

noparse指令表示FreeMarker 不会在这个指令体中间寻找FTL标签, 插值和其他特殊的字符序列,除了noparse的结束标记。
compress指令它捕捉在指令体(也就是在开始标签和结束标签中)中生成的内容, 然后缩小所有不间断的空白序列到一个单独的空白字符。
setting指令设置影响FreeMarker的值。可以设置国际化相关的东西

自定义指令

自定义指令可以将模板中重复的内容进行复用
定义:

  • 自定义指令可以使用 macro 指令来定义或者使用纯Java来实现
  • 参数的声明,直接跟在指令名后,可以指定默认值
  • 嵌套内容,使用nested指令

如下的一个简单的子定义指令

<#macro mydirect1>
    这是自定义指令
</#macro>

<@mydirect1 />

两个要点:
1.使用macro来声明自定的指令
2.使用自定义指令以@开头

如下是带有参数的自定义指令,其中age有默认值:

<#macro mydirect2 name age=18>
    hello ${name}, age is ${age}
</#macro>
<@mydirect2 name="tom"/>

如果想要在自定义指令中嵌套一些内容,下面这样写是没有效果的:

<#macro mydirect3 >
    mydirect3
</#macro>
<@mydirect3>
    内容
</@mydirect3>

其显示的结果只有mydirect3
正确的做法是使用<#nested>指令,如下

<#macro mydirect3 >
    mydirect3
    <#nested>
</#macro>
<@mydirect3>
    内容
</@mydirect3>

其显示结果为:

mydirect3
内容

空值处理

1.null对象的处理方法:使用!

如下,设置如下的数据:

        User user = new User();
        user.setName("小明");
        //不设置group属性
        //Group group = new Group();
        //group.setName("朋友");
        //user.setGroup(group);

        Map<String, User> root = new HashMap<>();
        root.put("user", user);

        ......
        template.process(root, writer);

使用${user.group!"不属于任何组"}可正常显示"不属于任何组"
但是使用${user.group.name!"不属于任何组"}则会报错,这是因为!只会做最后一个属性的判读
整体加上一个小括号就不会出错了,如下:

${(user.group.name)!"不属于任何组"}

2.变量不存在的处理方式:使用??(??判断某个变量是否存在,返回boolean值)

<#if user.age??>
    存在age
    <#else>
    不存在age
</#if>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值