springboot整合freemarker的踩坑及解決
springboot整合freemarker踩坑
報錯
2021-04-23 02:01:18.148 ERROR 9484 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is freemarker.core.InvalidReferenceException: The following has evaluated to null or missing:
==> hots [in template "inc/right.ftl" at line 6, column 11]----
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: @hots [in template "inc/right.ftl" at line 6, column 9]
- Reached through: #include "/inc/right.ftl" [in template "index.ftl" at line 52, column 13]
~ Reached through: #nested [in template "inc/layout.ftl" in macro "layout" at line 25, column 5]
~ Reached through: @layout "首頁" [in template "index.ftl" at line 2, column 1]
----] with root causefreemarker.core.InvalidReferenceException: The following has evaluated to null or missing:
==> hots [in template "inc/right.ftl" at line 6, column 11]----
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: @hots [in template "inc/right.ftl" at line 6, column 9]
- Reached through: #include "/inc/right.ftl" [in template "index.ftl" at line 52, column 13]
~ Reached through: #nested [in template "inc/layout.ftl" in macro "layout" at line 25, column 5]
~ Reached through: @layout "首頁" [in template "index.ftl" at line 2, column 1]
----
at freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:134) ~[freemarker-2.3.28.jar:2.3.28]
at freemarker.core.UnifiedCall.accept(UnifiedCall.java:106) ~[freemarker-2.3.28.jar:2.3.28]
at freemarker.core.Environment.visit(Environment.java:330) ~[freemarker-2.3.28.jar:2.3.28]
at freemarker.core.Environment.visit(Environment.java:336) ~[freemarker-2.3.28.jar:2.3.28]
at freemarker.core.Environment.include(Environment.java:2582) ~[freemarker-2.3.28.jar:2.3.28]
at freemarker.core.Include.accept(Include.java:171) ~[freemarker-2.3.28.jar:2.3.28]
at freemarker.core.Environment.visit(Environment.java:366) ~[freemarker-2.3.28.jar:2.3.28]
at freemarker.core.Environment.invokeNestedContent(Environment.java:618) ~[freemarker-2.3.28.jar:2.3.28]
at freemarker.core.BodyInstruction.accept(BodyInstruction.java:60) ~[freemarker-2.3.28.jar:2.3.28]
at freemarker.core.Environment.visit(Environment.java:366) ~[freemarker-2.3.28.jar:2.3.28]
at freemarker.core.Environment.invoke(Environment.java:775) ~[freemarker-2.3.28.jar:2.3.28]
at freemarker.core.UnifiedCall.accept(UnifiedCall.java:83) ~[freemarker-2.3.28.jar:2.3.28]
at freemarker.core.Environment.visit(Environment.java:330) ~[freemarker-2.3.28.jar:2.3.28]
at freemarker.core.Environment.visit(Environment.java:336) ~[freemarker-2.3.28.jar:2.3.28]
at freemarker.core.Environment.process(Environment.java:309) ~[freemarker-2.3.28.jar:2.3.28]
at freemarker.template.Template.process(Template.java:384) ~[freemarker-2.3.28.jar:2.3.28]
at org.springframework.web.servlet.view.freemarker.FreeMarkerView.processTemplate(FreeMarkerView.java:389) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.web.servlet.view.freemarker.FreeMarkerView.doRender(FreeMarkerView.java:302) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.web.servlet.view.freemarker.FreeMarkerView.renderMergedTemplateModel(FreeMarkerView.java:253) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.web.servlet.view.AbstractTemplateView.renderMergedOutputModel(AbstractTemplateView.java:178) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:316) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1370) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1116) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1055) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) ~[spring-webmvc-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.14.jar:9.0.14]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.14.jar:9.0.14]
at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]2021-04-23 02:01:18.177 ERROR 9484 --- [nio-8080-exec-1] s.e.ErrorMvcAutoConfiguration$StaticView : Cannot render error page for request [/] and exception [The following has evaluated to null or missing:
==> hots [in template "inc/right.ftl" at line 6, column 11]----
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: @hots [in template "inc/right.ftl" at line 6, column 9]
- Reached through: #include "/inc/right.ftl" [in template "index.ftl" at line 52, column 13]
~ Reached through: #nested [in template "inc/layout.ftl" in macro "layout" at line 25, column 5]
~ Reached through: @layout "首頁" [in template "index.ftl" at line 2, column 1]
----] as the response has already been committed. As a result, the response may have the wrong status code.
問題原因
因為在service里試著把redis邏輯代碼運行,然后再控制臺上輸出,結(jié)果發(fā)現(xiàn)結(jié)果是沒有問題的,而且通過報錯信息初步認(rèn)為是前端的問題,hots沒找到,但是跟之前的一個類似功能相比較,然后通過不斷的對比,找到問題是出在配置類。
之前一直認(rèn)為template類中的getname方法就能完成映射功能
其實需要在FreemarkerConfig類里面進行聲明
解決方法
再FreemarkerConfig類先通過@Autowired導(dǎo)入template類,然后使用configuration.setSharedVariable(“hots”, hotsTemplate);進行聲明,缺少這一步會使得前端對于<@hots>這個標(biāo)簽無法識別。
springboot freemarker基礎(chǔ)配置及使用
1.基礎(chǔ)配置
1.1引入依賴
<!-- 引入freemarker模板引擎的依賴 --> <dependency> ? ? <groupId>org.springframework.boot</groupId> ? ? <artifactId>spring-boot-starter-freemarker</artifactId> </dependency>
1.2在application.properties配置文件中添加如下配置:
# 是否開啟thymeleaf緩存,本地為false,生產(chǎn)建議為true spring.freemarker.cache=false spring.freemarker.charset=UTF-8 spring.freemarker.allow-request-override=false spring.freemarker.check-template-location=true #類型 spring.freemarker.content-type=text/html spring.freemarker.expose-request-attributes=true spring.freemarker.expose-session-attributes=true # #文件后綴 spring.freemarker.suffix=.ftl #路徑 .ftl文件就創(chuàng)建在templates下面或者子目錄 spring.freemarker.template-loader-path=classpath:/templates/
2.基礎(chǔ)使用
首先我在controller類中編寫一個測試接口用來測試使用,編寫內(nèi)容如下
@Controller public class FreeMarkerController { ? ? Map<String ,Object> map = new HashMap<>(); ? ? List<Object> list = new ArrayList(); ? ? @GetMapping("/freemaker/{id}/{name}") ? ? public String demo(@PathVariable("id")String id ,@PathVariable("name") String name,Model model){ ? ? ? ? map.clear(); ? ? ? ? map.put("id",id); ? ? ? ? map.put("name",name); ? ? ? ? list.add(2); ? ? ? ? list.add(4); ? ? ? ? map.put("aa",null); ? ? ? ? model.addAttribute("map",map); ? ? ? ? model.addAttribute("list",list); ? ? ? ? model.addAttribute("date",new Date()); ? ? ? ? return "index"; ? ? } }
以下所有變量都是有上面接口提供
2.1調(diào)用map類型數(shù)據(jù),實體類也可使用此格式調(diào)用屬性
/*可直接獲取id對應(yīng)的v值*/ id:${map.id} name:${map.name}
2.2集合調(diào)用,set集合也可用此格式調(diào)用相應(yīng)的元素
list01:${list[0]} list02:${list[1]}
2.3字符串拼接的兩種方法
${"你好啊${map.name}"} ${"你好啊"+map.name}
2.4FreeMarker表達式中支持“+”、“-”、“*”、“/”、“%”運算符
${list[1]+list[0]} ${list[1]-list[0]} ${list[1]*list[0]} ${list[1]/list[0]} ${list[1]%list[0]}
2.5表達式中支持的比較運算符有如下幾種:
1. =(或者==):判斷兩個值是否相等;
2. !=:判斷兩個值是否不相等;
注: =和!=可以用作字符串、數(shù)值和日期的比較,但兩邊的數(shù)據(jù)類型必須相同。而且FreeMarker的比較是精確比較,不會忽略大小寫及空格。
3. >(或者gt):大于
4. >=(或者gte):大于等于
5. <(或者lt):小于
6. <=(或者lte):小于等于
注: 上面這些比較運算符可以用于數(shù)字和日期,但不能用于字符串。大部分時候,使用gt比>有更好的效果,因為FreeMarker會把>解釋成標(biāo)簽的結(jié)束字符??梢允褂美ㄌ杹肀苊膺@種
2.6時間格式轉(zhuǎn)換
${date?string("yyyy-MM-dd")}
2.7支持邏輯表達式
FreeMarker支持邏輯運算但是只支持布爾型邏輯運算兩個值進行比較運算的的時候需要添加括號才能進行邏輯運算,一般用于指令中
FreeMarker支持邏輯運算但是只支持布爾型邏輯運算兩個值進行比較運算的的時候需要添加括號才能進行邏輯運算,一般用于指令中
1. &&: 邏輯與;
2. ||:邏輯或;
3. !:邏輯非
邏輯運算符只能用于布爾值。
2.8FreeMarker無法理解null值
FreeMarker的變量必須賦值,否則就會拋出異常。而對于FreeMarker來說,null值和不存在的變量是完全一樣的,因為FreeMarker無法理解null值。
FreeMarker提供兩個運算符來避免空值:
1.!運算
1.1若是msg不存在不報異常默認(rèn)空值,若是不使用!會報異常<br>
${msg!}
1.2若是存在則輸出,若是不存在則默認(rèn)為abc<br>
${map.a!"abc"}<br>
2.??返回布爾值一般用在指令中下面會有引用此處不解釋<br>
2.9 if指令
<#if map.aa?? > ? ? 存在 ? ? <#else > ? ? 不存在 </#if> <br> <#if (list[0]>=3) > ? ? 優(yōu)秀 ? ? <#elseif (list[0]>=2)> ? ? 良好 ? ? <#else > ? ? 差勁 </#if>
2.10 list指令 遍歷
<#list list as li> ? ? ${li}<br> </#list>
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java線程池運行狀態(tài)監(jiān)控實現(xiàn)解析
這篇文章主要介紹了Java線程池運行狀態(tài)監(jiān)控實現(xiàn)解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-10-10詳解mybatis plus使用insert沒有返回主鍵的處理
這篇文章主要介紹了詳解mybatis plus使用insert沒有返回主鍵的處理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09Java實現(xiàn)訂單超時未支付自動取消的8種方法總結(jié)
這篇文章主要為大家介紹了Java實現(xiàn)訂單超時未支付自動取消功能的8種不同方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-08-08java、spring、springboot中整合Redis的詳細(xì)講解
這篇文章主要介紹了java、spring、springboot中整合Redis的詳細(xì)講解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04