Freemarker添加模板后的空指針報錯(The following has evaluated to null or missing)


Freemaker給我的工作提供了極大的便利,但經常后台代碼運行正常,在加入了其他模板后(比如說分頁模板),頻繁報空指針(或者參數獲取不到)問題,報錯日志如下圖:

 1 八月 10, 2017 1:10:07 下午 org.apache.catalina.core.StandardWrapperValve invoke
 2 嚴重: Servlet.service() for servlet [springMVC] in context with path [/jewelry_star] threw exception [Request processing failed; nested exception is freemarker.core._MiscTemplateException: When calling macro "pager", required parameter "code" (parameter #7) was not specified.
 3 
 4 ----
 5 Tip: If the omission was deliberate, you may consider making the parameter optional in the macro by specifying a default value for it, like <#macro macroName paramName=defaultExpr>)
 6 ----
 7 
 8 ----
 9 FTL stack trace ("~" means nesting-related):
10     - Failed at: @page.pager pageIndex=pageModel.pageI...  [in template "goods/goodsList.html" at line 120, column 9]
11 ----] with root cause
12 FreeMarker template error:
13 When calling macro "pager", required parameter "code" (parameter #7) was not specified.
14 
15 ----
16 Tip: If the omission was deliberate, you may consider making the parameter optional in the macro by specifying a default value for it, like <#macro macroName paramName=defaultExpr>)
17 ----
18 
19 ----
20 FTL stack trace ("~" means nesting-related):
21     - Failed at: @page.pager pageIndex=pageModel.pageI...  [in template "goods/goodsList.html" at line 120, column 9]
22 ----
23 
24 Java stack trace (for programmers):
25 ----
26 freemarker.core._MiscTemplateException: [... Exception message was already printed; see it above ...]
27     at freemarker.core.Macro$Context.sanityCheck(Macro.java:232)
28     at freemarker.core.Macro$Context.runMacro(Macro.java:181)
29     at freemarker.core.Environment.invoke(Environment.java:701)
30     at freemarker.core.UnifiedCall.accept(UnifiedCall.java:84)
31     at freemarker.core.Environment.visit(Environment.java:324)
32     at freemarker.core.MixedContent.accept(MixedContent.java:54)
33     at freemarker.core.Environment.visitByHiddingParent(Environment.java:345)
34     at freemarker.core.ConditionalBlock.accept(ConditionalBlock.java:48)
35     at freemarker.core.Environment.visit(Environment.java:324)
36     at freemarker.core.MixedContent.accept(MixedContent.java:54)
37     at freemarker.core.Environment.visit(Environment.java:324)
38     at freemarker.core.Environment.process(Environment.java:302)
39     at freemarker.template.Template.process(Template.java:325)
40     at org.springframework.web.servlet.view.freemarker.FreeMarkerView.processTemplate(FreeMarkerView.java:367)
41     at org.springframework.web.servlet.view.freemarker.FreeMarkerView.doRender(FreeMarkerView.java:284)
42     at org.springframework.web.servlet.view.freemarker.FreeMarkerView.renderMergedTemplateModel(FreeMarkerView.java:234)
43     at org.springframework.web.servlet.view.AbstractTemplateView.renderMergedOutputModel(AbstractTemplateView.java:167)
44     at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
45     at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1257)
46     at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1037)
47     at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980)
48     at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
49     at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
50     at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
51     at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
52     at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
53     at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
54     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
55     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
56     at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
57     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
58     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
59     at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
60     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
61     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
62     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
63     at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
64     at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
65     at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
66     at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
67     at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
68     at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624)
69     at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
70     at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
71     at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
72     at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
73     at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)
74     at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
75     at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
76     at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
77     at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
78     at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
79     at java.lang.Thread.run(Unknown Source)

 

一般這個時候我就會去檢查模板的宏導入處是否正確添加參數。但有時還需檢查模板本身是否也有添加參數引用

一般經過這兩個步驟,問題就能順利解決。

 

后來查閱網上資料,還有以下若干個解決方法:

