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
相关产品推荐
相关产品推荐

