You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为Freemarker的Java List<Map>变量重写toString()遇遍历问题求助

问题分析与解决方案

你的问题出在自定义包装类的实现逻辑上:你继承DefaultObjectWrapper包装后的对象被FreeMarker识别成了StringModel(因为它优先支持字符串输出),而StringModel同时实现了TemplateHashModel接口,所以FreeMarker会把它当作哈希结构而非序列(List)处理,遍历的时候就要求你指定键值对变量。

要同时满足两种需求,你不需要继承DefaultObjectWrapper,而是让自定义包装类同时实现TemplateScalarModel和TemplateSequenceModel,这样FreeMarker既能识别它是可遍历的序列,又能直接输出字符串。

具体实现步骤

  • 自定义包装类,持有List<Map>的实例,同时实现两个核心接口:

    1. TemplateScalarModel:负责处理${myListOfMapsVar}的字符串输出,在getAsString()方法中返回列表的toString()结果。
    2. TemplateSequenceModel:负责支持<#list>遍历,实现size()和get(int index)方法,注意返回的Map对象需要用默认包装器处理,才能在模板中通过item.mapKeyName访问属性。
  • 代码示例:

import freemarker.template.*;
import java.util.List;
import java.util.Map;

public class ListOfMapsWrapper implements TemplateScalarModel, TemplateSequenceModel {
    private final List<Map<String, Object>> targetList;
    private final ObjectWrapper defaultWrapper;

    public ListOfMapsWrapper(List<Map<String, Object>> targetList, ObjectWrapper defaultWrapper) {
        this.targetList = targetList;
        // 传入默认包装器,用来处理List中的Map对象
        this.defaultWrapper = defaultWrapper;
    }

    // 处理${}输出字符串
    @Override
    public String getAsString() throws TemplateModelException {
        return targetList.toString();
    }

    // 处理list遍历的长度
    @Override
    public int size() throws TemplateModelException {
        return targetList.size();
    }

    // 获取遍历的每个元素,并用默认包装器包装Map
    @Override
    public TemplateModel get(int index) throws TemplateModelException {
        if (index < 0 || index >= targetList.size()) {
            return null;
        }
        Map<String, Object> map = targetList.get(index);
        return defaultWrapper.wrap(map);
    }
}
  • 使用方式:
    在把List<Map>放入模板上下文时,用这个自定义包装类包装:
// 获取默认包装器(不能修改全局配置的话,直接用FreeMarker的默认实例)
ObjectWrapper defaultWrapper = DefaultObjectWrapper.getDefaultInstance(Configuration.VERSION_2_3_32);
List<Map<String, Object>> myList = ...; // 你的List<Map>数据
templateModel.put("myListOfMapsVar", new ListOfMapsWrapper(myList, defaultWrapper));

这样处理后,模板中既可以用${myListOfMapsVar}输出字符串,也可以用<#list myListOfMapsVar as item>遍历,直接通过item.mapKeyName访问Map中的属性。

内容的提问来源于stack exchange,提问作者Mark Roy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 18:24:27