90.参考: Struts2のための
FreeMarkerリファレンス

概要

Struts2でHTMLデザインを記述するとき、s:textfieldタグなどを使用します。

そうすると、自動的にテキストボックスやタイトルを出力してくれるので大変便利です。

しかし、出力するデザインを独自のものに変更したい場合はどのようにするのでしょうか?

1つは、Struts2はtextやlabelなどのタグにclass属性を設定してくれるので、それを利用する方法があります。

つまり、CSS(スタイルシート)を使用してデザインを変えます。

ですがこれだけですと、色や幅などは変えられても大幅なデザインの変更はできません。

tableタグを出力させるなど、HTMLデザイン自体を変更したい場合は、ftlファイル(FreeMarker Template Language)を変更します。

結局FreeMarker を使用することになるのですが、FreeMarkerのすべてを覚えるのは大変です。

ここでは、「これだけ知っていればStruts2のFreeMarkerが使える」といったTips的なものを記述していこうと思います。

【補足】

Struts2では、FreeMarkerのHTMLデザインを変更する場合、たいていの場合、Struts2で用意しているテンプレートをコピーして

カスタマイズすることになります。

逆に言うと、Struts2のテンプレート(ftl)が読めれば何とかなります。

この記事では、「Struts2のftlを読める」を目標にしています。

FreeMarkerとは

FreeMarkerとはJavaで動作するテンプレートエンジンです。

大まかに言えば、モデル(POJO)をHTMLデザインに変換するツール、と思っていただければよいと思います。

JSPも同じことができるため、何故わざわざ別のツールを使用するの?と思われるかもしれないですね。

自分も今回初めて触ったのでそう思いました。

しかし、記述がJSPより簡潔になっていて書きやすいことと、モデルにプロパティ自体が存在しないときの対処方法などが

かなり楽になっています。

使い回ししやすい点もJSPと違うと思います。

以降では、FreeMarkerで覚えておいた方がよい概念を記述して、そのあと、Struts2におけるTipsのようなものを簡単に記述しようかと思います。

FreeMarkerでの基本概念

記述の仕方

FreeMarkerでは、XMLのようにタグのような記述の仕方をします。

開始・終了のタグが存在します。

【テンプレートファイル(ftl)の記述の例】

<#assign bl = parameters.isStudent />

<#if bl>

disabled="disabled"<#rt/>

</#if>

タグは、<# 始まりで記述します。

このタグをディレクティブ(Directive)と呼ぶそうです。

また、FreeMarkerがタグを用意していますので、それ以外のタグは使用できません。

上記では、#assignは、変数に値を設定するタグです。

#if は、javaのifと同じで条件分岐をするタグです。

テンプレートのロードとデータモデルの引き渡し

FreeMarkerは通常、テンプレートファイルの読み込みを行い、読み込んだテンプレートにモデル(POJO)を渡すという作業をしなければなりません。

しかし、Struts2を使用するとそれらは自動的に行われます。

ですのでこのあたりの処理は気にしなくても良いです。

ただ、テンプレートに渡すモデルがどのような構成になっているのかを記述しているドキュメントが見つかりませんでした。

ですので、それらを記述していくこともこの記事の目標になっています。

変数について

【使用できる変数(データ)】

FreeMarkerの変数は、主に二つあるようです。

・テンプレートに渡されたモデル

・テンプレート内で宣言されたもの

どちらも参照するときは、EL式のように、user.name といった記述の仕方をします。

【変数をデザインに文字列出力する方法】

${user.name} のように${ }で記述します。

【オブジェクトのメソッド】

FreeMarkerでは他の言語と同様にオブジェクトの持っているメソッドも呼び出せます。

例えば、変数varにString型のオブジェクトを設定したとします。

その場合、var.startWith('abc') のようにメソッドを呼び出せます。

【変数に使用できるbuilt-in関数】

FreeMarkerの特徴といっていいかもしれません。

オブジェクトが持っているメソッドとは別に、FreeMarkerが用意している関数があります。

built-in関数と呼ぶらしいですが、?を使用して呼び出します。

例: var?html や var.toString()?html

上記はhtmlエスケープをするbuilt-in関数の使用例です。

どのような関数があるかも後述していければと思います。

リファレンス

配列、マップなどの記述方法

【配列の記法】

["red", "green", "blue"]

【ハッシュの記法】

