天天看點

Groovy模闆引擎下(The MarkupTemplateEngine引擎細節介紹)

1.1基礎:

模闆包含groovy代碼,下面詳細具體的解析一下第一個樣例:

1 渲染xml的聲明字元串

2 打開一個cars标簽

3 cars是模闆資料模型的一個變量包含了所有的car執行個體

4 周遊每一項,從car執行個體建立car标簽

5 關閉上述的cars标簽

模闆可以使用通常的groovy代碼,能在list(來自模闆資料模型)上使用each為每個car執行個體生成一個car标簽。

相似的情景下,渲染html代碼非常簡單:

1 渲染html檔案類型的标簽

2 打開一個帶有屬性的html标簽

3 打開一個head标簽

4 渲染帶有http-equiv屬性的 meta标簽

5 渲染title标簽

6 關閉head 标簽

7 打開head标簽

8 渲染p标簽

9 關閉body标簽

10 關閉html标簽

輸出結果如下:

通過一些配置,能美化輸出,增加一些換行以及縮進。

1.2支援的方法

上述示例,文檔類型通過<code>yieldunescaped方法渲染。同時我們也見到過xmldeclaration方法。模闆引擎支援多種方法幫助渲染内容。</code>

方法名

描述

樣例

yield

渲染内容,但是渲染前會轉義

模闆:yield ‘some text with &lt;angle brackets&gt;’輸出:some text with &amp;lt;angle brackets&amp;gt;

yieldunescaped

渲染原始内容,渲染後不進行轉義

模闆:yieldunescaped ‘some text with &lt;angle brackets&gt;’輸出:some text with &lt;angle brackets&gt;

xmldeclaration

渲染xml聲明字元串。如果在配置檔案中編碼進行了聲明,則會寫入xml聲明

模闆:xmldeclaration()輸出:&lt;?xml version=’1.0’?&gt;如果templateconfiguration#getdeclarationencoding非空輸出:&lt;?xml version=’1.0′ encoding=’utf-8’?&gt;

comment

渲染原始内容到xml的注釋中

模闆:comment ‘this is &lt;a href=’http://docs.groovy-lang.org/latest/html/documentation/foo.html’&gt;commented out&lt;/a&gt;’輸出:&lt;!–this is &lt;a href=’http://docs.groovy-lang.org/latest/html/documentation/foo.html’&gt;commented out&lt;/a&gt;–&gt;

newline

渲染新行同時參考:templateconfiguration#setautonewline和templateconfiguration#setnewlinestring.

模闆:p(‘text’)newline()p(‘text on new line’)輸出:&lt;p&gt;text&lt;/p&gt;&lt;p&gt;text on new line&lt;/p&gt;

pi

渲染xml處理聲明

模闆:pi(“xml-stylesheet”:[href:”mystyle.css”, type:”text/css”])輸出:&lt;?xml-stylesheet href=’mystyle.css’ type=’text/css’?&gt;

tryescape

如果是對象字元串,從實體對象渲染轉義的字元串,否則傳回實體對象本身

模闆:yieldunescaped tryescape(‘some text with &lt;angle brackets&gt;’)輸出:some text with &amp;lt;angle brackets&amp;gt;

1.3 包含

<code>markuptemplateengine模闆支援從其他檔案引入内容,引入的類型可以是:</code>

另一個模闆

原始内容

轉義的内容

引入另外的模闆如下:

如果引入的檔案名是動态的(存儲在變量中)則使用上述的方法替代 include xxx:文法是非常有用的。引入的檔案能在classpath上找到。這是markuptemplateengine接受classloader 作為構造器參數的原因(其他的原因:在模闆中引入涉及到其他類的代碼)

如果你不想設定模闆到classpath上,markuptemplateengine可以接受一個友善的構造器友善你定義模闆所在的檔案目錄。

1.4 片段

片段是内嵌的模闆,他們在單一的模闆中内提高複用性。一個碎片包含:字元串,内嵌模闆和模型 用于渲染模闆。參考下面的模闆:

<code>1</code>

<code>ul {</code>

<code>2</code>

<code>    </code><code>pages.each {</code>

<code>3</code>

<code>        </code><code>fragment </code><code>"li(line)"</code><code>, line:it</code>

<code>4</code>

<code>    </code><code>}</code>

<code>5</code>

<code>}</code>

fragment元素建立内嵌模闆,根據指定的模型渲染模闆。這裡,我們有li(line)片段, line綁定到it, it對應于pages的周遊,我們将會為每個page生成單個的li元素.

片段對于模闆元素的分解非常有意思,對于模闆來說,他們需要付出片段編譯的代碼,并且不能外部化。

1.5 布局

布局涉及到其他的模闆。通常用于組合模闆并且共享通用的結構。如果你的html頁面有通用的布局,并且隻想替換body,那麼布局将是非常有意思的,将簡化操作。首先,需要建立一個布局模闆:

layout-main.tpl

1. title變量是布局變量

2. 調用bodycontents渲染body

然後需要做的就是在模闆中引入布局:

this is the body

對于contents方法的調用通知模闆引擎這塊代碼對于模闆是特殊的聲明而不是用于直接渲染的幫助方法。如果沒有在聲明前新增contents方法,那麼内容将直接被渲染,但是你會看到一個随機生成的字元串而不是代碼塊對應的結果值。

布局是一個有力的方式共享橫跨多個模闆的通用内容。不需要重寫以及引入任何東西。

布局所用的資料模型和頁面所用的資料模型是獨立的。然後繼承頁面的資料模型也是可行的,設想一下定義的模型如下:

<code>model = new hashmap&lt;string,object&gt;();</code>

<code>model.put('title','title from main model');</code>

模闆如下:

<code>layout 'layout-main.tpl', true,                             (1)</code>

