本文參考自 Template engines ,大部分代碼直接引用了文檔的内容。
模闆引擎介紹
Groovy語言包含了一個模闆引擎功能,可以生成各種類型的格式化檔案,非常友善。模闆引擎有下面幾個,它們都實作了Template接口。
- SimpleTemplateEngine - 基本的模闆
- StreamingTemplateEngine - 功能和 SimpleTemplateEngine相同,不過支援大于64k的模闆
- GStringTemplateEngine - 将模闆儲存為可寫的閉包,在流式場景中很有用
- XmlTemplateEngine - 輸出XML檔案的模闆引擎
- MarkupTemplateEngine - 一個完整的、優化過的模闆引擎,可以用于生成HTML等模闆
SimpleTemplateEngine
這是最賤的模闆引擎, 使用起來也非常簡單。直接看Groovy文檔的例子吧。可以看到它的模闆文法類似JSP标簽和EL表達式。
def text = 'Dear "$firstname $lastname",\nSo nice to meet you in <% print city %>.\nSee you in ${month},\n${signed}'
def binding = ["firstname":"Sam", "lastname":"Pullara", "city":"San Francisco", "month":"December", "signed":"Groovy-Dev"]
def engine = new groovy.text.SimpleTemplateEngine()
def template = engine.createTemplate(text).make(binding)
def result = 'Dear "Sam Pullara",\nSo nice to meet you in San Francisco.\nSee you in December,\nGroovy-Dev'
StreamingTemplateEngine
它和SimpleTemplateEngine類似,隻不過能處理比較大的文本。它使用
<% %>
、
<%= %>
和GString文法。下面的例子同樣來自Groovy文檔。
def text = '''\
Dear <% out.print firstname %> ${lastname},
We <% if (accepted) out.print 'are pleased' else out.print 'regret' %> \
to inform you that your paper entitled
'$title' was ${ accepted ? 'accepted' : 'rejected' }.
The conference committee.'''
def template = new groovy.text.StreamingTemplateEngine().createTemplate(text)
def binding = [
firstname : "Grace",
lastname : "Hopper",
accepted : true,
title : 'Groovy for COBOL programmers'
]
String response = template.make(binding)
assert response == '''Dear Grace Hopper,
We are pleased to inform you that your paper entitled
'Groovy for COBOL programmers' was accepted.
The conference committee.'''
GStringTemplateEngine
首先我們先将模闆儲存為檔案。注意在模闆中沒有使用print方法,而是使用out,這樣符合GString的規範。
Dear "$firstname $lastname",
So nice to meet you in <% out << (city == "New York" ? "\\"The Big Apple\\"" : city) %>.
See you in ${month},
${signed}
然後讀取模闆,并使用給定的字元串替換模闆。
def f = new File('test.template')
def engine = new groovy.text.GStringTemplateEngine()
def template = engine.createTemplate(f).make(binding)
println template.toString()
XmlTemplateEngine
XmlTemplateEngine用于生成XML模闆。它提供了标準的
${expression}
和
$variable
文法來插入資料。還提供了
<gsp:scriptlet>
<gsp:expression>
用來插入代碼段和表達式。
<>"'
這幾個符号會在處理模闆的時候轉義。
gsp: tags
命名空間的标簽會在模闆生成的時候移除,其他命名空間則不會移除。
下面是Groovy文檔的例子。
def binding = [firstname: 'Jochen', lastname: 'Theodorou', nickname: 'blackdrag', salutation: 'Dear']
def engine = new groovy.text.XmlTemplateEngine()
def text = '''\
<document xmlns:gsp='http://groovy.codehaus.org/2005/gsp' xmlns:foo='baz' type='letter'>
<gsp:scriptlet>def greeting = "${salutation}est"</gsp:scriptlet>
<gsp:expression>greeting</gsp:expression>
<foo:to>$firstname "$nickname" $lastname</foo:to>
How are you today?
</document>
'''
def template = engine.createTemplate(text).make(binding)
println template.toString()
生成的結果如下。
<document type='letter'>
Dearest
<foo:to xmlns:foo='baz'>
Jochen "blackdrag" Theodorou
</foo:to>
How are you today?
</document>
MarkupTemplateEngine
簡介
終于說到重點了。這其實才是本篇文章想要說的重點内容。在官方文檔中,前面所有内容才占了所有内容的四分之一。剩下的内容都在這裡。
Groovy标記模闆引擎的功能很強,完全可以作為一個WEB程式的視圖層使用。不過我在實際用的時候發現一點問題,那就是Intellij IDEA沒有支援……這就比較蛋疼了,我好像在記事本裡寫代碼一樣。這大概就是它最主要的缺點了吧。
這個标記模闆引擎主要用來生成類XML的模闆,類似HTML等等。但是也可以用來生成所有類型的文檔。前面那些模闆都是基于字元串的。而這個模闆是基于Groovy DSL的(學過Gradle就明白了,它們長得很像)。
先來看看直覺的例子吧。假設有下面的模闆。
xmlDeclaration()
cars {
cars.each {
car(make: it.make, model: it.model)
}
}
模型資料是這樣的。
model = [cars: [new Car(make: 'Peugeot', model: '508'), new Car(make: 'Toyota', model: 'Prius')]]
最後生成的檔案類似這樣。
<?xml version='1.0'?>
<cars><car make='Peugeot' model='508'/><car make='Toyota' model='Prius'/></cars>
Groovy标記模闆引擎提供的功能有強類型的模型檢查、代碼片和導入、國際化等幾個重要功能。
代碼格式和方法
标記模闆其實是合法的Groovy代碼。下面這個代碼中其實有很多方法和閉包,看看你能認出幾個。其實看了這麼多Groovy文章的話,應該很容易猜出來哪些是方法、哪些是參數了。
yieldUnescaped '<!DOCTYPE html>'
html(lang:'en') {
head {
meta('http-equiv':'"Content-Type" content="text/html; charset=utf-8"')
title('My page')
}
body {
p('This is an example of HTML contents')
}
}
廢話就不說了。說說常用的方法吧。
- yieldUnescaped方法會直接輸出給定的語句,不轉義其中的字元。
- yield方法和上面相反,會轉義特殊字元。
- head這些HTML标簽方法會生成對應的标簽。
- xmlDeclaration()方法會生成一個标準的XML文檔頭。
- comment方法生成HTML注釋。
- newLine生成一個新行。
包含
模闆中還可以包含其他模闆。下面是三種包含方式,分别包含另一個模闆,不需要轉義的文本或者是需要轉義的文本。
include template: 'other_template.tpl'
include unescaped: 'raw.txt'
include escaped: 'to_be_escaped.txt'
還有幾個等價的Groovy方法,這些方法主要在模闆檔案是動态的時候才有用。
includeGroovy(<name>)
includeEscaped(<name>)
includeUnescaped(<name>)
布局
我們可以編寫布局檔案。布局檔案和其它Groovy模闆檔案的字尾名都是
tpl
。我一開始不知道,結果找不到視圖檔案,花了不少時間。例如編寫下面這樣一個檔案。
html {
head {
title(title)
}
body {
bodyContents()
}
}
然後将頁面寫為下面這樣。Groovy模闆引擎會将布局檔案和實際布局結合,生成最終的布局。
layout 'layout-main.tpl',
title: 'Layout example',
bodyContents: contents { p('This is the body') }
使用模闆引擎
使用方法和其他模闆引擎差不多。都要建立引擎執行個體,然後傳入模闆檔案和資料。标記模闆引擎還需要一個額外的配置對象。
TemplateConfiguration config = new TemplateConfiguration();
MarkupTemplateEngine engine = new MarkupTemplateEngine(config);
Template template = engine.createTemplate("p('test template')");
Map<String, Object> model = new HashMap<>();
Writable output = template.make(model);
output.writeTo(writer);
預設情況下生成的模闆是部分行的,适合生産環境但是不适合人類閱讀。我們可以修改配置來讓結果更可讀。下面的配置打開了縮進和分行。其他配置請查閱相應文檔。
config.setAutoNewLine(true);
config.setAutoIndent(true);
國際化
我們可以為每個模闆檔案建立不同區域的版本,這樣就可以讓程式可以實作國際化功能。例如,原始的檔案是
file.tpl
,那麼法語版本的檔案就是
file_fr_FR.tpl
,英語版本就是
file_en_US.tpl
。在建立模闆配置對象的時候,我們可以傳遞一個
Locale
對象作為預設區域使用。
強類型聲明
Groovy模闆的類型是在運作時解析的,不過我們也可以手動聲明資料類型,這樣模闆執行速度會更快。在
modelTypes
中将使用到的模型聲明出即可。
modelTypes = {
List<Page> pages
}
pages.each { page ->
p("Page title: $page.title")
p(page.text)
}
Spring內建
Spring對Groovy标記模闆提供了支援。隻要類路徑存在Groovy相關類,就可以配置使用Groovy标記模闆。
首先先添加Groovy的依賴。下面是Gradle的依賴配置。
compile 'org.codehaus.groovy:groovy-all:2.4.9'
然後在Spring配置檔案中添加下面的配置。
<!--Groovy模闆引擎-->
<mvc:view-resolvers>
<mvc:groovy/>
</mvc:view-resolvers>
<!--Groovy模闆引擎配置-->
<mvc:groovy-configurer auto-indent="true"
cache-templates="false"
resource-loader-path="/WEB-INF/templates"/>
之後,在配置的模闆路徑下編寫
*.tpl
格式的模闆檔案,就可以讓Spring正常解析了。