{"Joe":23, "Fred":25}

上記のように記述すると新たな配列、ハッシュを宣言できます。

取り出し方は以下のようになります。それぞれvarという変数に値が入っているとして記述しています。

配列: var[2] ⇒"blue"です。

ハッシュ: var.Joe ⇒23です

※ちなみに、配列もハッシュも+演算子が使用できて、要素を追加することができます。

例: {"a":1, "b":2} + {"c":3, "d":4} ⇒{"a":1, "b":2, "c":3, "d":4}

演算子

FreeMarkerの演算子のページを参考にして記述しています。

? :built-inの関数呼び出し

${remarks?html}

?は、built-in関数の呼び出しです。

変数の型によって呼び出せる関数が異なります。

例えば、上記の変数remarksがStringのときは、html関数を呼び出せます。

参考までにStringで使用できる関数を記述しておきます。

【Stringのbuilt-in関数の一覧 (一部)】

html: HTMLエスケープします。(例: < ⇒ &lt;)

cap_first: 文字列の先頭を大文字に変えます。

lower_case: 文字列の全てを小文字に変えます。

upper_case: 文字列の全てを大文字に変えます。

trim: 文字列の前後の空白を削除します。

built-in関数の一覧: http://freemarker.sourceforge.net/docs/ref_builtins.html

! :デフォルト値を指定する演算子

${name!'taro'}

${user.name!'taro'}

${(user.name)!'taro'}

! は、プロパティが存在しないかnullのときのデフォルト値を指定できます。

1段目の例を見てください。 もし、上記変数nameがnullのとき、"taro"が返ります。

もちろん、nameの値が"hanako"などのnull以外のとき、"hanako"が返ります。

2段目の例を見てください。

この場合も、nameプロパティがnullか、もしくはプロパティ自体が存在しなければ"taro"が返ります。

ただし、userがnullのときはエラーになります

3段目の例を見てください。

2段目のエラー回避のための記述方法です。

()を記述すると、何段階かのプロパティを介しても、いずれかでnullになれば"taro"を返します。

?? :変数が存在するかどうかをチェックする演算子

<#if mouse??>

yes

</#if>

変数が存在するかどうかをチェックします。

プロパティが階層指定(例:user.name)の場合は、デフォルト演算子(!)と同じルールになります。

タグ(Directive)

#if , #else , #elseif :条件分岐のディレクティブ

<#if x == 1>

x is 1

<#elseif x == 2>

x is 2

<#elseif x == 3>

x is 3

</#if>

条件分岐のためのタグです。

あまり説明はいらないかと思います。

ただ、>が使用できないという注意点があります。

使用したい場合、以下のいずれかの方法をとります。

【>のエスケープの方法】

【()をつける】

<#if (x > 1) >

<#if (x >= 1) >

【&gt;を使用する※】

<#if x &gt; 2 >

<#if x &gt;= 2 >

【\lt, \lte, \gt , \gte を使用する】

<#if x \lt 2 >

<#if x \lte 2 >

※&gt; の注意点

FreeMarkerでは、&...; という表現形式のサポートをしていません。

上記の$gt;は、ifの中でしか使用できないことに注意してください。

#include :他のテンプレート(ftl)を取り込むディレクティブ

<#include "/${parameters.templateDir}/${parameters.theme}/controlheader.ftl" />

他のftlファイルを取り込みます。

Struts2では、上記の例のように変数を使用してファイルパスを記述することが多いです。

parametersはStruts2が用意しているプロパティです。(詳しくは以降の章で記述していますのでそちらを参照ください。)

templateDirは、Struts2の設定ファイルに記述したtemplateの置き場所です。(概要の記事も参照)

ですので、templateDir が"template"で、theme="simple"が指定されていた場合は以下のようになります。

<#include "/template/simple/controlheader.ftl" />

Struts2はそこそこ部品のようにftlファイルを分割してくれているので、既存のthemeをincludeして再利用することが多くなると思います。

#assign :変数に値を設定するディレクティブ

<#assign name = parameters.name/>

変数に値を設定します。

値を設定しなおすときにも使用します。

上記の例では、変数nameに、s:textfield name="user.name" などで設定したname属性の値を設定しています。

#t , #lt , #rt :HTMLデザインに出力するときに空白を除去するディレクティブ

<#if parameters.name??>

name="${parameters.name?html}"<#rt/>

</#if>