<code>    </code><code>bodycontents: contents { p('this is the body') }</code>

1. 注意設定成ture開啟模闆繼承。

是以,傳遞title的值到先前的例子就變的不是那麼必要。渲染的結果如下:

<code>&lt;html&gt;&lt;head&gt;&lt;title&gt;title from main model&lt;/title&gt;&lt;/head&gt;&lt;body&gt;&lt;p&gt;this is the body&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</code>

但是重寫來自父模型的值也是可能的:

<code>    </code><code>title: 'overriden title',                               (2)</code>

1 true表示從父模型繼承

2 但是title被重寫

輸出的結果如下:

<code>&lt;html&gt;&lt;head&gt;&lt;title&gt;overriden title&lt;/title&gt;&lt;/head&gt;&lt;body&gt;&lt;p&gt;this is the body&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</code>

2 渲染内容

2.1建立模闆引擎

服務端渲染模闆引擎需要groovy.text.markup.markuptemplateengine和groovy.text.markup.templateconfiguration的執行個體

<code>templateconfiguration config = new templateconfiguration(); (1)</code>

<code>markuptemplateengine engine = new markuptemplateengine(config); (2)</code>

<code>template template = engine.createtemplate("p('test template')"); (3)</code>

<code>map&lt;string, object&gt; model = new hashmap&lt;&gt;(); (4)</code>

<code>writable output = template.make(model); (5)</code>

<code>6</code>

<code>output.writeto(writer); (6)</code>

1 建立模闆配置

2 基于模闆配置建立模闆引擎

3 基于字元串建立模闆

4 建立用于模闆的資料模型

5 綁定資料模型到模闆

6 渲染輸出

下面是解析模闆的一些可選擇的項:

基于string,使用createtemplate(string)

基于reader, 使用createtemplate(reader)

基于url, 使用 createtemplate(url)

基于模闆名, 使用 createtemplatebypath(string)

通常被建議的最終的版本:

<code>template template = engine.createtemplatebypath("main.tpl");</code>

<code>writable output = template.make(model);</code>

<code>output.writeto(writer);</code>

2.2 配置選項

通過<code>templateconfiguration的一些配置選項,可以配置引擎,改變引擎的預設行為:</code>

選項

預設值

declarationencoding

null

定義調用xmldeclaration時預設的編碼格式,本身不影響輸出

xmldeclaration()輸出:

&lt;?xml version=’1.0’?&gt;

如果templateconfiguration#getdeclarationencoding非空:

輸出:

&lt;?xml version=’1.0′ encoding=’utf-8’?&gt;

expandemptyelements

false

如果true,輸出标簽的擴充格式

模闆:p()輸出:

&lt;p/&gt;

如果expandemptyelements 是true:

&lt;p&gt;&lt;/p&gt;

如果true,屬性的雙引号代替單引号

模闆:tag(attr:’value’)輸出:

&lt;tag attr=’value’/&gt;

如果usedoublequotes是true:

&lt;tag attr=”value”/&gt;

newlinestring

系統預設(系統屬性line.separator)

允許選擇新行渲染所使用的字元串

模闆p(‘foo’)newline()

p(‘baz’)

如果newlinestring=’bar':

&lt;p&gt;foo&lt;/p&gt;bar&lt;p&gt;baz&lt;/p&gt;

autoescape

如果true,資料模型中的變量會在渲染前自動轉義

autoindent

如果true,執行新行後的自動縮進

autoindentstring

4空格

縮進使用的字元串

autonewline

如果true,執行新行的自動插入

basetemplateclass

groovy.text.markup.basetemplate

設定編譯模闆的父類,提供應用所需的特殊模闆

locale

default locale

設定模闆預設的語言環境

2.3. 自動格式化

預設的,模闆引擎會輸出沒有格式化的文本。參見配置選項,對輸出做必要的格式化

<code>autoindent</code> 新行插入後自動縮進

<code>autonewline</code> 基于原始預設的模闆内容自動插入新行

通常,推薦設定autoindent和autonewline為true,增加可讀性,代碼如下:

<code>config.setautonewline(true);</code>

<code>config.setautoindent(true);</code>

使用下面的模闆:

<code>html {</code>

<code>    </code><code>head {</code>

<code>        </code><code>title('title')</code>

輸出結果:

<code>&lt;html&gt;</code>

<code>    </code><code>&lt;head&gt;</code>

<code>        </code><code>&lt;title&gt;title&lt;/title&gt;</code>

<code>    </code><code>&lt;/head&gt;</code>

<code>&lt;/html&gt;</code>

我們可以稍微的調整模闆讓title和heade位于同一行

<code>    </code><code>head { title('title')</code>

輸出如下:

<code>    </code><code>&lt;head&gt;&lt;title&gt;title&lt;/title&gt;</code>

新行僅僅插入在花括号标簽之後,同時插入對應于新的内嵌内容被發現的地方。這就意味着标簽中包含的标簽不會觸發新行的插入除非使用花括号。

<code>        </code><code>meta(attr:'value')          (1)</code>

<code>        </code><code>title('title')              (2)</code>

<code>        </code><code>newline()                   (3)</code>

<code>        </code><code>meta(attr:'value2')         (4)</code>

<code>7</code>

<code>8</code>

1 meta和head不在同一行,新行被出入

2 新行不會被插入,和前面的标簽處于同一深度

3 調用newline強制插入新行

4 在新行被渲染

<code>        </code><code>&lt;meta attr='value'/&gt;&lt;title&gt;title&lt;/title&gt;</code>

<code>        </code><code>&lt;meta attr='value2'/&gt;</code>

預設的情況下,現在使用4個空格縮進,但是可以通過設定templateconfiguration#autoindentstring屬性來定制化。