はじめまして。「あそんで♪HuggPet」というソーシャルゲームのフロントエンドの開発を担当しています、2012年入社のホシナと申します。

「あそんで♪HuggPet」(以下HuggPet)では、開発にFreeMarkerというテンプレートエンジンを使用しています。今回は、FreeMarkerを使った開発を、フロントサイドの視点から少しばかりご紹介したいと思います。

FreeMarkerとは

FreeMarkerはJavaベースのテンプレートエンジンです。
FreeMarker Template Languageという言語で書かれたテンプレートファイルとJavaオブジェクトから、動的にHTMLのソースコードを生成することができます。


今回ご紹介するのは、テンプレートファイル(以下FTLファイル)側の基本的な書き方です。「そもそもFreeMarkerってなに?」「どう書けば良いの?」というフロントディベロッパーさんにお読みいただけると良いかもしれません。

FreeMarkerの全体的な機能についての詳細は、ここでは省略させていただきます。
ご興味のある方は、こちらをご参照ください。

FTLファイルの基本

先程も述べた通り、FTLファイルでは動的にHTMLのソースコードを生成できます。
まずはサーバサイドから受け取った変数をブラウザに出力してみましょう。下記のようなFTLファイルを用意します。

test.ftl
<!DOCTYPE html>
<html lang="ja">
<head>
	<title>テスト</title>
</head>
<body>
	<#-- テスト -->
	<p>テスト:${hoge}</p>
</body>
</html>

普通のhtmlファイルのソースコードと違うのは、
<#-- テスト -->
<p>テスト:${hoge}</p>
この辺りの記述ですね。

ここで、サーバサイドで、変数"hoge"に"fuga"という文字列を設定したとします。
すると、test.ftlのブラウザでの実行結果は
テスト:fuga
となります。"${hoge}"の部分に変数の値が出力されます。

FTLファイルでは、"${(変数名)}"という記述で変数にアクセスできます。変数には、文字列・数値・ブール値・配列・ハッシュ・Date型の値などを入れることができます。

変数の値をHTMLに直接出力する際は、エスケープ処理を忘れないようにしなければなりません。FTLにはエスケープ処理をしてくれるビルトインが用意されていて、
${hoge?html}
このように記述すればOKです。

また、コメント文は下のように書きます。
<#-- ここにコメントを書く -->

このように、サーバサイドから値を受け取ってソースコードを動的に生成していくのがFTLファイルの基本的な動きとなります。

それでは、HuggPetのソースコードを見ながら、現場での使用例をご紹介していきます。

"${(変数名)}"の使用例


画像の赤枠の部分は、ユーザーのピグ画像・ペット画像・体力ゲージを表示するモジュールです。この部分のFTLファイルのソースコードは、以下のようになっています。
<#-- ピグ画像・ペット画像 -->
<span id="pigg"><img src="${piggImageUrl!'default'?html}"></span>
<span id="piggPet"><img src="${synthesizeImage!'default'?html}"></span>

<#-- 体力ゲージ -->
<div id="piggStamina">
	<p class="time">あと${timeOfMaxStamina!?html}で全回復!</p>
	<dl class="gauge">
	    <dt style="width: ${(currentStamina / maxStamina * 100)?floor}%"></dt>
	    <dd>${currentStamina!?html}/${maxStamina!?html}</dd>
	</dl>
</div>

imgタグにおける使用

最初のピグ画像・ペット画像の部分を見てみます。
<span id="pigg"><img src="${piggImageUrl!'default'?html}"></span>
<span id="piggPet"><img src="${synthesizeImage!'default'?html}"></span>
画像のsrc属性の値を変数で受け取って、各ユーザーに対応する画像を表示しています。
src="${piggImageUrl!'default'?html}"
先程登場したビルトイン"?html"に加えて、"!'default'"という記述があります。この部分ではデフォルト値を設定しています。(省略可能です)
こう書いておくと、万一piggImageUrlの値を正常に受け取れなかった場合、src="default"となります。一部のAndroid端末ではsrc属性が空のimgタグが存在すると画面が正常に動作しないため、デフォルト値の設定が有効です。

数値計算

