Java使用 FreeMark

一、 使用场景

        FreeMarker是一款模板引擎,可以帮助开发者生成任意类型的文本,包括HTML、XML、JSON、CSS、邮件模板等等。它可以将数据和模板进行绑定,通过填充模板中的占位符来生成最终的文本。FreeMarker最常见的应用场景是在Web开发中生成HTML页面。在Web应用中,数据通常来自于后端,而页面的生成则是由前端负责。通过使用FreeMarker,前端可以使用模板来定义页面的结构和样式,后端则可以将数据填充到模板中,生成最终的HTML页面。

        总之,只要你有模板,就能通过 FreeMark 去生成对应的内容

二、简单的使用

2.1 pom

    <dependencies>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.31</version>
        </dependency>
    </dependencies>

2.2 util

package com.apps.util;


import freemarker.cache.FileTemplateLoader;
import freemarker.cache.MultiTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;

import java.io.File;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

public class FreeMarkUtil {

    //单例
    private static final Configuration cfg =  new Configuration();

    static {
        // 设置默认编码
        cfg.setDefaultEncoding("utf-8");
    }

    public static String process(String templateName, Map<String, Object> root) throws Exception {
        String path = FreeMarkUtil.class.getResource("").getPath();
        //模板的位置,我是放在 /resource 下,我的类路径是 com/apps/util
        path = path.replace("/com/apps/util/","");
        //建议,就算不同文件夹,但是模板文件名也不能相同
        FileTemplateLoader ftl = new FileTemplateLoader(new File(path +"/component_template/"));
        TemplateLoader[] loaders = new TemplateLoader[] { ftl };
        MultiTemplateLoader mul = new MultiTemplateLoader(loaders);
        cfg.setTemplateLoader(mul);

        //创建模版对象
        Template t = cfg.getTemplate(templateName+".json");

        //设置输出流
        StringWriter writer = new StringWriter();
        String result = "";
        try {
            //在模版上执行插值操作,并输出到制定的输出流中
            t.process(root, writer);//root 是模板中的变量的值
            result = writer.toString();
        }catch (Exception e){
            throw new Exception(e);
        }finally {
            writer.close();
        }
        return result;
    }
    // 测试
    public static void main(String[] args) throws Exception {
        HashMap<String, Object> root = new HashMap<>();
        String template = process("template", root);
        System.out.println(template);
    }
}

        用 String process = FreeMarkUtil.process(name, params); 就能拿到 String 对象,就可以转换成自己想要的对象。建议用 JSON.parseObject() 去转换成对象,因为模板大了之后其他工具包可以转换不过来。

2.3 示例

        我的模板是一个简单的 Json 

        使用 main() 生成的如下:

三、 Freemarker 进阶使用

3.1 变量表达式

        在 FreeMarker 中,可以使用以下变量表达式来引用模板中的变量或属性:

1. ${variable}:输出变量的值。
2. ${object.property}:输出对象的属性值。
3. ${map.key}:输出 Map 中指定 key 的值。
4. ${list[index]}:输出列表中指定位置的值。
5. ${variable!‘defaultValue’}:如果变量值为 null,则输出 defaultValue 值。记得有单引号
6. ${variable?size}:输出变量的长度(对于字符串、列表或数组)或元素个数(对于 Map)。
7. ${variable?keys}:输出变量中所有的键(对于 Map)。
8. ${variable?values}:输出变量中所有的值(对于 Map)。
9. ${variable?string}:将变量转换为字符串输出 (没啥用,你存什么格式,就会填什么格式)
10. ${variable?html}:将变量转义为 HTML 格式输出。(没啥用,你存什么格式,就会填什么格式)
11. ${variable?cap_first}:将变量的首字母大写后输出。
12. ${variable?lower_case}:将变量转换为小写字母后输出。
13. ${variable?upper_case}:将变量转换为大写字母后输出。
14. ${variable?date}:将变量转换为日期格式输出。
15. ${variable?number}:将变量转换为数字格式输出。
16. ${variable?c}:将变量格式化为货币金额输出。(没啥用)
17. ${variable?string("UTF-8")}:将变量转换为指定编码格式的字符串输出。(没啥用,换模板的时候设置 UTF-8就可以了)

        这些变量表达式是 FreeMarker 中最常用的,通过使用这些表达式可以方便地在模板中输出变量的值、属性、长度等信息,并进行格式化输出。

3.2 内置指令

FreeMarker 内置指令包括:

1. if、elseif、else:用于条件语句的指令。
2. list、else、items:用于循环语句的指令。
3. include:用于引用其他模板的指令。
4. macro、nested、return:用于宏定义和调用的指令。
5. assign:用于将变量赋值的指令。
6. global、local:用于全局和局部变量的定义和赋值。
7. function:用于定义自定义函数的指令。
8. switch、case、default:用于多分支条件语句的指令。
9. break、stop、recover、rt、escape:用于流程控制的指令。
10. compress、lt、rt、noparse:用于模板格式化和编译优化的指令。

        这些指令可以实现复杂的模板逻辑和数据处理,提高模板的可读性和可维护性。

