如何使用 Freemarker 模板输出 JSON
How to Use Freemarker Templates to Output JSON
我有一个应用程序需要处理一些数据并将其输出为 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 中执行此操作的方法吗?如果没有,是否有另一个模板库更适合我正在尝试做的事情?
您可以使用 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 (,)
。
另外,<#if line?is_last == false>,</#if>
可以用<#sep>,</#sep>
代替。 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"
}
]
}
我有一个应用程序需要处理一些数据并将其输出为 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 中执行此操作的方法吗?如果没有,是否有另一个模板库更适合我正在尝试做的事情?
您可以使用 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 (,)
。
另外,<#if line?is_last == false>,</#if>
可以用<#sep>,</#sep>
代替。 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"
}
]
}