<property name="freemarkerSettings">
<props>
<prop key="classic_compatible">true</prop>
</props>
</property>
freemarker.core.Configurable
/**
* Returns whether the engine runs in the "Classic Compatibile" mode.
* When this mode is active, the engine behavior is altered in following
* way: (these resemble the behavior of the 1.7.x line of FreeMarker engine,
* now named "FreeMarker Classic", hence the name).
* <ul>
* <li>handle undefined expressions gracefully. Namely when an expression
* "expr" evaluates to null:
* <ul>
* <li>as argument of the <tt><assign varname=expr></tt> directive,
* <tt>${expr}</tt> directive, <tt>otherexpr == expr</tt> or
* <tt>otherexpr != expr</tt> conditional expressions, or
* <tt>hash[expr]</tt> expression, then it is treated as empty string.
* </li>
* <li>as argument of <tt><list expr as item></tt> or
* <tt><foreach item in expr></tt>, the loop body is not executed
* (as if it were a 0-length list)
* </li>
* <li>as argument of <tt><if></tt> directive, or otherwise where a
* boolean expression is expected, it is treated as false
* </li>
* </ul>
* </li>
* <li>Non-boolean models are accepted in <tt><if></tt> directive,
* or as operands of logical operators. "Empty" models (zero-length string,
* empty sequence or hash) are evaluated as false, all others are evaluated as
* true.</li>
* <li>When boolean value is treated as a string (i.e. output in
* <tt>${...}</tt> directive, or concatenated with other string), true
* values are converted to string "true", false values are converted to
* empty string.
* </li>
* <li>Scalar models supplied to <tt><list></tt> and
* <tt><foreach></tt> are treated as a one-element list consisting
* of the passed model.
* </li>
* <li>Paths parameter of <tt><include></tt> will be interpreted as
* absolute path.
* </li>
* </ul>
* In all other aspects, the engine is a 2.1 engine even in compatibility
* mode - you don't lose any of the new functionality by enabling it.
*/
public boolean isClassicCompatible() {
return classicCompatible != null ? classicCompatible.booleanValue() : parent.isClassicCompatible();
}
* <li>Paths parameter of <tt><include></tt> will be interpreted as
* absolute path.
* </li>
freemarker.cache.TemplateCache
public static String getFullTemplatePath(Environment env, String parentTemplateDir, String templateNameString)
{
if (!env.isClassicCompatible()) {
if (templateNameString.indexOf("://") >0) {
;
}
else if (templateNameString.length() > 0 && templateNameString.charAt(0) == '/') {
int protIndex = parentTemplateDir.indexOf("://");
if (protIndex >0) {
templateNameString = parentTemplateDir.substring(0, protIndex + 2) + templateNameString;
} else {
templateNameString = templateNameString.substring(1);
}
}
else {
templateNameString = parentTemplateDir + templateNameString;
}
}
return templateNameString;
}
模板解析器得知 classic_compatible = true 则 <#include > 标签使用绝对路径模式寻找引用文件,若path是缺少文件夹名称的相对路径则报模板文件找不到。
Caused by: java.io.FileNotFoundException: Template demo.ftl not found.
at freemarker.template.Configuration.getTemplate(Configuration.java:580) ~[freemarker-2.3.19.jar:2.3.19]
at freemarker.core.Environment.getTemplateForInclusion(Environment.java:1490) ~[freemarker-2.3.19.jar:2.3.19]
at freemarker.core.Include.accept(Include.java:157) ~[freemarker-2.3.19.jar:2.3.19]
... 70 common frames omitted
Caused by: freemarker.template.TemplateException: Error reading included file demo.ftl
at freemarker.core.Include.accept(Include.java:167) ~[freemarker-2.3.19.jar:2.3.19]
at freemarker.core.Environment.visit(Environment.java:221) ~[freemarker-2.3.19.jar:2.3.19]
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is freemarker.template.TemplateException: Error reading included file demo.ftl
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:943) ~[spring-webmvc-4.0.0.RELEASE.jar:4.0.0.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:822) ~[spring-webmvc-4.0.0.RELEASE.jar:4.0.0.RELEASE]