カテゴリ: Play Framework 更新日: 2026/02/02

Play Frameworkのビューを共通化!テンプレート間のインクルード方法を徹底解説

テンプレート間のインクルード方法
テンプレート間のインクルード方法

先生と生徒の会話形式で理解しよう

生徒

「先生、Webサイトを作っていると、ヘッダーやフッターなど、どのページでも同じ内容を書く場所がありますよね。これって、ページを増やすたびに全部のファイルにコピーしないといけないんですか?」

先生

「いいえ、そんなことはありませんよ。Play FrameworkのビューエンジンであるTwirl(トワール)には、他のテンプレートファイルを読み込む『インクルード』という仕組みがあるんです。」

生徒

「インクルードを使えば、一箇所直すだけで全部のページが更新されるようになるんですか?」

先生

「その通りです!開発効率も上がるし、ミスも減らせます。それでは、具体的な使い方を見ていきましょう!」

1. テンプレートのインクルードとは?

1. テンプレートのインクルードとは?
1. テンプレートのインクルードとは?

Webアプリケーションを開発する際、サイト全体の共通デザイン(ヘッダー、ナビゲーションバー、フッターなど)を複数の画面で共有したい場面が必ず出てきます。 Play FrameworkのTwirlテンプレートでは、あるテンプレートの中から別のテンプレートを呼び出すことができます。これを「インクルード」や「テンプレートの再利用」と呼びます。

