在Freemarker模板开发中,处理集合数据的动态分组并批量渲染子列表是常见需求,这种场景无需将分组逻辑全部放到后端,通过Freemarker内置的指令就能高效实现。

核心实现思路
实现动态分组并渲染子列表的核心逻辑分为三步:首先遍历原始数据集合,按照指定字段提取分组标识;然后通过映射结构缓存每个分组下的子列表数据;最后遍历所有分组,批量渲染每个分组对应的子列表内容。
基础数据分组实现
假设后端传递的原始数据集合为userList,每个用户对象包含deptId和deptName部门信息、userName用户名称,需要按照部门分组渲染用户列表,实现代码如下:
<#-- 第一步:定义分组映射,key为部门ID,value为该部门下的用户列表 -->
<#assign deptUserMap = {} />
<#-- 第二步:遍历原始用户列表,动态构建分组映射 -->
<#list userList as user>
<#-- 获取当前用户的部门ID作为分组键 -->
<#assign deptId = user.deptId />
<#-- 判断分组键是否已存在,不存在则初始化空列表 -->
<#if !deptUserMap?keys?seq_contains(deptId)>
<#assign deptUserMap = deptUserMap + {deptId: []} />
</#if>
<#-- 将当前用户添加到对应分组的列表中 -->
<#assign currentList = deptUserMap[deptId] />
<#assign newList = currentList + [user] />
<#assign deptUserMap = deptUserMap + {deptId: newList} />
</#list>
<#-- 第三步:遍历分组映射,批量渲染每个部门的子列表 -->
<#list deptUserMap?keys as deptId>
<h3>部门:${userList?filter(user -> user.deptId == deptId)[0].deptName}</h3>
<ul>
<#list deptUserMap[deptId] as user>
<li>用户名称:${user.userName}</li>
</#list>
</ul>
</#list>
动态分组规则扩展
如果分组规则不是固定字段,而是需要动态传入分组字段名,比如有时候按部门分组,有时候按角色分组,可以通过传递分组字段参数实现通用分组逻辑:
<#-- groupField为动态传入的分组字段名,比如deptId、roleId -->
<#assign groupMap = {} />
<#list dataList as item>
<#assign groupKey = item[groupField] />
<#if !groupMap?keys?seq_contains(groupKey)>
<#assign groupMap = groupMap + {groupKey: []} />
</#if>
<#assign tempList = groupMap[groupKey] />
<#assign groupMap = groupMap + {groupKey: tempList + [item]} />
</#list>
<#-- 渲染分组后的子列表 -->
<#list groupMap?keys as key>
<h4>分组标识:${key}</h4>
<ul>
<#list groupMap[key] as item>
<li>${item.name}</li>
</#list>
</ul>
</#list>
注意事项
- Freemarker中不能直接修改已有映射的单个键值,需要通过重新赋值整个映射的方式更新分组数据,避免赋值逻辑错误。
- 如果原始数据量较大,建议优先在后端完成分组后传递给模板,减少模板内的运算开销,提升页面渲染效率。
- 分组渲染时如果需要展示分组对应的描述信息,比如部门名称,需要确保原始数据中所有同分组的描述信息一致,或者通过额外传递分组描述映射的方式获取。
常见场景示例
比如需要按照日期分组展示订单列表,后端传递orderList,每个订单包含orderDate下单日期、orderId订单ID、orderAmount订单金额,实现代码如下:
<#assign dateOrderMap = {} />
<#list orderList as order>
<#assign orderDate = order.orderDate />
<#if !dateOrderMap?keys?seq_contains(orderDate)>
<#assign dateOrderMap = dateOrderMap + {orderDate: []} />
</#if>
<#assign tmpList = dateOrderMap[orderDate] />
<#assign dateOrderMap = dateOrderMap + {orderDate: tmpList + [order]} />
</#list>
<#list dateOrderMap?keys as date>
<h3>下单日期:${date}</h3>
<table border="1" cellpadding="5" cellspacing="0">
<tr>
<th>订单ID</th>
<th>订单金额</th>
</tr>
<#list dateOrderMap[date] as order>
<tr>
<td>${order.orderId}</td>
<td>${order.orderAmount}</td>
</tr>
</#list>
</table>
</#list>
Freemarker动态分组批量渲染数据分组子列表渲染修改时间:2026-06-25 08:33:35