【FreeMarker】【程式開發】資料模型,物件包裝
在簡單的示例中,可以使用 java.lang 和 java.util 包下的類,還有使用者自定義的 Java Bean來構建資料物件。
- 使用 java.lang.String 來構建字串
- 使用java.lang.Number 來派生數字型別
- 使用 java.lang.Boolean 來構建布林值
- 使用 java.util.List 或 Java 陣列構建序列
- 使用 java.util.Map 來構建雜湊表
- 使用自定義的 bean 類來構建雜湊表,bean中的項和bean的屬性對應
資料模型
在內部,模板中可用的變數都是實現了 freemarker.template.TemplateModel 介面的 java 物件。
但在自己的資料模型中,可以使用基本的Java集合類作為變數,因為這些變數會在內部被替換為適當的 TemplateModel 型別;這種功能特性被稱為 object wrapping 物件包裝。
物件包裝功能可以透明地把任何型別的物件轉換為實現了 TemplateModel 介面型別的例項。
這就是的下面的轉換成為可能,如在模板中 java.sql.ResultSet 轉換為序列變數,把 javax.servlet.ServletRequest 物件轉換成包含請求屬性的雜湊表變數,甚至可以遍歷 XML 文件作為 FTL變數。
包裝這些物件,需要使用合適的,也就是所謂的物件包裝器是錢(也可能是自定義的實現)。
標量
4中型別的變數:
- 布林值 —— 實現TemplateBooleanModel介面
- 數字 —— 實現TemplateNumberModel介面
- 字串 —— 實現TemplateScalarModel介面
- 日期 —— 實現TemplateDateModel介面
容器
雜湊表
FreeMarker中的雜湊表是實現了 TemplateHashModel 介面的物件。TemplateHashModelEx介面擴充套件了TemplateHashModel介面;經常使用的實現類是SimpleHash,該類實現了TemplateHashModelEx介面。
序列
序列是實現了TemplateSequenceModel介面的Java物件。經常使用的實現類是SimpleSequence。
集合
集合是實現了TemplateCollectionModel介面的Java物件。通常使用的實現類是SimpleCollection。
方法
方法變數實現了 TemplateMethodModel 介面。這個介面僅包含一個方法:TemplateModel exec(java.util.List arguments),當使用方法呼叫表示式去呼叫方法時,exec方法將會被呼叫。形參將會包含FTL方法呼叫形參的值,exec方法的返回值給出了FTL方法呼叫表示式的返回值。
TemplateMethodModelEx介面擴充套件了TemplateMethodModel介面。
例如:
public class IndexOfMethod implements TemplateMethodModel {
public TemplateModel exec(List args) throws TemplateModelException {
if (args.size() != 2) {
throw new TemplateModelException("Wrong arguments");
}
return new SimpleNumber(
((String) args.get(1)).indexOf((String) args.get(0)));
}
}
將一個方法例項放入根資料模型中,
root.put("indexOf", new IndexOfMethod());
在模板中呼叫:
<#assign x = "something">
${indexOf("met", x)}
${indexOf("foo", x)}
輸出為:
2
-1
指令@
指令變數實現了TemplateDirectiveModel介面。
節點變數
節點變數體現了樹形結構中的節點。節點變數的引入是為了幫助使用者在資料模型中處理XML文件,也可以使用者構建樹狀模型。
節點變數實現TemplateNodeModel介面。
物件包裝
當往容器中新增一些物件時,可以是任意java物件型別的引數,而不一定是TemplateModel。這是因為模板實現會默默地用合適的TemplateModel物件來替換原有物件。比如向容器中加入一個String,也許它將被替換為一個SimpleScalar例項來儲存相同的文字。
至於什麼型別的Java物件可以被替換,又使用什麼樣的TemplateModel來實現,它可以被實現的容器自身來控制,也可以委派給ObjectWrapper的一個例項。
ObjectWrapper是一個介面,其中只定義了一個方法:TemplateModel wrap(java.lang.Object obj)。可以傳遞一個object型別的物件,它會返回對應的TemplateModel物件,如果不行則丟擲TemplateModelException一場。替換原則是在ObjectWrapper的實現類中編碼實現的。
最重要的ObjectWrapper實現類是FreeMarker核心包提供的:
public interface ObjectWrapper {
ObjectWrapper BEANS_WRAPPER = BeansWrapper.getDefaultInstance();
ObjectWrapper DEFAULT_WRAPPER = DefaultObjectWrapper.instance;
ObjectWrapper SIMPLE_WRAPPER = SimpleObjectWrapper.instance;
我們使用java.util.HashMap作為根的雜湊表,而不是SimpleHash或其他特定的FreeMarker類,因為Template.process(...)自動包裝了給定的資料模型引數的物件,所以它才會起作用。它使用受Configuration設定的物件包裝器。因此,編寫簡單的FreeMarker應用程式就不需要知道TemplateModel。注意根的型別不需要一定是java.util.Map,它也可以是實現了TemplateHashModel介面的被包裝的物件。