CLOVER🍀

That was when it all began.

テンプレートエンジンをサクッと試したいなら、Groovyを使用してはいかがでしょう?

夏休み前の小ネタです。

JavaでViewを書く時って、最近は何を使うのが流行りなのでしょうか?いろいろあると思いますが、まだまだVelocityやFreeMarkerといったテンプレートエンジンが主流だよという開発現場も多いと思います。

…自分のことです。

Apache Velocity
http://velocity.apache.org/

FreeMarker
http://freemarker.org/

で、これらを使うはいいんですけど、初めて使う時とか、ちょっと構文やディレクティブを確認したい時に、Groovyだと簡単に試せるよ!というお話。

Velocityだと拡張子が「.vm」、FreeMarkerだと拡張子が「.ftl」のファイルを通常テンプレートとして作成して、テンプレートの評価を行います。

が、わざわざファイルを用意しなくても、Stringをテンプレートとするクラスが、両ライブラリには備わっています。

StringResourceLoader
http://velocity.apache.org/engine/releases/velocity-1.7/apidocs/org/apache/velocity/runtime/resource/loader/StringResourceLoader.html

StringTemplateLoader
http://freemarker.org/docs/api/freemarker/cache/StringTemplateLoader.html

なんですが、テンプレートって1行で済むものじゃないし、Javaだと複数行に跨る文字列を書くの、面倒ですよね。

その他、クラスパスの設定をして…Mavenでもいいですよ?でも、最初に動かすまで、いろいろ準備が大変ですよね。

そこで、オススメしたいのがGroovy+Grapeを使うことです。

ライブラリの依存関係は、Grapeで一発!
Velocity

@Grab('org.apache.velocity:velocity:1.7')

FreeMarker

@Grab('org.freemarker:freemarker:2.3.20')

複数行に跨るテンプレートを書くのも、Groovyなら簡単です。
Velocity

// テンプレートの内容
def templateAsString = '''\
Hello ${name}!!

このブログのURLは、${blog_url}です。

プログラミング言語:
#foreach ($language in $languages)
${language}
#end

Mapでバインド:
key1 => ${map.key1}
key2 => ${map.key2}

Groovy参考書籍:
タイトル:${book.title}
お値段:${book.price}
発売日:${book.publishDate}'''

FreeMarker

// テンプレートの内容
def templateAsString = '''\
Hello ${name}!!

このブログのURLは、${blog_url}です。

プログラミング言語:
<#list languages as language>
${language}
</#list>

Mapでバインド:
key1 => ${map.key1}
key2 => ${map.key2}

Groovy参考書籍:
タイトル:${book.title}
お値段:${book.price}
発売日:${book.publishDate}'''

複数行に跨る文字列を「'''」で囲っているところが、Groovy的にはポイントです。

では、それぞれちょっとしたサンプルを。

Velocity

velocity-runner.groovy 
@Grab('org.apache.velocity:velocity:1.7')
import org.apache.velocity.VelocityContext
import org.apache.velocity.Template
import org.apache.velocity.app.Velocity
import org.apache.velocity.runtime.resource.loader.StringResourceLoader

// テンプレート名
def templateName = 'stringTemplate.vm'

// テンプレートの内容
def templateAsString = '''\
Hello ${name}!!

このブログのURLは、${blog_url}です。

プログラミング言語:
#foreach ($language in $languages)
${language}
#end

Mapでバインド:
key1 => ${map.key1}
key2 => ${map.key2}

