Freemarker如何获取自定义指令的未处理原始内容?
如何获取Freemarker自定义指令的原始未处理内容
要解决宏中嵌套内容被预先处理的问题,不能使用Freemarker宏,必须实现自定义TemplateDirectiveModel指令。通过自定义指令,你可以直接获取未解析的原始模板片段,而不是处理后的内容。
核心解决方案思路
Freemarker的宏(#macro)在执行<#nested/>时会立刻处理嵌套内容并输出结果,无法保留原始模板代码。而自定义指令通过DirectiveCallPlace对象可以直接获取指令嵌套的原始未解析字符串,完全符合你的需求。
实现步骤
1. 编写自定义指令类
实现TemplateDirectiveModel接口,在execute方法中获取原始嵌套内容,并完成业务逻辑:
import freemarker.core.DirectiveCallPlace; import freemarker.core.Environment; import freemarker.template.*; import java.io.IOException; import java.util.Map; public class ProcessContentDirective implements TemplateDirectiveModel { @Override public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException { // 解析指令参数:获取name值 SimpleScalar nameParam = (SimpleScalar) params.get("name"); if (nameParam == null) { throw new TemplateModelException("Required parameter 'name' is missing."); } String contentName = nameParam.getAsString(); // 获取原始未处理的嵌套模板内容 DirectiveCallPlace callPlace = env.getCurrentDirectiveCallPlace(); String rawTemplateContent = callPlace.getNestedContentAsString(); // 业务逻辑:从数据库读取或存入原始内容 String storedContent = getFromDatabase(contentName); if (storedContent == null) { saveToDatabase(contentName, rawTemplateContent); storedContent = rawTemplateContent; } // 处理并输出最终内容 Template dynamicTemplate = new Template("dynamic-content", storedContent, env.getConfiguration()); String processedOutput = FreeMarkerTemplateUtils.processTemplateIntoString(dynamicTemplate, env.getDataModel()); env.getOut().write(processedOutput); } // 模拟数据库读取方法 private String getFromDatabase(String name) { // 实际项目中替换为数据库查询逻辑 return null; // 首次访问返回null,触发存入操作 } // 模拟数据库存储方法 private void saveToDatabase(String name, String content) { // 实际项目中替换为数据库插入/更新逻辑 System.out.printf("Saved to DB: name=%s, content=%s%n", name, content); } }
2. 配置Freemarker,注册自定义指令
将自定义指令加入Freemarker配置的共享变量:
Configuration freemarkerCfg = new Configuration(Configuration.VERSION_2_3_32); // 配置模板加载路径、编码等其他设置... freemarkerCfg.setSharedVariable("process", new ProcessContentDirective());
3. 修改模板,使用自定义指令
替换原来的宏调用,使用自定义指令:
<@process name='this-content-name'> <p>This is some content about ${companyName}</p> </@process>
效果验证
运行后,日志(或数据库存储内容)会输出原始模板代码:
Saved to DB: name=this-content-name, content=<p>This is some content about ${companyName}</p>
而不是处理后的This is some content about My Company Name,完全符合你的预期。
内容的提问来源于stack exchange,提问作者cmorris
相关产品推荐
相关产品推荐

