如何使用 Freemarker 模板输出 JSON

Posted

技术标签:

【中文标题】如何使用 Freemarker 模板输出 JSON【英文标题】:How to Use Freemarker Templates to Output JSON 【发布时间】:2021-10-11 16:18:07 【问题描述】:

我有一个应用程序需要处理一些数据并将其输出为 JSON 文件。我认为我可以使用模板库来构造输出,而不是手动处理所有内容。 Freemarker 似乎提供了我正在寻找的东西,但我在处理列表时遇到了问题。

我的数据模型的类如下所示:

public class Order     
    public String orderNumber;
    public Date processed;
    public Boolean release; 
    public List<OrderLine> lines;       


public class OrderLine 
    public String unit;
    public Integer quantity;
    public String itemNumber;

JSON 输出应如下所示:

"OrderNo": "1055249", "OrderDate": "202103251951", "Release": true, "OrderLines": [
"UnitOfMeasure": "EA", "Quantity": "1", "ItemNo": "764724473433",
"UnitOfMeasure": "EA", "Quantity": "1", "ItemNo": "764724810979"
]

注意 OrderLines 列表。我可以很容易地为其他属性组合一个模板,但我不知道如何处理像 OrderLine 这样的重复元素。内置的 list 指令打印出每个元素,但我需要一个逗号分隔的值列表。

有没有人知道在 freemarker 中无需创建自定义指令的方法?如果没有,是否有另一个模板库更适合我正在尝试做的事情?

【问题讨论】:

为什么使用 Freemarker 输出 JSON? (您是否搜索过类似“Java JSON 库”之类的内容?) 【参考方案1】:

您可以使用inbuilt loop vars 生成以逗号分隔的订单行列表。请参考以下示例:

Order.ftl

<#import "OrderLine.ftl" as OrderLine>

    "OrderNo": "$order.orderNumber",
    "OrderDate": "$order.processed?datetime",
    "Release": $order.release?c,
    "OrderLines": [
        <@OrderLine.OrderLine order.lines/>
    ]

OrderLine.ftl

<#macro OrderLine lines>
<#list lines as line>
        
            "unit": "$line.unit",
            "quantity": "$line.quantity",
            "itemNumber": "$line.itemNumber"
        <#if line?is_last == false>,</#if>
</#list>
</#macro>

在上面的ftl 中,我使用?is_last 循环变量在列表中的两个订单行对象之间添加comma (,)

另外,&lt;#if line?is_last == false&gt;,&lt;/#if&gt; 可以替换为 &lt;#sep&gt;,&lt;/#sep&gt;。 check sep directive

FreemarkerService.java

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import freemarker.template.Configuration;
import freemarker.template.Template;

public class FreemarkerService 

    private static final Configuration CONFIGURATION = new Configuration(Configuration.VERSION_2_3_0);

    public static void main(String args[]) throws Exception 
        OrderLine orderLine   = new OrderLine("EA", 1, "764724473433");
        OrderLine orderLine2  = new OrderLine("EA", 1, "764724810979");
        List<OrderLine> lines = new ArrayList<>();
        lines.add(orderLine);
        lines.add(orderLine2);

        Order order = new Order("1055249", new Date(), true, lines);

        Map<String, Object> input = new HashMap<>();
        input.put("order", order);

        String json = generateJsonByTemplate("Order.ftl", input);

        System.out.println(json);
    

    public static String generateJsonByTemplate(String templateName, Map<String, Object> input) throws Exception
    
        String sourceCode = null;

        try
        
            Template template   = CONFIGURATION.getTemplate(templateName);
            StringWriter writer = new StringWriter();

            template.process(input, writer);
            sourceCode = writer.toString();
        
        catch (Exception exception)
        
            throw new Exception("Processing failed for template '" + templateName  + "' with error: " + exception.getMessage(), exception);
        

        return sourceCode;
    

输出:


    "OrderNo": "1055249",
    "OrderDate": "Aug 7, 2021 11:43:34 AM",
    "Release": true,
    "OrderLines": [
        
            "unit": "EA",
            "quantity": "1",
            "itemNumber": "764724473433"
        ,
        
            "unit": "EA",
            "quantity": "1",
            "itemNumber": "764724810979"
        
    ]

【讨论】:

&lt;#if line?is_last == false&gt;,&lt;/#if&gt; 可以替换为&lt;#sep&gt;,。 (此外,something == false 等任何条件都可以替换为 !something。) 指令正是我所需要的。谢谢!

以上是关于如何使用 Freemarker 模板输出 JSON的主要内容,如果未能解决你的问题,请参考以下文章

如何在 freemarker 模板处理中转义 unicode 符号?

如何在freemarker中转义json字符串

如何在 Freemarker 中输出 $expression 而不会被解释?

模板引擎freemarker动态更新生成JSON模板字段值,Java

模板引擎freemarker动态更新生成JSON模板字段值,Java

Java模板引擎 FreeMarker