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

Freemarker模板调用Java方法返回HTML字符串的实现及转义问题

关于Freemarker模板中Java生成HTML字符串的转义疑问

我用Freemarker(FTL)模板生成HTML页面,传入了一个包含元素列表的对象。因为要实现复杂逻辑——按key渲染表格行,无对应元素时渲染空行——如果用Freemarker的if、list指令实现,模板代码会冗余复杂,还得重复写逻辑。

所以我打算用Java代码实现表格行的渲染逻辑,写了renderRow方法生成HTML行字符串,示例代码如下:

...
public String renderRow(String key){
    StringBuilder sb = new StringBuilder();
    if(elements.contains(key)){
        for(var element: elements.get(key)){
            sb.append("<tr>");
            sb.append("<td>");
            sb.append(element.getNumber());
            // 其他HTML拼接逻辑
            ...
        }
    } else {
        sb.append(makeEmptyRow());
    }
    return sb.toString(); // 这里需要转义吗?
}
...

测试时在FTL里调用${object.renderRow("key")}能直接把返回的字符串渲染成HTML,但我没做转义处理,现在疑惑:是否需要手动转义?正确的转义方式是什么?


回答

核心结论

是否需要转义取决于你拼接的内容是否包含用户输入或不可信数据:

  • 如果element.getNumber()或其他拼接的内容是固定值/可信后端数据,不会出现<、>、&这类HTML特殊字符,那暂时不需要转义也不会有问题。
  • 如果内容来自用户输入、第三方接口或其他不可信来源,必须做转义——否则会引发XSS攻击,还可能破坏HTML结构。

正确的转义方式

不要自己手动替换特殊字符(容易遗漏),用成熟工具类或Freemarker自带能力处理:

方式1:让Freemarker接管转义(推荐)

把renderRow返回的内容改成纯文本数据结构,而非拼接好的HTML字符串,然后在FTL模板里用?html指令转义:
比如Java方法返回元素列表或空行标记,FTL里:

<#if object.hasElements("key")>
    <#list object.getElements("key") as element>
        <tr>
            <td>${element.number?html}</td>
            <!-- 其他字段同样用?html转义 -->
        </tr>
    </#list>
<#else>
    <tr><td colspan="N"></td></tr> <!-- N是表格列数 -->
</#if>

这种方式符合Freemarker最佳实践,逻辑与视图分离,代码更易维护,也不用自己处理转义细节。

方式2:在Java代码中手动转义

如果坚持要在Java里拼接HTML,用Apache Commons Text的StringEscapeUtils或Freemarker自带工具类转义:

// Apache Commons Text 示例
import org.apache.commons.text.StringEscapeUtils;

sb.append(StringEscapeUtils.escapeHtml4(element.getNumber().toString()));
// Freemarker 自带工具示例
import freemarker.template.utility.StringUtil;

sb.append(StringUtil.escapeHtml(element.getNumber().toString()));

转义后特殊字符会被转换成HTML实体(比如<变成&lt;),既不会破坏HTML结构,也能防止XSS攻击。

方式3:关闭Freemarker对该变量的自动转义

如果确定内容是100%可信的HTML,可以在FTL里用?no_esc指令关闭转义:

${object.renderRow("key")?no_esc}

但这种方式风险极高,仅适合完全可控的静态内容,绝不能用于处理用户输入等不可信数据。

额外提醒

  • 所有来自外部的不可信数据必须经过转义处理
  • 尽量避免在Java中直接拼接HTML,保持视图逻辑在FTL模板中,代码可读性和可维护性更强

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 00:14:55