(資料來源:博客園-Weagle   http://www.cnblogs.com/Weagle/p/5417947.html

一、書寫正確規范代碼

如代碼應該是

1 <#if user??>

而不是

1 <#if user>

 

二、修改Freemarker的配置

因為如果要消除錯誤,需要把前端代碼修后成后面這種形式,這對一個后端開發的人來說很不合理,而且,模板中不止一處出現了這種寫法。

所以可以把Freemarker的配置修改如下:

 1 <bean id="freemarkerConfig"
 2         class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
 3         <property name="templateLoaderPath" value="/template/" />
 4         <property name="freemarkerSettings">
 5             <!-- 設置默認的編碼方式,原先是GBK,需要設置成utf-8 -->
 6             <props>
 7                     <!--用於解決前端報空指針問題-->
 8                 <prop key="classic_compatible">true</prop>
 9                 <prop key="defaultEncoding">utf-8</prop>
10                 <prop key="template_exception_handler">rethrow</prop>
11             </props>
12         </property>
13     </bean>

原理:

以下為轉載內容,點擊查看原文

        在freemarker中的空值的處理,默認情況以${xxx}的方式取值會報錯,我們一般都采用${xxx?if_exists} 的方式去處理,煩死人了。經過查資料,很多人都建議使用classic_compatible=true的方式來處理,目測單詞的意思應該是:“兼容傳統模式”的意思。但是經過使用發現這個屬性設置為true時,也有很多其他問題,比如boolean值的處理,比如include指令必須使用絕對路徑,總之也會帶來很多煩人的事情。最后找到源碼,在Freemarker源碼的Configurable類的isClassicCompatible方法上找到了詳細的注釋,這里翻譯下,不過本人英語比較差,可能會有錯誤,如果有人不確定可以去看源碼。

       原注釋大意如下:

       該方法返回Freemarker模板解析引擎是否工作在“Classic Compatibile”模式下。如果這個模式被激活,則Freemarker模板解析引擎將以以下的方式工作:(類似於1.7.x這個版本的運行方式,這個也是1.7.x的版本被稱為“經典的Freemarker”的由來)。(譯者注:以下的1、2、3、4、5、6是譯者自己加的,方便讀者看)

       處理未定義的表達式,也就是說"expr"為null值。

       1、作為像表達式“<assign varname=expr>”、“${expr}”、“ otherexpr == expr“、“otherexpr != expr”條件表達式或者是“hash[expr]”表達式的參數,這個參數將被當成空字符來對待。(譯者注:這里注意空字符和null是不一樣的).

       2、作為“<list expr as item>”、“<foreach item in expr>”這樣的表達式的參數,其循環體將不會被執行,和list的長度為0是一樣的。

       3、作為“<if>”或者其他布爾表達式命令的參數,空值將被當成是false來處理。非布爾數據模型或者邏輯操作數也可以放在“<if>”表達式中,空模型(長度為零的字符串,空的數組或者hash集合)都被當成是false來對待,其他情況下都被當成是true來處理。

       4、當布爾值被當成字符串(比如用${...}輸出,或者是和其他字符串連接),true值將被轉換成“true”字符串處理,false值將被轉換成空字符串。

       5、提供給<list>和<foreach>的標量數據模型參數將被當成只包含一個該模型的list來處理。(譯者注:就是說,傳給<list>和<foreach>的參數不是list或者數組類型的,而是單個元素,則會被當成只有一個元素的list或者數組)

       6、“<include>”標簽的路徑參數將被作為絕對路徑處理。(譯者注:這里很多網上的文檔都沒有提過,是本人經過觀察發現的,然后從源碼和其注釋中找到的。在這種情況下,如果傳入的ftl路徑是相對路徑,則會報找不到文件的異常)。

       在其他方面,甚至是在兼容模式下,這個Freemaker解析引擎是2.1引擎,你不會因此而丟掉其他新的功能。

 

      以上就是譯文, 那么如果我們設置了全局的classic_compatible屬性,而在某個頁面上又不想遵守這個屬性該怎么辦呢?這樣就可以在當前這個頁面上采用以下的辦法,讓當前的頁面不再支持傳統模式:<#setting classic_compatible=false>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM