天天看點

Groovy模闆引擎

本文參考自 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正常解析了。