当前位置:首页 > 后端开发 > 正文

FTL中如何加入Java代码

FreeMarker模板中可通过预定义变量或自定义指令间接调用Java对象方法实现逻辑嵌入

核心概念:FTL 与 Java 的交互机制

FreeMarker 不直接支持在模板中编写 Java 逻辑(这是设计原则),而是通过数据模型(Data Model)指令(Directives) 实现动态内容生成,正确做法是将 Java 逻辑写在后台代码中,通过数据模型向模板暴露所需对象或方法。


安全嵌入 Java 功能的三种方式

变量表达式:访问 Java 对象属性/方法

<#-- 后台传递 User 对象到数据模型 -->
${user.name}       <#-- 调用 user.getName() -->
${user.calculateAge()} <#-- 调用无参方法 -->

注意

  • 方法必须是 public 且无副作用(不修改数据状态)。
  • 避免暴露敏感方法(如 setPassword())。

指令:控制逻辑与数据遍历

<#-- 条件判断 -->
<#if user.isAdmin>
  <p>管理员权限面板</p>
</#if>
<#-- 遍历集合 -->
<#list orders as order>
  ${order.id} - ${order.amount}
</#list>

自定义指令(高级):封装复杂逻辑

步骤
① 创建实现 TemplateDirectiveModel 的 Java 类

public class FormatDateDirective implements TemplateDirectiveModel {
  @Override
  public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) {
    Date date = (Date) params.get("date");
    String format = params.get("format").toString();
    SimpleDateFormat sdf = new SimpleDateFormat(format);
    env.getOut().write(sdf.format(date));
  }
}

② 将指令注册到配置

configuration.setSharedVariable("formatDate", new FormatDateDirective());

③ 在 FTL 中调用

FTL中如何加入Java代码  第1张

<@formatDate date=now format="yyyy-MM-dd HH:mm"/>

严格禁止的做法(安全风险)

在模板内编写 Java 代码
FreeMarker 不支持类似 JSP 的 <% %> 脚本,强行嵌入会破坏模板引擎结构,导致解析错误。

通过反射调用受限方法
${object.class.getDeclaredMethod("privateMethod").invoke(...)} 违反安全沙箱规则。


最佳实践与规范

  1. 逻辑与表现分离

    • 业务计算、数据库操作等应在 Java 服务层完成。
    • 模板仅负责数据展示和简单格式处理。
  2. 数据预处理
    在 Java 端将数据转换为模板友好格式:

    Map<String, Object> model = new HashMap<>();
    model.put("price", NumberFormat.getCurrencyInstance().format(product.getPrice()));
  3. 使用内置函数减少 Java 依赖
    FTL 提供丰富内置函数(如 ?date, ?string):

    ${rawDate?string("yyyy-MM-dd")}  <#-- 日期格式化 -->
    ${longText?substring(0,100)}     <#-- 截取字符串 -->
  4. Null 值安全处理
    避免空指针异常:

    ${user.birthday!}          <#-- 空值替换为空字符串 -->
    ${user.birthday!"N/A"}     <#-- 自定义默认值 -->

为什么这样设计?(权威性解释)

FreeMarker 通过严格分离逻辑层与视图层

  • 安全性:防止模板注入攻击(如任意代码执行)。
  • 可维护性:修改业务逻辑无需重构模板。
  • 性能:模板编译后可高效执行。
  • 符合 MVC 架构规范,被 Spring、Apache 等项目官方推荐。

常见问题解答

Q:能否在 FTL 中调用静态方法?
A:需通过 Configuration 注册静态工具类:

configuration.setSharedVariable("MathUtils", new StaticModels("com.example.MathUtils"));

模板调用: ${MathUtils.round(3.1415, 2)}

Q:如何调试数据模型内容?
A:使用 FTL 内省函数:

<#-- 输出所有可用变量 -->
<#list .data_model?keys as key> 
  ${key} = ${.data_model[key]?string} 
</#list>

工具链推荐

  • Spring Boot 集成
    spring-boot-starter-freemarker 自动配置数据绑定。
  • IDE 插件
    IntelliJ IDEA 的 FreeMarker 支持(语法高亮、调试)。
  • 在线测试工具
    FreeMarker 在线沙箱

引用说明: 基于 FreeMarker 官方文档安全规范(Apache FreeMarker Manual)及 OWASP 模板引擎安全指南,技术方案遵循 Spring Framework 最佳实践,确保企业级应用安全性。

0