Freemarker中,使用非字符串作为Map的Key,读取不到Value的问题
使用freemarker
作为模版引擎。尝试对一个非字符串作为Key
的Map
进行循环渲染的时候,会出现读取不到value
问题
案例演示
通过一个Map,按照性别对用户进行分组。性别的定义使用一个枚举,而不是字符串。然后渲染在页面上。
public static enum Gender {
BOY,
GIRL
}
Map<Gender, List<String>> models = new HashMap<>();
Controller
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
@RequestMapping("/test")
@RestController
public class TestController {
public static enum Gender {
BOY,
GIRL
}
@GetMapping
public ModelAndView test (HttpServletRequest request, HttpServletResponse response) throws IOException {
ModelAndView modelAndView = new ModelAndView("test/test");
Map<Gender, List<String>> models = new HashMap<>();
models.put(Gender.BOY, Arrays.asList("小明", "中明", "大明"));
models.put(Gender.GIRL, Arrays.asList("小红", "中红", "大红"));
modelAndView.addObject("users", models);
return modelAndView;
}
}
View
先遍历Map中的key,再根据key获取到value,对value进行遍历
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>freemarker</title>
</head>
<body>
<#list users?keys as gender>
<h3>${gender}</h3>
<ul>
<#list users[gender] as user>
<li>${user}</li>
</#list>
</ul>
</#list>
</body>
</html>
异常
Caused by: freemarker.core.InvalidReferenceException: The following has evaluated to null or missing:
==> users[gender] [in template "test/test.ftl" at line 11, column 40]
----
Tip: It's the final [] step that caused this error, not those before it.
----
Tip: If the failing expression is known to 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: #list users[gender] as user [in template "test/test.ftl" at line 11, column 33]
----
异常信息表示,根据key
读取到的value
是空。也就是这个表达式:users[gender]
解决办法1 - 使用字符串做为Map的key
Controller
修改Map
的Key
为,枚举的 name()
属性,它是字符串。
Map<String, List<String>> models = new HashMap<>();
models.put(Gender.BOY.name(), Arrays.asList("小明", "中明", "大明"));
models.put(Gender.GIRL.name(), Arrays.asList("小红", "中红", "大红"));
modelAndView.addObject("users", models);
渲染结果 - 正常
解决办法2 - 修改Freemarker的设置
对 Configuration 进行设置
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.TemplateModelException;
@Configuration
public class FreemarkerConfiguration {
@Autowired
private freemarker.template.Configuration configuration;
@PostConstruct
public void configuration() throws TemplateModelException {
this.configuration.setAPIBuiltinEnabled(true);
DefaultObjectWrapper defaultObjectWrapper = (DefaultObjectWrapper) configuration.getObjectWrapper();
defaultObjectWrapper.setUseAdaptersForContainers(true);
}
}
表达式需要修改
通过: map?api.get(key)
来获取到value
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>freemarker</title>
</head>
<body>
<#list users?keys as gender>
<h3>${gender}</h3>
<ul>
<#list users?api.get(gender) as user>
<li>${user}</li>
</#list>
</ul>
</#list>
</body>
</html>
渲染结果 - 正常
总结
处理这种问题,要么修改Map
的key
为字符串。要么修改Freemarker
的配置,以及取值表达式。
Freemarker配置
configuration.setAPIBuiltinEnabled(true);
DefaultObjectWrapper defaultObjectWrapper = (DefaultObjectWrapper) configuration.getObjectWrapper();
defaultObjectWrapper.setUseAdaptersForContainers(true);
取值表达式
<#list map?keys as key>
${key?c} - ${map?api.get(key)}<br/>
</#list>