3.3 条件指令

FreeMarker 内置了多种条件指令,常用的包括:

1. `if`:判断是否满足条件,满足则执行相应的语句块,语法如下:

   <#if condition>
       statement1
       statement2
   <#elseif condition2>
       statement3
   <#else>
       statement4
   </#if>

   其中,`condition` 和 `condition2` 为条件表达式,如果满足则执行 `statement1` 和 `statement2`,如果不满足则判断是否满足 `condition2`,满足则执行 `statement3`,否则执行 `statement4`。

2. `switch`:根据表达式的值进行多条件分支,语法如下:

   <#switch expression>
     <#case value1>
       statement1
     <#case value2>
       statement2
     <#default>
       statement3
   </#switch>

   其中,`expression` 为表达式,`value1`、`value2` 为需要匹配的值,如果匹配则执行相应的语句块,如果都不匹配则执行 `statement3`。

3. `list`:循环遍历一个列表,语法如下:


   <#list sequence as item>
     statement1
     statement2
   </#list>

   其中,`sequence` 为要遍历的列表,`item` 为当前遍历的元素变量名,`statement1` 和 `statement2` 为要执行的语句块。

4. `foreach`:与 `list` 类似,用于遍历一个集合或数组,语法如下:

   <#foreach item in sequence>
     statement1
     statement2
   </#foreach>

   其中,`sequence` 为要遍历的集合或数组,`item` 为当前遍历的元素变量名,`statement1` 和 `statement2` 为要执行的语句块。

5. `assign`:给变量赋值,语法如下:

  <#assign variable=value>

   其中,`variable` 为变量名,`value` 为要赋的值。

这些条件指令可以方便地控制模板的渲染流程和输出结果。

3.4 循环指令

FreeMarker 中常见的循环指令有以下几种:

1. `<#list>` 指令:用于遍历一个序列或集合,通常和 `item`、`index` 等内置变量一起使用,示例代码如下:

   <#list sequenceOrCollection as item>
     ${item_index + 1}. ${item}
   </#list>

   该指令遍历了名为 `sequenceOrCollection` 的序列或集合,并在循环体内使用了 `item` 变量表示当前元素,使用了 `item_index` 变量表示当前元素在序列或集合中的下标(从 0 开始)。

2. `<#foreach>` 指令:与 `<#list>` 类似,用于遍历一个序列或集合,但使用方式略有不同,示例代码如下:

   <#foreach item in sequenceOrCollection>
     ${item_index + 1}. ${item}
   </#foreach>

   该指令同样遍历了名为 `sequenceOrCollection` 的序列或集合,并在循环体内使用了 `item` 变量表示当前元素,使用了 `item_index` 变量表示当前元素在序列或集合中的下标(从 0 开始)。

3. `<#while>` 指令:用于执行一个条件循环,示例代码如下:

   <#assign counter = 0>
   <#while counter < 10>
     ${counter + 1}. Hello, world!<br>
     <#assign counter = counter + 1>
   </#while>

   该指令先将变量 `counter` 初始化为 0,然后执行一个条件循环,在每次循环中输出一条消息,并将 `counter` 加 1,直到 `counter` 大于等于 10 时循环结束。

4. `<#recurse>` 指令:用于执行递归循环,通常与自定义函数一起使用,示例代码如下:

   <#function printNodes nodes>
     <#list nodes as node>
       ${node.name}
       <#if node.children??>
         <ul>
           <#recurse nodes=node.children>
         </ul>
       </#if>
     </#list>
   </#function>

   该指令定义了一个自定义函数 `printNodes`,接受一个 `nodes` 参数,然后遍历 `nodes` 中的所有节点,并递归地输出其子节点的名称,如果当前节点没有子节点,则不输出 `<ul>` 标签。

III. Freemarker进阶
- 自定义指令

FreeMarker允许开发者定义自己的指令。开发者可以自行实现模板指令的功能,以便更好地控制模板的生成。

要定义自己的指令,可以通过实现`TemplateDirectiveModel`接口并覆盖其中的`execute()`方法来实现。在自定义指令中,我们可以通过`Environment`对象访问模板的各个部分,比如输出流和参数。

例如,以下是一个自定义指令的示例,该指令将字符串反转并输出:

public class ReverseDirective implements TemplateDirectiveModel {
    public void execute(Environment env, Map params, TemplateModel[] loopVars, 
                        TemplateDirectiveBody body) throws TemplateException, IOException {
        // 获取参数
        String input = params.get("input").toString();
        // 反转字符串
        String output = new StringBuilder(input).reverse().toString();
        // 输出结果
        Writer out = env.getOut();
        out.write(output);
    }
}

定义好自定义指令后,需要将其注册到FreeMarker的配置中,例如:

Configuration cfg = new Configuration(Configuration.VERSION_2_3_30);
// 注册自定义指令
cfg.setSharedVariable("reverse", new ReverseDirective());

在模板中使用自定义指令:

<@reverse input="Hello, World!"/>

输出:

!dlroW ,olleH

猜你喜欢

转载自blog.csdn.net/qq_37761711/article/details/130630377