たとえば、header.scala.html という部品を一つ作っておけば、トップページでもお問い合わせページでも、一行書くだけでその部品を表示させることが可能です。 プログラミングの世界にはDRY(Don't Repeat Yourself)という「同じことを繰り返さない」という重要な原則がありますが、インクルードはこの原則を守るための強力な武器になります。

2. インクルードの基本操作

2. インクルードの基本操作
2. インクルードの基本操作

Twirlでのインクルードは、Javaのメソッドを呼び出すのと同じ感覚で行えます。 読み込みたいテンプレートファイルを @views.html.ファイル名() と記述するだけです。

たとえば、app/views/common/footer.scala.html というファイルがある場合、メインのページからは以下のように呼び出します。


<!DOCTYPE html>
<html>
    <body>
        <h1>メインコンテンツ</h1>
        <p>ここにページの内容を書きます。</p>

        @views.html.common.footer()
    </body>
</html>

このように記述するだけで、コンパイル時に指定した場所の内容がガッチャンコと結合され、一つのHTMLとしてブラウザに表示されます。

3. 部品用テンプレートの作り方

3. 部品用テンプレートの作り方
3. 部品用テンプレートの作り方

読み込まれる側のテンプレート(部品)も、通常のテンプレートと作り方は同じです。 特別な設定は不要ですが、部品であることを分かりやすくするためにフォルダを分けたり(例:tagscommonフォルダ)、名前を工夫したりするのが一般的です。


<hr>
<footer>
    <p>&copy; 2026 Play Framework 学習ブログ. All Rights Reserved.</p>
</footer>

このように、部品側は <html><body> タグを含まない、断片的なHTMLとして作成します。

4. 引数を持ったテンプレートのインクルード

4. 引数を持ったテンプレートのインクルード
4. 引数を持ったテンプレートのインクルード

インクルードの素晴らしい点は、ただ静的なHTMLを表示するだけでなく、呼び出し元からデータ(変数)を渡せることです。 これにより、「見た目は同じだけど、表示される文字が違うボタン」のような部品を作ることができます。

部品側の先頭で @(title: String) のように受け取る引数を宣言しておけば、呼び出す側で @views.html.common.header("マイページ") のように値を渡せます。


@(label: String, color: String)

<button style="background-color: @color; color: white; padding: 10px;">
    @label
</button>

5. コントローラからの呼び出しとデータの流れ

5. コントローラからの呼び出しとデータの流れ
5. コントローラからの呼び出しとデータの流れ

複数のテンプレートを組み合わせる場合でも、Javaのコントローラ側が意識するのは「一番親となるテンプレート」だけです。 コントローラから親テンプレートにデータを渡し、親から子(部品)へとデータをリレー形式で渡していくのがPlay Frameworkの標準的な流れです。


package controllers;

import play.mvc.*;
import views.html.*;

public class MyPageController extends Controller {
    public Result index() {
        String pageTitle = "ダッシュボード";
        // 親テンプレート(index.scala.html)を呼び出す
        return ok(views.html.index.render(pageTitle));
    }
}

この pageTitle という変数は、まず index.scala.html に届き、そこからインクルードされたヘッダーなどの部品へと引き継がれていきます。

6. フォルダ階層がある場合の指定方法

6. フォルダ階層がある場合の指定方法
6. フォルダ階層がある場合の指定方法

プロジェクトが大きくなると、ビューファイルが増えて管理が大変になります。 その場合、フォルダ(パッケージ)を分けて整理しますが、インクルード時の記述もそれに対応させる必要があります。

フォルダ区切りは /(スラッシュ)ではなく .(ドット)で表現します。 もし app/views/admin/users/list.scala.html を呼び出すなら、@views.html.admin.users.list() となります。 これはJavaのパッケージ指定と同じルールなので、Javaに慣れている人なら直感的に理解できるはずです。

7. ループ内でのインクルード活用法

7. ループ内でのインクルード活用法
7. ループ内でのインクルード活用法

以前学習した @for 文とインクルードを組み合わせることで、リスト表示などを非常に綺麗に記述できます。 たとえば、商品リストを表示する際、商品一つの表示カードを別のテンプレートとして切り出しておくと便利です。


@(productList: List[models.Product])

<div class="row">
    @for(product <- productList) {
        <div class="col-md-4">
            @views.html.components.productCard(product)
        </div>
    }
</div>

このように、複雑なHTML構造を部品化して @for 文の中をスッキリさせることで、コードの読みやすさが劇的に向上します。

8. インクルードを使うメリット:保守性の向上

8. インクルードを使うメリット:保守性の向上
8. インクルードを使うメリット:保守性の向上

インクルードを適切に使う最大のメリットは保守性(メンテナンスのしやすさ)です。 たとえば、サイトのロゴ画像を変更することになった場合、インクルードを使っていなければ全てのHTMLファイルを修正しなければなりません。

しかし、ヘッダーを部品化して共通化していれば、header.scala.html を一箇所書き換えるだけで、サイト全体のロゴが一瞬で切り替わります。 大規模なシステム開発になればなるほど、この「変更のしやすさ」が開発コストに大きく影響してくるのです。

9. インクルードとレイアウト機能の違い

9. インクルードとレイアウト機能の違い
9. インクルードとレイアウト機能の違い

Play Frameworkにはインクルードの他に「レイアウト」という機能もあります。 インクルードは「部品を呼び出す」のに対し、レイアウトは「全体の枠組みの中に中身を流し込む」という逆の発想です。

初心者のうちは、まずはインクルードを使って「共通する部品を切り出す」感覚を身につけるのがおすすめです。 慣れてきたら、サイト全体の枠を定義するレイアウト機能(main.scala.html など)と組み合わせて、より高度なテンプレート設計に挑戦してみましょう。

10. インクルード時の注意点:循環参照

10. インクルード時の注意点:循環参照
10. インクルード時の注意点:循環参照

最後に一つだけ注意点があります。それは循環参照(じゅんかんさんしょう)です。 テンプレートAがテンプレートBをインクルードし、さらにテンプレートBがテンプレートAをインクルードする、といった状態です。

これをやってしまうと、合わせ鏡のように無限に読み込みが繰り返され、エラーが発生してしまいます。 部品を作る際は、「どのテンプレートが親で、どのテンプレートが子なのか」という階層構造を意識して設計することが、トラブルを防ぐコツです。

カテゴリの一覧へ
新着記事
New1
Jakarta EE
Jakarta EEとクラウドネイティブ開発の相性とは?初心者向けにわかりやすく解説
New2
Jakarta EE
JakartaEE JSPのリクエスト属性とスコープの基本を徹底解説!初心者向け入門ガイド
New3
Play Framework
Play Frameworkのビューテストを徹底解説!Twirlテンプレートの品質を高める方法
New4
Jakarta EE
JakartaEE フィルタで認証と認可を実装する方法を初心者向けに解説!サーブレットのセキュリティ入門
人気記事
No.1
Java&Spring記事人気No1
Jakarta EE
Jakarta EEとSpringの比較|どちらを選ぶべきか?初心者向けに徹底解説!
No.2
Java&Spring記事人気No2
Play Framework
Play Frameworkのビューを共通化!テンプレート間のインクルード方法を徹底解説
No.3
Java&Spring記事人気No3
Play Framework
Play Frameworkプロジェクト作成直後にやるべき初期設定ガイド!初心者でも安心
No.4
Java&Spring記事人気No4
Jakarta EE
Jakarta サーブレットのHttpServletRequestを徹底解説!初心者でもわかる基本操作と使い方
No.5
Java&Spring記事人気No5
Play Framework
Play Frameworkで多言語対応(i18n)を徹底解説!Twirlテンプレートでの使い方
No.6
Java&Spring記事人気No6
Play Framework
Play FrameworkでCSSやJavaScriptを読み込む方法を徹底解説!静的リソースの組み込みガイド
No.7
Java&Spring記事人気No7
Jakarta EE
Jakarta EEとJava EEアプリの互換性を完全解説!移行で困らないための基礎知識
No.8
Java&Spring記事人気No8
Jakarta EE
Jakarta EEの標準仕様とAPI一覧を完全解説!初心者でもわかるエンタープライズJavaの基本