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

Spring Boot FreeMarker如何动态使用非磁盘来源的自定义模板?

解决方案

核心结论

你完全不需要将ftl模板存储到磁盘,也不需要固定配置模板路径即可实现需求。SpringTemplateLoader是针对从Spring资源路径批量加载模板的场景设计的,若仅需要直接处理byte[]形式的单模板,完全可以绕开它直接使用FreeMarker原生API实现。


方案1:直接处理byte[]模板(适配你的测试用例)

FreeMarker的Template类支持直接从字符串内容构造,无需依赖任何模板加载器,你可以直接按如下方式实现工具类:

import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.stereotype.Component;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.Map;

@Component
public class FreeMarkerUtil {
    // 直接注入Spring Boot自动配置好的FreeMarker全局配置,线程安全可全局复用
    private final Configuration freeMarkerConfig;

    public FreeMarkerUtil(Configuration freeMarkerConfig) {
        this.freeMarkerConfig = freeMarkerConfig;
    }

    public String getContentFromTemplate(byte[] templateBytes, Map<String, ?> model) throws Exception {
        // byte[]转字符串,使用UTF-8编码和模板默认编码保持一致
        String templateContent = new String(templateBytes, StandardCharsets.UTF_8);
        // 直接构造临时Template对象,不需要配置模板路径
        Template template = new Template(
                "temp_template", // 临时模板名称,无特殊业务要求可随意填写
                new StringReader(templateContent),
                freeMarkerConfig
        );
        // 渲染模板并返回结果
        StringWriter writer = new StringWriter();
        template.process(model, writer);
        return writer.toString();
    }
}

该实现完全适配你给出的测试用例,无需修改原有测试代码即可直接运行。


方案2:自定义模板加载器(适配多来源模板统一加载场景)

如果你需要统一管理来自数据库、文件、远程接口等多来源的模板,可以自定义实现FreeMarker的TemplateLoader接口,不需要使用SpringTemplateLoader:

步骤1:实现自定义模板加载器

import freemarker.cache.TemplateLoader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;

public class MultiSourceTemplateLoader implements TemplateLoader {
    // 注入你的模板数据访问类,比如数据库Mapper
    private final TemplateMapper templateMapper;

    public MultiSourceTemplateLoader(TemplateMapper templateMapper) {
        this.templateMapper = templateMapper;
    }

    @Override
    public Object findTemplateSource(String templateId) throws IOException {
        // 此处根据模板标识从任意来源获取模板内容
        // 示例:根据模板ID从数据库查询模板字节数组
        byte[] templateBytes = templateMapper.selectContentById(templateId);
        if (templateBytes == null) {
            return null;
        }
        return new String(templateBytes, StandardCharsets.UTF_8);
    }

    @Override
    public long getLastModified(Object templateSource) {
        // 返回模板最后修改时间,用于缓存校验,不需要缓存可直接返回0
        return System.currentTimeMillis();
    }

    @Override
    public Reader getReader(Object templateSource, String encoding) throws IOException {
        return new StringReader((String) templateSource);
    }

    @Override
    public void closeTemplateSource(Object templateSource) throws IOException {
        // 不需要资源清理可留空
    }
}

步骤2:替换FreeMarker默认配置

import org.springframework.context.annotation.Bean;

@org.springframework.context.annotation.Configuration
public class FreeMarkerCustomConfig {
    @Bean
    public freemarker.template.Configuration freeMarkerConfiguration(TemplateMapper templateMapper) {
        freemarker.template.Configuration config = new freemarker.template.Configuration(freemarker.template.Configuration.VERSION_2_3_31);
        config.setDefaultEncoding("UTF-8");
        // 替换为自定义的多来源模板加载器
        config.setTemplateLoader(new MultiSourceTemplateLoader(templateMapper));
        return config;
    }
}

配置完成后,你可以直接通过configuration.getTemplate("模板ID")方法加载任意来源的模板。


内容的提问来源于stack exchange,提问作者Al Phaba

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 10:30:01