自定义TemplateExceptionHandler

时间:2014-10-22 08:38:33

标签: freemarker

我需要更改FreeMarker关于处理模板和数据的行为,以防丢失一些数据。 在缺少的情况下,我需要保持模板不变并继续处理。

实施例: 模板:

... 
var1 = ${var1} 
var2 = ${var2} 
...

数据:

var1 = Hello

处理后我需要结果:

...
var1 = Hello
var2 = ${var2}
...

我的解决方案是:

class MyTemplateExceptionHandler implements TemplateExceptionHandler {
    public void handleTemplateException(TemplateException te, Environment env, java.io.Writer out)
            throws TemplateException {
        try {
            //2nd word on 2nd row is name of missing variable :(
            String missingVariable = te.getMessageWithoutStackTop().split("\n")[1].split(" ")[1];
            out.write("${" + missingVariable + "}");
        } catch (IOException e) {
            throw new TemplateException("Failed to print error message. Cause: " + e, env);
        }
    } }

并使用:

...
Configuration cfg = new Configuration();
cfg.setTemplateExceptionHandler(new MyTemplateExceptionHandler());
...

我的解决方案有效,但我不满意,因为:

1)在handleTemplateException()中获取缺失变量非常糟糕。是否存在更好的方法来获取缺失变量的名称?

2)即使我有自己的TemplateExceptionHandler,FreeMarker也会输出足够的信息。我可以改变吗?

缺少变量的示例输出" environment_name":

22.10.2014 9:01:55 freemarker.log._JDK14LoggerFactory$JDK14Logger error
SEVERE: Error executing FreeMarker template
FreeMarker template error:
The following has evaluated to null or missing:
==> environment_name  [in template "Osb-PrepareAndDeploy.ftl" at line 33, column 33]

Tip: If the failing expression is known to be legally null/missing, either specify a default value with myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthessis: (myOptionVar.foo)!myDefault, (myOptionVar.foo)??

The failing instruction (FTL stack trace):
----------
==> ${environment_name}  [in template "Osb-PrepareAndDeploy.ftl" at line 33, column 31]
----------

Java stack trace (for programmers):
----------
freemarker.core.InvalidReferenceException: [... Exception message was already printed; see it above ...]
    at freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:98)
    at freemarker.core.EvalUtil.coerceModelToString(EvalUtil.java:382)
    at freemarker.core.Expression.evalAndCoerceToString(Expression.java:115)
    at freemarker.core.DollarVariable.accept(DollarVariable.java:76)
    at freemarker.core.Environment.visit(Environment.java:265)
    at freemarker.core.MixedContent.accept(MixedContent.java:93)
    at freemarker.core.Environment.visit(Environment.java:265)
    at freemarker.core.Environment.process(Environment.java:243)
    at freemarker.template.Template.process(Template.java:277)
    at net.homecredit.scm.jenkinsTool.countrySettings.Country.createJobs(Country.java:282)
    at net.homecredit.scm.jenkinsTool.Start.main(Start.java:83)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

1 个答案:

答案 0 :(得分:0)

您无法阻止记录异常。 TemplateExceptionHandler并不意味着从错误中获取非错误,它只是让您决定在错误发生后做什么。比如,您想要打印错误页面或其他内容。在极端情况下,您可能希望在打印一些错误指示符后继续页面呈现,但这仍然是需要修复的错误。

如果你说出为什么需要这个,也许会有所帮助。也许解决方案不是TemplateExceptionHandler - s。

从更智能的异常处理开始,首先,在处理程序中,您应该检查异常是否为InvalidReferenceException,因为我猜您不想与其他人打交道。然后,使用getBlamedExpressionString()(需要FreeMarker 2.3.21),您可以获得要打印到输出的部分内容。它只是其中的一部分,因为如果${x + 1}因未定义x而失败,则只返回"x",而不是"x + 1"