本地写了一个很简单的Freemarker 测试,从对象属性中获取值,替换模版,然后打印出来。
本以为非常简单的一个测试,结果愣是没出结果,一直在报错。
各种百度、谷歌,愣是没有我这种情况。
冥冥之中,自有天助。记录下错误和结论。
奉天承运,皇帝昭曰:上代码!
package tdd.com.ilvf.common.util;
import java.io.StringWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.ilvf.common.util.DateUtil;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
public class FreemarkerTest {
public static void main(String[] args) throws Exception {
//注意版本与pom中的引用版本一致
Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
cfg.setDefaultEncoding("utf-8");
StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
cfg.setTemplateLoader(stringTemplateLoader);
String templateContent="欢迎:${name}, 生日:${birth?string('yyyy-MM-dd')},你的身份证号码是${card.name}";
stringTemplateLoader.putTemplate("myTemplate", templateContent);
Template template = cfg.getTemplate("myTemplate");
Map<String, Object> dataMap = new HashMap<String, Object>();
dataMap.put("name", "张三");
dataMap.put("birth", DateUtil.addMonth(new Date(), -1));
dataMap.put("card", new Card("Audi", "123456789"));
StringWriter writer = new StringWriter();
template.process(dataMap, writer);
System.out.println(writer.toString());
}
}
class Card {
private String name;
private String number;
public Card(String name, String number) {
this.name = name;
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
@Override
public String toString() {
return "Card["+name+","+number+"]";
}
}
pom版本为
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.23</version>
</dependency>
执行后,报错如下:
2019-03-22 15:39:27 [ main:0 ] - [ ERROR ] freemarker.log._Log4jLoggerFactory$Log4jLogger.error(_Log4jLoggerFactory.java:60) Error executing FreeMarker template
FreeMarker template error:
The following has evaluated to null or missing:
==> card.name [in template "myTemplate" at line 1, column 56]
----
Tip: It's the step after the last dot that caused this error, not those before it.
----
Tip: If the failing expression is known to be legally refer to something that's sometimes null or missing, either specify a default value like 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 parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----
----
FTL stack trace ("~" means nesting-related):
- Failed at: ${card.name} [in template "myTemplate" at line 1, column 54]
----
Java stack trace (for programmers):
----
freemarker.core.InvalidReferenceException: [... Exception message was already printed; see it above ...]
at freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:131)
at freemarker.core.EvalUtil.coerceModelToString(EvalUtil.java:355)
at freemarker.core.Expression.evalAndCoerceToString(Expression.java:82)
at freemarker.core.DollarVariable.accept(DollarVariable.java:41)
at freemarker.core.Environment.visit(Environment.java:324)
at freemarker.core.MixedContent.accept(MixedContent.java:54)
at freemarker.core.Environment.visit(Environment.java:324)
at freemarker.core.Environment.process(Environment.java:302)
at freemarker.template.Template.process(Template.java:325)
at tdd.com.ilvf.common.util.FreemarkerTest.main(FreemarkerTest.java:35)
Exception in thread "main" FreeMarker template error:
The following has evaluated to null or missing:
==> card.name [in template "myTemplate" at line 1, column 56]
----
Tip: It's the step after the last dot that caused this error, not those before it.
----
Tip: If the failing expression is known to be legally refer to something that's sometimes null or missing, either specify a default value like 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 parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----
----
FTL stack trace ("~" means nesting-related):
- Failed at: ${card.name} [in template "myTemplate" at line 1, column 54]
----
Java stack trace (for programmers):
----
freemarker.core.InvalidReferenceException: [... Exception message was already printed; see it above ...]
at freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:131)
at freemarker.core.EvalUtil.coerceModelToString(EvalUtil.java:355)
at freemarker.core.Expression.evalAndCoerceToString(Expression.java:82)
at freemarker.core.DollarVariable.accept(DollarVariable.java:41)
at freemarker.core.Environment.visit(Environment.java:324)
at freemarker.core.MixedContent.accept(MixedContent.java:54)
at freemarker.core.Environment.visit(Environment.java:324)
at freemarker.core.Environment.process(Environment.java:302)
at freemarker.template.Template.process(Template.java:325)
at tdd.com.ilvf.common.util.FreemarkerTest.main(FreemarkerTest.java:35)
确认检查过类名、属性名、getter、setter方法,也确定属性已经赋值,没有null。
结论:无意中,将 Card类 放到单独的文件中(除此之外,无任何改动),运行正常。