Groovy参考書籍:
タイトル:${book.title}
お値段:${book.price}
発売日:${book.publishDate}'''

// StringResourceLoaderを使用するように設定
Velocity.addProperty(Velocity.RESOURCE_LOADER, 'string')
Velocity.addProperty('string.resource.loader.class', StringResourceLoader.class.name)

// Velocityの初期化
Velocity.init()

// テンプレートの登録
def repository = StringResourceLoader.repository
repository.putStringResource(templateName, templateAsString)

def template = Velocity.getTemplate(templateName, 'UTF-8')

// VelocityContextの作成
def context = new VelocityContext()

// テンプレートにバインドするデータを登録
context.put('name', 'Velocity')
context.put('blog_url', 'http://d.hatena.ne.jp/Kazuhira/')
context.put('languages', ['Java', 'Groovy', 'JavaScript', 'Perl', 'PHP'])
context.put('map', [key1: 'value1', key2: 'value2'])
context.put('book', new Book(title: 'プログラミングGROOVY',
                             price: 3360,
                             publishDate: '2011/07/06'))

// テンプレートの評価と結果表示
def writer = new StringWriter()
template.merge(context, writer)
println(writer.toString())

class Book {
    def title
    def price
    def publishDate
}

FreeMarker
freemarker-runner.groovy

@Grab('org.freemarker:freemarker:2.3.20')
import freemarker.cache.StringTemplateLoader
import freemarker.template.Configuration

// テンプレート名
def templateName = 'stringTemplate.ftl'

// テンプレートの内容
def templateAsString = '''\
Hello ${name}!!

このブログのURLは、${blog_url}です。

プログラミング言語:
<#list languages as language>
${language}
</#list>

Mapでバインド:
key1 => ${map.key1}
key2 => ${map.key2}

Groovy参考書籍:
タイトル:${book.title}
お値段:${book.price}
発売日:${book.publishDate}'''


def configuration = new Configuration()
// NumberFormatは変えてます…
configuration.numberFormat = '###'

// 該当のテンプレートに対して、StringTemplateLoaderを使用するように設定
def templateLoader = new StringTemplateLoader()
templateLoader.putTemplate(templateName, templateAsString)
configuration.templateLoader = templateLoader

def template = configuration.getTemplate(templateName)

// テンプレートにバインドするデータを登録
def context = [:]
context.put('name', 'FreeMarker')
context.put('blog_url', 'http://d.hatena.ne.jp/Kazuhira/')
context.put('languages', ['Java', 'Groovy', 'JavaScript', 'Perl', 'PHP'])
context.put('map', [key1: 'value1', key2: 'value2'])
context.put('book', new Book(title: 'プログラミングGROOVY',
                             price: 3360,
                             publishDate: '2011/07/06'))

// テンプレートの評価と結果表示
def writer = new StringWriter()
template.process(context, writer)
println(writer.toString())

class Book {
    def title
    def price
    def publishDate
}

実行結果は、それぞれこんな感じです。
Velocity

$ groovy velocity-runner.groovy 
Hello Velocity!!

このブログのURLは、http://d.hatena.ne.jp/Kazuhira/です。

プログラミング言語:
Java
Groovy
JavaScript
Perl
PHP

Mapでバインド:
key1 => value1
key2 => value2

Groovy参考書籍:
タイトル:プログラミングGROOVY
お値段:3360
発売日:2011/07/06

FreeMarker

$ groovy freemarker-runner.groovy 
Hello FreeMarker!!

このブログのURLは、http://d.hatena.ne.jp/Kazuhira/です。

プログラミング言語:
Java
Groovy
JavaScript
Perl
PHP

Mapでバインド:
key1 => value1
key2 => value2

Groovy参考書籍:
タイトル:プログラミングGROOVY
お値段:3360
発売日:2011/07/06

とまあ、いろいろ用意しなくても比較的簡単に動かすことができます。

Groovyの文法を覚えていない場合は?この例は、Groovyの構文をそれなりに出していますが、Javaのほぼ上位互換でもあるので、慣れないならJavaの構文で書いてもだいたいは大丈夫です。

Velocity、FreeMarkerに限らず、簡単な動作確認とかはサクッと行えるので、Java開発にどっぷりな現場ほど、Groovyを使うと便利な局面がそれなりにあるんじゃないかなーと思います。

簡単なスクリプトを書いたり、GroovyConsoleも便利ですよ。

…と、ちょっと変わったノリでエントリを書いてみました。