
FreeMarker允许开发者通过实现TemplateDirectiveModel或TemplateMethodModelEx接口,在Java代码中对模板参数进行自定义逻辑处理。本文将详细介绍如何利用这两种方式,在Java中获取并比较FreeMarker模板变量的值,并根据条件修改或返回新值,例如实现参数验证或格式化,以增强模板的动态性和灵活性。
FreeMarker模板引擎提供了强大的数据模型和表达式语言,但在某些场景下,我们需要在Java层面对模板变量进行更复杂的逻辑判断、数据转换或业务规则校验。例如,当一个模板变量需要根据特定条件进行格式化或替换时,纯粹的FreeMarker表达式可能无法满足需求,或者会导致模板逻辑过于复杂。本文将探讨如何通过自定义指令(TemplateDirectiveModel)和自定义方法(TemplateMethodModelEx)在Java代码中获取并处理FreeMarker模板参数,以实现诸如“检查 accNo 是否大于 0,否则设置为 0000”之类的业务逻辑。
1. 使用自定义指令 (TemplateDirectiveModel)
自定义指令类似于HTML标签,用于生成内容块或执行副作用。它通过实现TemplateDirectiveModel接口来实现,允许开发者在FreeMarker模板中定义自己的标签,并在Java代码中控制这些标签的行为。
1.1 获取参数方式
在TemplateDirectiveModel的execute方法中,可以通过两种主要方式获取模板参数:
立即学习“Java免费学习笔记(深入)”;
作为指令参数传入:这是最常见且推荐的方式,参数直接通过指令的属性传递。例如,在模板中使用 ,则在Java代码中可以通过params Map获取到value参数。作为环境变量获取:如果指令本身不接受参数,但需要访问模板环境中已定义的变量(例如 ),则可以通过Environment对象的getVariable()方法获取。这种方式相对不推荐,因为它降低了指令的独立性和可读性。
1.2 Java实现示例 (AccNoDirective.java)
以下是一个实现TemplateDirectiveModel的Java类,它接收一个名为value的参数,检查其是否为大于0的数字,并根据条件输出原始值或”0000″。
import freemarker.core.Environment;import freemarker.template.*;import java.io.IOException;import java.io.Writer;import java.util.Map;/** * 自定义FreeMarker指令,用于处理账户号码。 * 如果账户号码大于0,则输出其值;否则输出"0000"。 */public class AccNoDirective implements TemplateDirectiveModel { @Override public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException { // 1. 尝试从指令参数中获取 'value' TemplateScalarModel valueModel = (TemplateScalarModel) params.get("value"); String accNoStr = null; if (valueModel != null) { accNoStr = valueModel.getAsString(); } else { // 2. 如果指令参数中没有 'value',则尝试从环境变量中获取 'accNo' (不推荐,但作为示例) TemplateModel accNoVar = env.getVariable("accNo"); if (accNoVar instanceof TemplateScalarModel) { accNoStr = ((TemplateScalarModel) accNoVar).getAsString(); } else if (accNoVar instanceof TemplateNumberModel) { accNoStr = ((TemplateNumberModel) accNoVar).getAsNumber().toString(); } } String result = "0000"; // 默认值 if (accNoStr != null && !accNoStr.trim().isEmpty()) { try { long accNo = Long.parseLong(accNoStr); if (accNo > 0) { result = accNoStr; } } catch (NumberFormatException e) { // 处理非数字输入,可以抛出异常或输出错误信息 env.getOut().write("Error: accNo parameter is not a valid number."); return; } } // 将结果写入输出流 env.getOut().write(result); }}
1.3 FreeMarker模板使用示例
为了在模板中使用上述指令,需要先在FreeMarker配置中注册它。假设已注册为accNoDirective。
{ "Account_Number" : "" }{ "Account_Number" : "" }{ "Account_Number" : "" }{ "Account_Number" : "" }{ "Account_Number" : "" }{ "Account_Number" : "" }
注意事项: TemplateDirectiveModel主要用于生成内容或控制模板流。直接操作env.getOut().write()会将内容直接写入FreeMarker的输出流。
TextCortex
AI写作能手,在几秒钟内创建内容。
62 查看详情
2. 使用自定义方法 (TemplateMethodModelEx)
自定义方法类似于函数,用于计算并返回一个值。它通过实现TemplateMethodModelEx接口来实现,是处理单个值转换或计算的更典型和推荐的方式。
2.1 获取参数方式
TemplateMethodModelEx的exec方法接收一个List类型的arguments参数,其中包含了FreeMarker模板中调用该方法时传入的所有参数。这些参数通常是TemplateModel的子类(如TemplateScalarModel、TemplateNumberModel等)。
2.2 Java实现示例 (AccNoMethod.java)
以下是一个实现TemplateMethodModelEx的Java类,它接收一个参数,检查其是否为大于0的数字,并返回原始值或”0000″。
import freemarker.template.TemplateMethodModelEx;import freemarker.template.TemplateModelException;import freemarker.template.TemplateScalarModel;import freemarker.template.SimpleScalar;import java.util.List;/** * 自定义FreeMarker方法,用于处理账户号码。 * 如果账户号码大于0,则返回其值;否则返回"0000"。 */public class AccNoMethod implements TemplateMethodModelEx { @Override public Object exec(List arguments) throws TemplateModelException { if (arguments.isEmpty()) { throw new TemplateModelException("AccNoMethod expects at least one argument."); } // 获取第一个参数 Object arg0 = arguments.get(0); if (!(arg0 instanceof TemplateScalarModel)) { throw new TemplateModelException("The argument must be a scalar (string or number)."); } TemplateScalarModel accNoModel = (TemplateScalarModel) arg0; String accNoStr = accNoModel.getAsString(); String result = "0000"; // 默认值 if (accNoStr != null && !accNoStr.trim().isEmpty()) { try { long accNo = Long.parseLong(accNoStr); if (accNo > 0) { result = accNoStr; } } catch (NumberFormatException e) { // 抛出异常,让FreeMarker捕获并处理 throw new TemplateModelException("Argument is not a valid number: " + accNoStr, e); } } // 必须返回一个TemplateModel对象 return new SimpleScalar(result); }}
2.3 FreeMarker模板使用示例
同样,为了在模板中使用此方法,需要在FreeMarker配置中注册它。假设已注册为accNoMethod。
{ "Account_Number" : "${accNoMethod(accNo1)}" }{ "Account_Number" : "${accNoMethod(accNo2)}" }{ "Account_Number" : "${accNoMethod(accNo3)}" }{ "Account_Number" : "${accNoMethod(accNo4)}" }
注意事项: TemplateMethodModelEx必须返回一个TemplateModel对象(如SimpleScalar、SimpleNumber等)。
3. 注册自定义指令/方法
在Java应用程序中,需要将自定义指令或方法注册到FreeMarker的Configuration实例中,以便模板能够识别和使用它们。通常通过setSharedVariable方法完成。
import freemarker.template.Configuration;import freemarker.template.Version;import freemarker.template.TemplateExceptionHandler;public class FreeMarkerConfigurator { public static Configuration createFreeMarkerConfiguration() { // 创建FreeMarker配置实例,并指定FreeMarker版本 Configuration cfg = new Configuration(new Version("2.3.31")); // 设置模板加载器 (例如,从类路径加载模板) cfg.setClassForTemplateLoading(FreeMarkerConfigurator.class, "/templates"); // 设置默认编码 cfg.setDefaultEncoding("UTF-8"); // 设置异常处理器 (开发环境通常设置为HTML_DEBUG_HANDLER,生产环境设置为RETHROW_HANDLER) cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); // 注册自定义指令 cfg.setSharedVariable("accNoDirective", new AccNoDirective()); // 注册自定义方法 cfg.setSharedVariable("accNoMethod", new AccNoMethod()); return cfg; } // 示例:如何使用配置渲染模板 /* public static void main(String[] args) throws Exception { Configuration cfg = createFreeMarkerConfiguration(); Template template = cfg.getTemplate("my_template.ftl"); Map data = new HashMap(); data.put("someVariable", "Hello"); // 渲染模板到控制台 template.process(data, new OutputStreamWriter(System.out)); } */}
4. 总结与最佳实践
选择依据:当需要根据条件生成大段HTML、JSON或其他文本内容,或控制模板的执行流程时,使用TemplateDirectiveModel。它更适合处理有副作用或需要渲染复杂内容的场景。当需要对单个或少量参数进行计算、转换并返回一个值时,TemplateMethodModelEx是更简洁、更符合函数式编程思维的选择。对于本例中的“检查accNo并返回一个值”的需求,TemplateMethodModelEx是更优解,因为它专注于返回一个处理后的值,而不是直接操作输出流。类型处理: 在Java代码中,从TemplateModel转换为具体类型(如TemplateScalarModel、TemplateNumberModel)时,务必进行类型检查(instanceof)和异常处理(try-catch),以避免运行时错误。错误处理: 自定义方法和指令应妥善处理异常,例如参数类型不匹配、业务逻辑错误等。对于方法,可以通过抛出TemplateModelException来通知FreeMarker模板渲染失败;对于指令,可以直接向输出流写入错误信息,或者抛出异常。可读性与维护性: 优先使用指令或方法的参数来传递数据,而不是依赖环境变量。这能提高模板的可读性,使指令/方法的输入更加明确,也更易于测试和维护。性能考量: 自定义指令和方法会在每次模板渲染时执行其Java代码。确保其中的逻辑高效,避免不必要的计算或资源消耗。
通过合理地利用FreeMarker的自定义指令和方法
以上就是Apache FreeMarker自定义指令与方法:在Java中处理模板参数值的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/968709.html
微信扫一扫
支付宝扫一扫