Spring MVC中Freemarker调用spring.ftl时springMacroRequestContext为空报错
Spring MVC中Freemarker使用spring.ftl宏时springMacroRequestContext为空问题
在Spring MVC环境下,通过Freemarker HTML模板使用spring.ftl提供的通用工具宏读取资源文件标签时,出现springMacroRequestContext为空的错误。已在FreeMarkerViewResolver中设置setExposeSpringMacroHelpers(true),但问题仍未解决。
配置代码
package com.omb; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver; import java.util.Properties; @Configuration @EnableWebMvc public class FreeMarkerConfiguration implements WebMvcConfigurer { @Bean public FreeMarkerViewResolver viewResolver() { FreeMarkerViewResolver viewResolver = new FreeMarkerViewResolver(); viewResolver.setExposeSpringMacroHelpers(true); viewResolver.setExposeRequestAttributes(true); viewResolver.setPrefix(""); viewResolver.setSuffix(".ftl"); viewResolver.setContentType("text/html;charset=UTF-8"); return viewResolver; } @Bean public FreeMarkerConfigurer freemarkerConfig() { FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); configurer.setDefaultEncoding("UTF-8"); configurer.setTemplateLoaderPath("/WEB-INF/views/ftl/"); Properties settings = new Properties(); settings.setProperty("auto_import", "/spring.ftl as spring"); settings.setProperty("incompatible_improvements", "2.3.32"); settings.setProperty("template_exception_handler", "rethrow"); configurer.setFreemarkerSettings(settings); return configurer; } }
服务注入配置
@Autowired private FreeMarkerConfiguration freeMarkerConfiguration;
模板调用方法
public static byte[] generateDoc(String templateName, String templateDocument, Map<String, Object> objects, Map<String, Object> params, FreeMarkerConfiguration configuration) throws IOException, TemplateException { ConverterProperties converterProperties = getConverterProperties(); Template template = new Template(templateName, new StringReader(templateDocument), configuration.freemarkerConfig().createConfiguration()); try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { Writer writer = new OutputStreamWriter(out); Environment env = template.createProcessingEnvironment(objects, writer); populateEnvironnment(env); env.process(); ByteArrayOutputStream fos = new ByteArrayOutputStream(); PdfDocument output = new PdfDocument(new PdfWriter(fos)); output.setDefaultPageSize((PageSize) ownParams.get(PAGE_SIZE)); try (ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray())) { HtmlConverter.convertToPdf(in, output, converterProperties); } return fos.toByteArray(); } }
HTML模板代码
<#import "/spring.ftl" as spring/> <!DOCTYPE html> <html> <body> <@spring.messageText "resource.bundle.key"/> </body> </html>
错误信息
The following has evaluated to null or missing: ==> springMacroRequestContext [in template "spring.ftl" at line 28, column 24] ---- 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: ${springMacroRequestContext.getMessag... [in template "spring.ftl" in macro "message" at line 28, column 22] - Reached through: @spring.message "sale.enum.TravelPass... [in template "MY_TEMPLATE" at line 7, column 9] ---- FreeMarker template error: The following has evaluated to null or missing: ==> springMacroRequestContext [in template "spring.ftl" at line 28, column 24] ---- 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: ${springMacroRequestContext.getMessag... [in template "spring.ftl" in macro "message" at line 28, column 22] - Reached through: @spring.message "resource.bundle.key... [in template "MY_TEMPLATE" at line 53, column 9] ---- Java stack trace (for programmers): ---- freemarker.core.InvalidReferenceException: [... Exception message was already printed; see it above ...] at freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:134) at freemarker.core.UnexpectedTypeException.newDescriptionBuilder(UnexpectedTypeException.java:85) at freemarker.core.UnexpectedTypeException.<init>(UnexpectedTypeException.java:48) at freemarker.core.NonHashException.<init>(NonHashException.java:49) at freemarker.core.Dot._eval(Dot.java:48)
临时解决方案
目前找到一个临时解决办法,但不够优雅:手动向数据模型Map中添加RequestContext。
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); map.put("springMacroRequestContext", new RequestContext(request, null, null, null));
内容的提问来源于stack exchange,提问作者Ousmane MBINTE
相关产品推荐
相关产品推荐