タグなどで改行をすると、余計な空白ができてしまいます。

これらのタグは、余計な空白を除去します。

上記の例では、name="..."の後の改行が除去されます。

#t :前後の空白を削除します。

#lt :左側の空白を削除します。

#rt :右側の空白を削除します。

Struts2が用意しているデータモデル(プロパティ)

parameters :Struts2タグの属性値などを保持するプロパティ

<#if parameters.listKey??>

<#assign itemKey = parameters.listKey />

<#/if>

parametersプロパティには、Struts2のJSPのタグで指定した属性値が入っています。

上記の例では、listKey属性に値が設定されているかを#ifでチェックしています。

(以下の「カスタムパラメタの追加 (Struts2のタグからftlへの値の引き渡し)」も参照してみてください)

Struts2のタグの例:

<s:checkboxlist list="#{'1' : 'a', '2' : 'b', '3' : 'c'}" name="level"/>

⇒parameters.listKeyには、['1','2','3'] という配列が渡ってきます。

【OGNLの評価について】

Struts2では基本的に、すべての属性値がOGNLで評価されます。

そうすると、parametersに渡ってくる属性値はOGNLで評価される前の値なのか、それとも評価後の値なのかが気になります。

parmetersは評価後の値が渡ってくるようです。

どうもStruts2のタグは評価後の値をparametersという変数に詰めておくようです。

例えばStruts2のタグで、value="user.name"が設定された場合、%{user.name}を実行します。(評価します)

それで見つからなければ"user.name"という文字列として扱われます。

ですので評価に失敗すれば、parameters.valueには"user.name"という文字列が渡ってきます。

カスタムパラメタの追加 (Struts2のタグからftlへの値の引き渡し)

実は、parametersプロパティには属性値だけでなく、自由な変数を追加できます。

以下の例を見てください。

【JSP上の記述】

<s:checkbox name="user.status" value="true" >

<s:param name="myParam" value="%{'あいう'}"/>

</s:checkbox>

【ftl上での取得方法】

<#assign myParam= parameters.myParam />

Struts2のタグでは、s:paramというタグを使用できます。

これを使用すると、ftl 上でも値を取得できます。

stack :ValueStackオブジェクト

実はValueSatckも使用可能です。

stackというプロパティ名です。

<#assign itemKey = stack.findValue(parameters.listKey)/>

tag :タグクラスで用意されているメソッド呼び出し

タグクラス自体も参照できるようです。

<#if tag.contains(parameters.nameValue?default(''), itemKeyStr)>

checked="checked"<#rt/>

</#if>

tagには、contains()というメソッドがあります。

このメソッドは、配列の中に指定の値が含まれているかどうかをチェックするようです。

FreeMarkerの古いバージョンではこのようなbuilt-inがなかったため、Struts2はこのような方法で実現したのではないでしょうか。

ちなみに最新のFreeMarkerでは追加されたようです。

themeの継承

実は、FreeMarkerの他のthemeを継承することもできます。

継承と唐突に言われても分かりにくいかと思いますので、簡単に説明してから例を示したいと思います。

FreeMarkerは、フォルダとftlファイルによって構成されています。

template

├sample

├hidden.ftl

├radiomap.ftl

上記でいうと、sampleがthemeと呼ばれるもので、Javaでいうクラスのようなものです。

また、その配下にあるhidden.ftlはtemplateと呼ばれるもので、Javaでいうメソッドのようなものです。

FreeMarkerのいう継承とは、themeを継承して、ftlファイルをオーバーライドするイメージです。

上記のファイル構成での継承の例を以下に示します。

【template/sample2/theme.properties ファイル】

parent = sample

新しくsample2というthemeを作ったとします。

もし、上記のようなpropertiesファイルを作成した場合は、sample2フォルダの配下に何もなくてもsampleと同じ動作をします。

もし、hidden.ftlというファイルを作れば、hidden.ftlだけが上書きされてsampleと違う動きになります。

これがFreeMarkerの継承です。

ftlファイルの文字コードについて

ftlファイルにはタグ以外の文字を直接記述しない方がよいかもしれません。

特に"あいう"のような全角文字は、JSPの文字コードとftlのファイルの文字コードと一致していないと文字化けします。

ですので、parametersなどで受け取った文字を出力するようにして、直接記述するようにしない方がよいと思われます。

Created Date: 2012/02/11