freemarker的classic_compatible設置,解決報空錯誤

前段時間接觸freemaker時,原本後端寫各接口運行正常,但加入了模板後,頻繁報空指針問題,整了許久,最後仍是請教了別人解決了這個問題,如今記錄下來,方便之後碰到了能夠查閱。前端

錯誤樣例以下:java

ERROR: freemarker.runtime - Error executing FreeMarker template
FreeMarker template error:
The following has evaluated to null or missing:
==> user  [in template "include/header.ftl" at line 4, column 14]
 
----
Tip: If the failing expression is known to be 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: #if user  [in template "include/header.ftl" at line 4, column 9]
    - Reached through: #include "/include/header.ftl"  [in template "index.ftl" at line 6, column 1]
----
 
Java stack trace (for programmers):
----
freemarker.core.InvalidReferenceException: [... Exception message was already printed; see it above ...]
    at freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:131)
    at freemarker.core.UnexpectedTypeException.newDesciptionBuilder(UnexpectedTypeException.java:77)

 

能夠看到,在讀取user的時候,由於爲空,報錯了,錯誤處的代碼是這樣的web

<#if user>

其實準確的寫法應該是spring

<#if user??>

若是要消除錯誤,須要把前端代碼修後成後面這種形式,這讓一個後端開發的人來講很不合理啊,並且,模板中不止一處出現了這種寫法。express

請教之後把freemarker的配置修改以下:後端

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

添加了一行數組

 <prop key="classic_compatible">true</prop>

問題圓滿解決了。ui

從網上查找緣由,發現下面這位哥們已經比較詳細的解釋了,就全文摘錄吧。編碼

如下爲轉載內容,點擊查看原文lua

        在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」的由來)。(譯者注:如下的一、二、三、四、五、6是譯者本身加的,方便讀者看)

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

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

       二、做爲「<list expr as item>」、「<foreach item in expr>」這樣的表達式的參數,其循環體將不會被執行,和list的長度爲0是同樣的。

       三、做爲「<if>」或者其餘布爾表達式命令的參數,空值將被當成是false來處理。非布爾數據模型或者邏輯操做數也能夠放在「<if>」表達式中,空模型(長度爲零的字符串,空的數組或者hash集合)都被當成是false來對待,其餘狀況下都被當成是true來處理。

       四、當布爾值被當成字符串(好比用${...}輸出,或者是和其餘字符串鏈接),true值將被轉換成「true」字符串處理,false值將被轉換成空字符串。

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

       六、「<include>」標籤的路徑參數將被做爲絕對路徑處理。(譯者注:這裏不少網上的文檔都沒有提過,是本人通過觀察發現的,而後從源碼和其註釋中找到的。在這種狀況下,若是傳入的ftl路徑是相對路徑,則會報找不到文件的異常)。

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

 

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

相關文章
相關標籤/搜索