Java
Velocity

Apache Velocity 基礎知識まとめ

More than 3 years have passed since last update.

社内で簡易的なメモを作ったのでそのまま転載

基本的な情報

バージョンによる動作差異がありますが、以下が非常に参考になります
http://www.jajakarta.org/velocity/velocity-1.4/docs-ja/user-guide.html

以下は、↑のリンクから特に特徴的なものを抜粋したものです。

Getterの省略

Velocityテンプレート上では、getterメソッドをpublicフィールドのように利用できます。

例:

${user.userId}
↓

user → Userクラスのインスタンスの場合、user.getUserId() と同等です。

{} と !

  • {} : 変数がどこからどこまでかを表します

    たとえば $hoge という変数に "あいうえお" という値が入っていたとして、
    "あいうえおaiueo" と出力したい場合に、
    $hogeaiueo と記載してしまうと、変数 $hoge ではなく $hogeaiueo という変数が参照されます。

    これを避けるために ${hoge}aiueo とどこまでが変数かマークします。

  • ! : 変数が空の場合の出力制御

    変数が未定義やnullの場合に出力を抑制します。
    $hoge が未定義の場合に出力した場合に以下のような差異があります

    • ${hoge} または $hoge"$hoge" という文字列が出力
    • $!{hoge} または $!hoge … 何も出力されない

WEBで利用する場合

様々なWEBフレームワークと併せて利用することもあるかと思います。
その場合、velocity-tools というものを利用することになります。
https://velocity.apache.org/tools/devel/

中でも、velocity-struts を利用することで、
各スコープへの参照が自動化されます。

例:

  1. toolbox.xmlに定義されているか?
  2. 各サーブレットクラスのインスタンスか?
    • $request
    • $session
    • $application
  3. ローカル変数が定義されているか?
  4. requestスコープにattributeが存在するか?
  5. sessionスコープにattributeが存在するか?
  6. applicationスコープにattributeが存在するか?

「これなんで実行できてるんだろ・・・?」
みたいに思った場合は、toolbox.xmlに定義されてることが多いかもしれません。

マクロ

velocity-macro.vmというファイルに定義可能で、
view上で頻繁に登場する似た処理を関数っぽく作成しておくことができます。

velocityにはparse機能(他vmファイルを利用する機能)がありますが、
こちらはマクロと違い引数を渡すことができません。

感覚的には、

  • よりロジック的なもの(if/foreachなどを使う)はマクロ
  • HTMLの部品化(metaタグとか)はparse

かな〜と思います。

velocityでちゃんと表示されない!!

90%が基本的なミスな気がする。(他の要因だったらすいません・・・)

例:
form.content.userId で何回やっても取得できない

確認すること
* form はちゃんと値が入っているか?
* form に該当するクラスに getContent メソッド(引数無し)が存在するか?
* content に該当するクラスに getUserId メソッド(引数無し)が存在するか?

HTMLエスケープ

ReferenceInsertionEventHandlerを利用することで、
すべての値について表示前に割り込ませることが可能。

こちらが参考になりました。
http://blog.physalis.net/2013/05/01/velocity-escape.html

なお上記参考サイトの場合、エスケープを回避させたい場合に
変数名末尾に特定文字列(NoEscape)を付与した場合はエスケープさせないようにしています。

このままでももちろん大丈夫ですが、
あとでパっと見たときになんとなくわかりにくくなるので、
velocity-toolbox経由で呼べる関数に、何もしないダミー関数を用意しておき、
その関数でラップされている場合には回避するようにしたほうが個人的には好みです。

public String noescape(String org) {
  // エスケープ回避用のダミー関数。
  // 詳細はReferenceInsertionEventHandlerの実装クラスを参照
  return org;
}
${utils.noescape(hoge)}

enumを呼びたい

FieldMethodizerで利用できなくもないです。
なんとなく強引な方法な気もするので、自己責任で。。。

public enum Hoge {
  PIYO,
  FUGA;
}
request.setAttribute("hoge", new FieldMethodizer(Hoge.class.getCanonicalName()));
${hoge.PIYO.name()}