Velocityでテンプレートを継承する方法
VelocityでDjangoのテンプレートのように基底のテンプレートをextendするための方法。
継承ができると何がいいか?
なぜそれほどうらやましいのか?
1. 基本となるレイアウトを1つのファイルで記述し、
変更が必要な部分のみ別のテンプレートに記述できる。
2. 基本レイアウトの変更可能部分についても、デフォルトの記述が可能。
3. 階層的に複数のレイアウトを継承できる(Aを継承したBを継承したCを・・・)
4. したがって、継承した側のテンプレートでは「本当に変更が必要な部分のみ」
記述すれば良い。
重要なのは2と3。
デフォルト記述の例:
例えばWebサイトで他の基本的なレイアウトは同じだがメニューだけが違うページが複数あるような場合を考える。
VelocityLayoutServletであれば、メニューだけが違う基本レイアウトテンプレートをそれぞれ用意するか、もしくはマクロなどでメニューを動的に変更できるよう工夫する必要がある。
上記の継承が使えた場合は、よく使われるメニューをデフォルトとして記述した基本レイアウトを1つ用意し、異なるメニューが必要な場合のみ拡張先のテンプレートで記述すればよい。
階層的な継承の例:
上の例であるメニューの中に、さらに特定のレイアウトが共通する複数のページを作る場合を考える。
VelocityLayoutServletであれば、・・・もう考えるのいやだ・・・な・・・となる。
継承が使える場合、前の基本レイアウトを継承した基本レイアウトを作る。簡単!
Velocityでテンプレート継承
いくつか方法はあると思うが、ユーザディレクティブを利用する方法を採用した。
velocity toolsではなく、velocity自体に継承機能を追加するため、どこででも利用できるのが利点。
今回、ユーザディレクティブに追加したのは下記の2つ。
# extends('継承元ファイル') # block('ブロック名')
手順1:
ディレクティブの実装クラスをダウンロードし、適切な場所に追加する。
velocity-template-extends.zip
手順2:
velocity.propertiesに下記のユーザディレクティブ設定を追加する。
#------------------------------- # USER DIRECTIVE #------------------------------- userdirective=org.apache.velocity.runtime.directive.Extends userdirective=org.apache.velocity.runtime.directive.ExtendBlock
以上、終了。
使用方法
extendsディレクティブ
extendsはparseディレクティブの変形で、extends〜endまでの部分をパースしてから継承元ファイルをパースするディレクティブ。
A.vm:
#extends('B.vm') A特有の内容をここに(普通はblockディレクティブ以外を書くことはない) #end
B.vm:
Bの内容
A.vmのパース結果:
A特有の内容をここに(普通はblockディレクティブ以外を書くことはない) Bの内容
blockディレクティブ
blockはテンプレートの「部分」を定義するディレクティブで、extendsの範囲外にある場合のみパース結果を書き出す。
同名の「部分」が複数ある場合は、常に最初に定義された「部分」が後から出てきた「部分」を上書きする。
1.vm:
#block('X') 最初に定義したXブロック #end #block('X') 次に定義したXブロック #end
1.vmのパース結果:
最初に定義したXブロック
2.vm:
#extends('3.vm') #block('X') 最初に定義したXブロック #end
3.vm:
基本テンプレートではXブロックを定義していない
2.vmのパース結果:
基本テンプレートではXブロックを定義していない
4.vm:
#extends('5.vm') #block('X') 最初に定義したXブロック #end
5.vm:
#block('X') ここでXブロックを定義 #end
5.vmのパース結果:
最初に定義したXブロック
継承の例
basic_layout.vm:
基本レイアウトをここに。 #block('menu') デフォルトのメニュー #end #block('contents') デフォルトの内容があれば、ここに #end
pageA.vm
#extends('basic_layout.vm') #block('contents') 内容だけ変更 #end #end
pageB.vm
#extends('basic_layout.vm') #block('contents') 独自の内容 #end #block('menu') メニューも変える。後ろで定義しても、最終的にはextendsの外での並び順になる。 #end #end
pageAのパース結果:
基本レイアウトをここに。 デフォルトのメニュー 内容だけ変更
pageBのパース結果:
基本レイアウトをここに。 メニューも変える。後ろで定義しても、最終的にはextendsの外での並び順になる。 独自の内容