【发布时间】:2018-04-22 11:17:17
【问题描述】:
我一直在尝试使用 freemarker.template.Template 类来处理给定的 .ftl 模板。基本上它没有找到弹簧标签库,并且在遇到第一个 标签时失败。但是,它可以很好地读取 spring 宏指令。
在 spring 中附加我的 freemarker 配置和错误消息:
我正在使用带有 freemarker 2.3.23 的 spring 4。在 tomcat 7 上运行我的 Spring MVC 应用程序时,它抱怨以下内容:
---- FTL 堆栈跟踪(“~”表示嵌套相关): - 失败:@spring.url "/imports/app/vendor/boot... [在模板 "config/pages/default-page.ftl" 第 5 行第 54 列] ----] 根本原因 FreeMarker 模板错误:以下已评估为 null 或缺失: ==> spring [in template "config/pages/default-page.ftl" at line 5, column 56]
Java 堆栈跟踪(针对程序员): ---- freemarker.core.InvalidReferenceException: [... 异常信息已被打印;见上面...]在 freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:131) 在 freemarker.core.UnexpectedTypeException.newDescriptionBuilder(UnexpectedTypeException.java:77) 在 freemarker.core.UnexpectedTypeException.(UnexpectedTypeException.java:40) 在 freemarker.core.NonHashException.(NonHashException.java:46) 在 freemarker.core.Dot._eval(Dot.java:45) 在 freemarker.core.Expression.eval(Expression.java:78) 在 freemarker.core.UnifiedCall.accept(UnifiedCall.java:74) 在 freemarker.core.Environment.visit(Environment.java:324) 在 freemarker.core.MixedContent.accept(MixedContent.java:54) 在 freemarker.core.Environment.visit(Environment.java:324) 在 freemarker.core.Environment.process(Environment.java:302) 在 freemarker.template.Template.process(Template.java:325) 在 com.isys.ghp.server.services.web.impls.HtmlRenditionComposer.composeRendition(HtmlRenditionComposer.java:43) 在 com.isys.ghp.controllers.app.RootControllerApp.welcome(RootControllerApp.java:48) 在 com.isys.ghp.controllers.app.RootControllerApp$$FastClassBySpringCGLIB$$cebaa583.invoke() 在 org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) 在 org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717) 在 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) 在 org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85) 在 com.isys.ghp.server.aspects.MethodLogger.around(MethodLogger.java:21) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:606) 在 org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621) 在 org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610) 在 org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:68) 在 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168) 在 org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) 在 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 在 org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653) 在 com.isys.ghp.controllers.app.RootControllerApp$$EnhancerBySpringCGLIB$$55180b14.welcome() 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:606) 在 org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221) 在 org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) 在 org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110) 在 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:776) 在 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705) 在 org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) 在 org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959) 在 org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893) 在 org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967) 在 org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:858) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:620) 在 org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:727) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 在 org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 在 org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:316) 在 org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126) 在 org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:122) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:48) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:205) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:96) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) 在 org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213) 在 org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176) 在 org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344) 在 org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 在 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) 在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) 在 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170) 在 org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) 在 org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950) 在 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) 在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) 在 org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040) 在 org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607) 在 org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:315) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 在 java.lang.Thread.run(Thread.java:745)
MVCConfiguration 的代码扩展了 WebMvcConfigurerAdapter
@Bean
public FreeMarkerViewResolver freemarkerViewResolver() {
LOGGER.debug("Executing freemarkerViewResolver()");
FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
resolver.setExposeSpringMacroHelpers(true);
resolver.setExposeRequestAttributes(true);
resolver.setCache(true);
resolver.setPrefix("");
resolver.setSuffix(".ftl");
return resolver;
}
@Bean(name="fmAdvanceConfigFactoryBean")
public FreeMarkerConfigurer getFreemarkerConfig() throws IOException, TemplateException {
FreeMarkerConfigurationFactoryBean freeMarkerConfigurationFactoryBean = new FreeMarkerConfigurationFactoryBean();
FreeMarkerConfigurer result = new FreeMarkerConfigurer();
result.setTemplateLoaderPath("/WEB-INF/views");
result.setConfiguration(freeMarkerConfigurationFactoryBean.createConfiguration());
return result;
}
模板处理块:
Template pageHTML = fmAdvanceConfigFactoryBean.getTemplate("config/pages/default-page.ftl");
StringWriter pageWriter = new StringWriter();
Map<String, Object> map = new HashMap<>();
pageHTML.process(map, pageWriter);
我一直在寻找很多提供高级配置的页面,但没有一个能够解决这个问题。我不确定我在这里缺少什么。任何帮助都将是有用的和感激的!
谢谢!
更新:你是对的,ddekany!就像你建议的那样,不同的配置文件中有另一种方法。我已经评论了该方法并检查了没有其他调用点。但是,现在它抱怨找不到模板。请看下面我的回答。你是对的。在不同的配置文件中还有另一种方法。我已经评论了该方法并检查了没有其他调用点。但是,现在它抱怨找不到模板:
freemarker.template.TemplateNotFoundException:找不到模板 名称“/config/pages/default-page.ftl”。该名称被解释为 这个模板加载器: LegacyDefaultFileTemplateLoader(baseDir="/Users/mdani/Data_MD/Developer_MD/Workspace/Tools/GH-Platform/STS.app/Contents/MacOS", canonicalBasePath="/Users/mdani/Data_MD/Developer_MD/Workspace/Tools/GH-Platform/STS.app/Contents/MacOS/")。 警告:未设置“template_loader”FreeMarker 设置 (Configuration.setTemplateLoader),并且使用默认值最多 当然不是故意和危险的,并且可能是造成这种情况的原因 错误。在 freemarker.template.Configuration.getTemplate(Configuration.java:2701) 在 freemarker.template.Configuration.getTemplate(Configuration.java:2503)
简化类:
@Loggable
@Bean(name="fmAdvanceConfigFactoryBean")
public FreeMarkerConfigurer getFreemarkerConfig() throws IOException, TemplateException {
Properties settings = new Properties();
settings.setProperty("auto_import", "/spring.ftl as spring");
FreeMarkerConfigurer result = new FreeMarkerConfigurer();
result.setTemplateLoaderPaths("/WEB-INF/views","classpath:/");
result.setFreemarkerSettings(settings);
return result;
}
新错误:
严重:Servlet.service() 用于 servlet [dispatcher] 在上下文中 路径 [/GHPWebApp] 抛出异常 [请求处理失败;嵌套的 异常是freemarker.core.InvalidReferenceException:以下 已评估为 null 或缺失: ==> springMacroRequestContext [在模板“spring.ftl”中,第 89 行,第 134 列]
---- 提示:如果已知失败的表达式合法地引用了有时为空或缺失的内容,请指定默认值 像 myOptionalVar!myDefault 这样的值,或使用 when-presentwhen-missing。 (这些只有 覆盖表达式的最后一步;覆盖整个表达式,
使用括号:(myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
---- FTL 堆栈跟踪(“~”表示嵌套相关): - 失败:${springMacroRequestContext.getContex... [在第 89 行第 132 列的宏“url”中的模板“spring.ftl”中] - 通过:@spring.url "/imports/app/vendor/boot... [in template "config/pages/default-page.ftl" at 第 4 行,第 54 列] ----] 根本原因 FreeMarker 模板错误:以下已评估为 null 或缺失: ==> springMacroRequestContext [在模板“spring.ftl”中,第 89 行,第 134 列]
---- 提示:如果已知失败的表达式合法地引用了有时为空或缺失的内容,请指定默认值 像 myOptionalVar!myDefault 这样的值,或使用 when-presentwhen-missing。 (这些只有 覆盖表达式的最后一步;覆盖整个表达式,
使用括号:(myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
---- FTL 堆栈跟踪(“~”表示嵌套相关): - 失败于:${springMacroRequestContext.getContex...[在第 89 行第 132 列的宏“url”中的模板“spring.ftl”中]
- 通过:@spring.url "/imports/app/vendor/boot... [in template "config/pages/default-page.ftl" at 第 4 行,第 54 列]
Java 堆栈跟踪(针对程序员): ---- freemarker.core.InvalidReferenceException: [... 异常信息已被打印;见上面...]在 freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:134) 在 freemarker.core.UnexpectedTypeException.newDescriptionBuilder(UnexpectedTypeException.java:85) 在 freemarker.core.UnexpectedTypeException.(UnexpectedTypeException.java:48) 在 freemarker.core.NonHashException.(NonHashException.java:49)
【问题讨论】:
标签: spring-mvc freemarker spring-java-config