如何在Freemarker中创建子数据列表以进行循环

huangapple go评论107阅读模式
英文:

How to create lists of subdata to loop through in Freemarker

问题

我正在寻找一种使用Freemarker生成按dataType(整数)分组的报告的方法,根据数据项列表。

所以,例如,我有:

data.datatype = 1,其中data的id = 1
data.datatype = 1,其中data的id = 4
data.datatype = 1,其中data的id = 7
data.datatype = 3,其中data的id = 2
data.datatype = 3,其中data的id = 3
data.datatype = 4,其中data的id = 5
...等等

这个序列按数据类型排序,但同时我需要保持数据项按其相应的顺序(次要排序顺序)。

我还在使用类似函数的宏。理想情况下,我希望有<#macro rendertable filteredDatatypelist datatype>

在过去,我调用宏来基于当前数据类型呈现标题、页脚和行,但我试图摆脱这种做法,希望有一个单一的宏来呈现每个数据类型的子列表上的整个表格。

也就是说,将数据项列表发送给宏。所以,例如,在上述数据中,我会调用rendertable宏3次,分别针对数据类型1、3和4。

我尝试创建使用filter的子列表,但这似乎可能会导致性能问题,每个数据类型的时间复杂度为O(n)。即使如此,我也不确定它会如何正常工作。***还请注意,我不知道有多少数据类型或它们的值是什么。***我还查看了seq_index_ofseq_last_index_of,但同样我不知道不同的数据类型会是什么。***我考虑首先创建一个唯一数据类型的列表,但我也不知道如何做。***换句话说,我不知道如何做类似于

<#assign dataForDataType = dataList?filter(data.datatype = 1)>
<#list dataForDataType as x>$<@renderTable x 1></#list>

***除非在上述情况下,我硬编码数据类型,它仅适用于硬编码的一个数据类型。***即使它是O(n),我认为我可以接受,但问题是我不知道如何对数据类型列表执行此操作。如何实现这一点将不胜感激。

英文:

I'm looking for a way to generate a grouped by report using Freemarker based on the dataType (int) from a list of data items.

So for example I have:

data.datatype = 1 where data has id = 1
data.datatype = 1 where data has id = 4
data.datatype = 1 where data has id = 7
data.datatype = 3 where data has id = 2
data.datatype = 3 where data has id = 3
data.datatype = 4 where data has id = 5
... and so on

The sequence is sorted by datatype but at the same time I need to keep the data items in their respective order (secondary sort order).

I'm also using macros like functions. Ideally I'd love to have &lt;#macro rendertable filteredDatatypelist datatype&gt;

In the past I did called a macro to render the header, footer, and row based on the current datatype but I'm trying to move away from that and have a single macro to render the whole table on the sublist for each datatype.

That is to say send the macro a list of the data items for the datatype. So for example in the above data I would call the rendertable macro 3 times, once for datatype 1, 3, and 4.

I looked at trying to create a sublist using filter but this seemed like it could be a performance issue with O(n) for each datatype. Not ideal but even then I'm not sure how it would work exactly. Also please note that I have no idea how many datatypes there are or what their values could be. I also looked at seq_index_of and seq_last_index_of but again I don't know what the different datatypes will be. I considered creating a list of unique datatypes first but I have no idea how to do that either. In other words I'm not sure how to even do something like

&lt;#assign dataForDataType = dataList?filter(data.datatype = 1)&gt;
&lt;#list dataForDataType as x&gt;$&lt;@renderTable x 1&gt;&lt;/#list&gt;

Except that in the case above I'm hardcoding the datatype and it only works for one datatype that is hardcoded. Even if it's O(n) I think I would be ok with it but the issue is that I don't know how to do it for a list of datatypes. Any help on how this can be achieved would be greatly appreciated.

答案1

得分: 0

我最终做的是创建一个扩展接口 TemplateMethodModelEx 的类,该类接受数据列表并返回数据类型列表。然后,我通过循环遍历数据类型,使用另一个函数从另一个 TemplateMethodModelEx 中获取特定数据类型的数据项。示例代码如下:

<#assign datatypes = getDistinctDataTypes(dataList)/>
<#list datatypes as datatype>
    数据类型: ${datatype.id}
    <#list getDataForDatatype(dataList, datatype) as data>
        ${data.whatever}
    </#list>
</#list>

然后,我创建了类似以下示例的类:

public class GetDistinctDataTypes implements TemplateMethodModelEx {
    @Override
    public Object exec(List arguments) throws TemplateModelException {
        // 测试代码省略,假设一切都能正常工作
        DefaultListAdapter defaultListAdapter = ((DefaultListAdapter)arguments.get(0));
        List<Data> dataList = (List<Data>)defaultListAdapter.getWrappedObject();
        // 进行必要的操作并返回数据类型列表
        return getDistinctDataTypesListFromDataList(dataList);
    }
}

然后,我将该方法添加到配置中,以便在模板中使用。你可以在FreeMarker文件中执行这一操作,但我认为在Java代码中更好。

CONFIGURATION.setSharedVariable("getDistinctDataTypes", new GetDistinctDataTypes());

有关更多关于 方法指令 的详细信息,请参阅FreeMarker文档页面。

英文:

What I ended up doing was creating a class that extended the interface TemplateMethodModelEx that would take in the list of data and then return a list of datatypes. I then looped through the datatypes and then using another function got the list of data items for a specific datatypes through another TemplateMethodModelEx.

Something along the lines of:

&lt;#assign datatypes = getDistinctDataTypes(dataList)/&gt;
&lt;#list datatypes as datatype&gt;
    Datatype: ${datatype.id}
    &lt;#list getDataForDatatype(dataList, datatype) as data&gt;
        ${data.whatever}
     &lt;/#list&gt;
&lt;/#list&gt;

Then I have classes such as this example:

public class GetDistinctDataTypes implements TemplateMethodModelEx {
    @Override
    public Object exec(List arguments) throws TemplateModelException
    {
        // Testing code is omitted for brevity and everything is assumed to just work and be correct.
        DefaultListAdapter defaultListAdapter = ((DefaultListAdapter)arguments.get(0));
        List&lt;Data&gt; dataList = (List&lt;Data&gt;)defaultListAdapter.getWrappedObject();
        // Do what I need and return list of datatypes
        return getDistinctDataTypesListFromDataList(dataList);
    }
}

I then also added the method to the Configuration so that it can be used. You can do it in the freemarker file but I find it's better in the Java code.

CONFIGURATION.setSharedVariable(&quot;getDistinctDataTypes&quot;, new GetDistinctDataTypes());

You can find more details on the following Freemarker document page about method directives.

huangapple
  • 本文由 发表于 2023年3月7日 01:17:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/75653869.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定