Error handling

Page Contents

可能的 exception

关于 FreeMarker 可能发生的异常可以如下分类:

自定义有关 TemplatException -s 的行为

模板处理期间引发的TemplateException -s 由freemarker.template.TemplateExceptionHandler对象处理,该对象通过setTemplateExceptionHandler(...)方法插入到Configuration对象中。这些是 FreeMarker 随附的TemplateExceptionHandler实现:

您也可以通过实现包含此方法的接口来编写自定义TemplateExceptionHandler

void handleTemplateException(TemplateException te, Environment env, Writer out)
        throws TemplateException;

每当出现TemplateException时,都会调用此方法。处理的异常在te参数中,模板处理的运行时环境在env参数中,并且处理程序可以使用out参数打印到输出。如果此方法引发异常(通常会重新引发te),则模板处理将被中止,而Template.process(...)将引发相同的异常。如果handleTemplateException没有引发异常,则模板处理将 continue 进行,就好像什么都没有发生一样,但是导致异常的语句将被跳过(请参阅稍后)。当然,处理程序仍可以将错误指示符打印到输出。

让我们通过示例看看在错误处理程序未引发异常时 FreeMarker 如何跳过语句。假设我们正在使用此模板异常处理程序:

class MyTemplateExceptionHandler implements TemplateExceptionHandler {
    public void handleTemplateException(TemplateException te, Environment env, java.io.Writer out)
            throws TemplateException {
        try {
            out.write("[ERROR: " + te.getMessage() + "]");
        } catch (IOException e) {
            throw new TemplateException("Failed to print error message. Cause: " + e, env);
        }
    }
}

...

cfg.setTemplateExceptionHandler(new MyTemplateExceptionHandler());

如果不在 FTL 标签内部(即未包含在<#...><@...>内)的插值中发生错误,则将跳过整个插值。因此,此模板(假设数据模型中缺少badVar):

a${badVar}b

如果我们使用MyTemplateExceptionHandler将打印此内容:

a[ERROR: Expression badVar is undefined on line 1, column 4 in test.ftl.]b

该模板将打印相同的内容(除了列号不同...):

a${"moo" + badVar}b

因为如果内部插值发生错误,整个插值将被跳过。

如果在评估指令调用的参数值时发生错误,或者参数列表存在其他问题,或者在<@exp ...>中评估exp时发生错误,或者exp的值不是用户定义的指令,然后跳过整个指令调用。例如:

a<#if badVar>Foo</#if>b

将打印此:

a[ERROR: Expression badVar is undefined on line 1, column 7 in test.ftlh.]b

请注意,该错误发生在if开始标记(<#if badVar>)中,但是整个指令调用都被跳过。从逻辑上讲,嵌套内容(Foo)被跳过了,因为嵌套内容是由封闭指令(if)处理(打印)的。

输出与此相同(除了列号不同...):

a<#if "foo${badVar}" == "foobar">Foo</#if>b

因为如果在参数评估期间发生任何错误,将跳过整个指令调用。

如果已经开始执行指令后发生错误,则不会跳过指令调用。也就是说,如果嵌套内容中发生错误:

a
<#if true>
  Foo
  ${badVar}
  Bar
</#if>
c

或在宏定义主体中:

a
<@test />
b
<#macro test>
  Foo
  ${badVar}
  Bar
</#macro>

输出将是这样的:

a
  Foo
  [ERROR: Expression badVar is undefined on line 4, column 5 in test.ftlh.]
  Bar
c

TemplateException logging

默认情况下,freemarker.runtime日志类别下的 FreeMarker logs全部TemplateException -s,即使它会从其公共 API 抛出它。由于日志记录已成为 Java 应用程序中的普遍做法,因此现在通常会导致两次 exception 记录,因此建议您在配置 FreeMarker 的cfg.setLogTemplateExceptions(false)(或log_template_exceptions=false)禁用此旧行为。

模板中的显式错误处理

尽管它与 FreeMarker 配置无关(本章的主题),但是出于完整性考虑,这里提到您也可以直接在模板内部处理错误:

上一章 首页 下一章