体力ゲージは、オレンジ色のゲージ部分のwidthを下記のように指定しています。
style="width: ${(currentStamina / maxStamina * 100)?floor}%"
体力ゲージのmax値(maxStamina)と現在の体力値(currentStamina)を受け取って割合を計算し、数値用のビルトイン"?floor"で数値を切り下げてから、オレンジ色の部分の幅を指定しています。


もう1ヶ所、使用例を見てみます。


こちらは「ひろば」(HuggPet内のサークル機能)のメンバー一覧を表示するモジュールです。
ひろばに所属しているユーザーの情報を、所属している人数分、表示しています。

この一覧部分のソースコードは、以下のようになっています。
※装飾のためのclassやidを省くなど、実際のソースコードより簡易化してあります。
<ul class="members">
<#list memberListPager.list as member>
  <li>
    <section>
      <#-- ユーザー画像・ピグ画像 -->
      <div>
        <img src="${member.userImg!'default'?html}">
        <img src="${member.petImg!'default'?html}">
      </div>

      <#-- ユーザー情報 -->
      <div>
      <p>${member.userName!?html}</p>
      <#if member.titleName??>
        <p>称号:${member.titleName!?html}</p>
      <#else>
          <p>称号はありません</p>
      </#if>
      <p>わざの数:
        ${member.normalSkillLearnedCount!?html}/
      ${member.normalSkillTotalCount!?html}</p>
      <#if member.eventSkillLearnedCount != 0>
        <p class="specialSkillCnt">${member.eventSkillLearnedCount!?html}</p>
      </#if>
      </div>
    </section>
  </li>
</#list>
</ul>

制御文の使用

FTLファイルでは、if文やswitch文などの制御文が使えます。例の中では、変数の存在を確かめるためにif文を使っています。
<#if member.titleName??>
	<p>称号:${member.titleName!?html}</p>
<#else>
	<p>称号はありません</p>
</#if>
この<#if hoge??>という書き方は、よく使用します。
変数の後に"??"をつけると、「変数が存在すればtrue」となります。変数が定義されていれば、空の場合でもtrueを返します。この例では、"member.titleName"が存在すれば値が表示され、"member.titleName"が存在しなければ「称号はありません」と表示されます。

因みにこのソースコードには登場しませんが、同じくよく使う記述に
<#if hoge?has_content>
というものがあります。こちらも変数が存在する場合にtrueを返しますが、"??"と異なるのは、変数が空のときはfalseを返すことです。

ループ処理

次に、ユーザー情報をリスト表示している大枠の部分です。
javascriptなどならfor文で実装するところですが、FTLでは
<ul class="members">
	<#list memberListPager.list as member>
		<li>~省略~</li>
	</#list>
</ul>
<#list>を使うことで、受け取ったlistの要素数だけ、ループ処理をします。所属しているユーザーの情報を埋め込んだli要素を、ユーザーの数="memberListPager.list"の要素数分出力してくれるわけです。
listの中の値には、<#list>内のas以降に指定した変数名を使ってアクセスできます。この例の中では、member.○○○という書き方をしています。

その他よく使用する記述

その他、HuggPetのFTLファイル内でよく登場する記述をご紹介しておきます。

<#assign>
変数を定義します。
<#assign hoge = "fuga">
<p>テスト:${hoge?html}</p>
(出力結果) テスト:fuga
といった具合です。

<#compress></#compress>
ホワイトスペースを削除します。ftlソースの一番外側をこれで囲む、というような使い方をしています。

<#include>
ファイルを読み込みます。例えば、共通ヘッダーをheader.ftlというファイル名で作成した場合、各ページでヘッダーを表示したい位置に
<#include "header.ftl">
と記述すればOKです。モジュールごとにファイルを分けて管理することができます。

まとめ

今回ご紹介したのは、ほんの一部分の基礎的な機能です。
突っ込んだ使い方については、こちらをご確認いただければと思います。
FreeMarker Manual

FreeMarkerは日本語のドキュメントが少ないので、本記事が少しでも参考になれば幸いです。

ここまでお読みいただきありがとうございました。
最後になりますが、「あそんで♪HuggPet」もぜひよろしくお願い致します。スマホで可愛いペットたちと触れ合ってみてください!