ドキュメント

§サブプロジェクトでの作業

複雑なプロジェクトは、必ずしも単一のPlayアプリケーションで構成されているとは限りません。大規模なプロジェクトを複数の小さなアプリケーションに分割したり、Playアプリケーションとは関係のない標準のJavaまたはScalaライブラリにロジックを抽出したりすることができます。

マルチプロジェクトビルドに関するsbtドキュメントを読むと役立ちます。サブプロジェクトは親プロジェクトのビルドファイルで完全に定義できますが、ここではサブプロジェクトの設定を独自のビルドファイルに入れます。

§シンプルなライブラリサブプロジェクトの追加

アプリケーションがシンプルなライブラリプロジェクトに依存するようにすることができます。`build.sbt`ファイルに別のsbtプロジェクト定義を追加するだけです。

name := "my-first-application"

version := "1.0"

lazy val myFirstApplication = (project in file("."))
    .enablePlugins(PlayScala)
    .aggregate(myLibrary)
    .dependsOn(myLibrary)

lazy val myLibrary = project

最後の行の小文字の`project`は、Scalaマクロであり、プロジェクトの名前とフォルダを決定するために、それが割り当てられているvalの名前を使用します。

`myFirstApplication`プロジェクトは、ベースプロジェクトを宣言します。サブプロジェクトがない場合は、これはすでに暗黙のうちに示されています。ただし、サブプロジェクトを宣言するときは、ベースプロジェクトで実行した場合にサブプロジェクトでコンパイル/テストなどの実行を確実に集約し、サブプロジェクトをメインプロジェクトのクラスパスに追加するために、それを宣言することが通常必要です。

上記の例では、アプリケーションの`myLibrary`フォルダにサブプロジェクトを定義しています。このサブプロジェクトは、デフォルトレイアウトを使用する標準のsbtプロジェクトです。

myProject
 └ build.sbt
 └ app
 └ conf
 └ public
 └ myLibrary
   └ build.sbt
   └ src
     └ main
       └ java
       └ scala

`myLibrary`には独自の`build.sbt`ファイルがあり、ここで独自の設定や依存関係などを宣言できます。

ビルドでサブプロジェクトが有効になっている場合は、このプロジェクトに焦点を当てて、個別にコンパイル、テスト、または実行できます。Playコンソールプロンプトで`projects`コマンドを使用すると、すべてのプロジェクトが表示されます。

[my-first-application] $ projects
[info] In file:/Volumes/Data/gbo/myFirstApp/
[info] 	 * my-first-application
[info] 	   my-library

デフォルトのプロジェクトは、変数名がアルファベット順で最初にくるものです。変数名をaaaMainにすると、メインプロジェクトにすることができます。現在のプロジェクトを変更するには、`project`コマンドを使用します。

[my-first-application] $ project my-library
[info] Set current project to my-library
>

開発モードでPlayアプリケーションを実行すると、依存プロジェクトは自動的に再コンパイルされ、コンパイルできないものがある場合は、ブラウザに結果が表示されます。

§共通の変数とコードの共有

サブプロジェクトとルートプロジェクトで共通の設定またはコードを共有する場合は、ルートプロジェクトの`project`ディレクトリにあるScalaファイルに配置できます。たとえば、`project/Common.scala`に次の内容がある場合があります。

import sbt._
import Keys._

object Common {
  val settings: Seq[Setting[_]] = Seq(
    organization := "com.example",
    version := "1.2.3-SNAPSHOT"
  )

  val fooDependency = "com.foo" %% "foo" % "2.4"
}

次に、各`build.sbt`ファイルで、ファイルで宣言されたものを参照できます。

name := "my-sub-module"

Common.settings

libraryDependencies += Common.fooDependency

注意すべきことの1つは、Playプロジェクトと非Playプロジェクトが混在している場合、Play設定を明示的に共有する必要がある場合があることです。たとえば、すべてのPlayプロジェクトで`InjectedRoutesGenerator`とspecs2を共有することが考えられます。

object Common {

  val playSettings = settings ++ Seq(
    routesGenerator := InjectedRoutesGenerator,
    libraryDependencies += specs2 % Test,
    resolvers += Resolver.ApacheMavenSnapshotsRepo // contains pekko(-http) snapshots
  )
}

また、サブプロジェクトの`build.sbt`ファイルには、次の内容が含まれます。

Common.playSettings

§Webアプリケーションをいくつかのパーツに分割する

Playアプリケーションは、デフォルト構成を持つ標準のsbtプロジェクトにすぎないため、別のPlayアプリケーションに依存できます。対応する`build.sbt`ファイルで、プロジェクトがJavaプロジェクトかScalaプロジェクトかに応じて、`PlayJava`または`PlayScala`プラグインを追加することにより、サブモジュールをPlayアプリケーションにすることができます。

注: 名前の衝突を避けるため、サブプロジェクトのAssetsコントローラを含むコントローラがメインプロジェクトとは異なる名前空間を使用していることを確認してください。たとえば、`admin`モジュールのコントローラは、`admin.MyController`の完全修飾パッケージ名を持つ必要があります。

§ルートファイルの分割

ルートファイルをより小さな部分に分割することもできます。これは、堅牢で再利用可能なマルチモジュールPlayアプリケーションを作成する場合に非常に便利な機能です。

§次のビルド構成を検討してください

build.sbt:

name := "myproject"

lazy val admin = (project in file("modules/admin")).enablePlugins(PlayScala)

lazy val main = (project in file("."))
    .enablePlugins(PlayScala).dependsOn(admin).aggregate(admin)

modules/admin/build.sbt

name := "myadmin"

libraryDependencies ++= Seq(
  "com.mysql" % "mysql-connector-j" % "8.0.33",
  jdbc,
  anorm
)

§プロジェクト構造

build.sbt
app
  └ controllers
  └ models
  └ views
conf
  └ application.conf
  └ routes
modules
  └ admin
    └ build.sbt
    └ conf
      └ admin.routes
    └ app
      └ controllers
      └ models
      └ views
project
  └ build.properties
  └ plugins.sbt

注: 構成ファイルとルートファイルの名前は、プロジェクト構造全体で一意である必要があります。特に、`application.conf`ファイルは1つだけ、`routes`ファイルも1つだけである必要があります。サブプロジェクトで追加のルートまたは構成を定義するには、サブプロジェクト固有の名前を使用します。たとえば、`admin`のルートファイルは`admin.routes`と呼ばれます。サブプロジェクトの開発モードで特定の設定セットを使用するには、これらの設定をビルドファイルに入れるとさらに良いでしょう。たとえば、`PlayKeys.devSettings += ("play.http.router", "admin.Routes")`のようにします。

conf/routes:

GET /index                  controllers.HomeController.index()

->  /admin admin.Routes

GET     /assets/*file       controllers.Assets.at(path="/public", file)

modules/admin/conf/admin.routes:

GET /index                  controllers.admin.HomeController.index()

GET /assets/*file           controllers.Assets.at(path="/public/lib/myadmin", file)

注: リソースは一意のクラスローダーから提供されるため、リソースパスはプロジェクトクラスパスルートからの相対パスである必要があります。
サブプロジェクトのリソースは`target/web/public/main/lib/{module-name}`に生成されるため、`play.api.Application#resources(uri)`メソッドを使用すると、リソースは`/public/lib/{module-name}`からアクセスできます。これは、`Assets.at`メソッドが行うことです。

§アセットとコントローラクラスはすべて`controllers.admin`パッケージで定義する必要があります

Java
package controllers.admin;

import controllers.AssetsMetadata;
import javax.inject.Inject;
import play.api.Environment;
import play.api.http.HttpErrorHandler;
import play.api.mvc.*;

public class Assets extends controllers.Assets {

  @Inject
  public Assets(HttpErrorHandler errorHandler, AssetsMetadata meta, Environment env) {
    super(errorHandler, meta, env);
  }

  public Action<AnyContent> at(String path, String file) {
    boolean aggressiveCaching = true;
    return super.at(path, file, aggressiveCaching);
  }
}
Scala
import javax.inject._

import play.api.http.HttpErrorHandler
import play.api.Environment

class Assets @Inject() (
    errorHandler: HttpErrorHandler,
    assetsMetadata: controllers.AssetsMetadata,
    environment: Environment
) extends controllers.AssetsBuilder(errorHandler, assetsMetadata, environment)

コントローラ

Java
/*
 * Copyright (C) from 2022 The Play Framework Contributors <https://github.com/playframework>, 2011-2021 Lightbend Inc. <https://www.lightbend.com>
 */

package controllers.admin;

import play.mvc.Controller;
import play.mvc.Result;

public class HomeController extends Controller {
  public Result index() {
    return ok("admin");
  }
}
Scala
package controllers.admin

import javax.inject.Inject

import play.api.mvc._

class HomeController @Inject() (val controllerComponents: ControllerComponents) extends BaseController {
  def index: Action[AnyContent] = Action { implicit request => Ok("admin") }
}

§`admin`でのリバースルーティング

通常のコントローラ呼び出しの場合

controllers.admin.routes.HomeController.index

`Assets`の場合

controllers.admin.routes.Assets.at("...")

§ブラウザ経由

http://localhost:9000/index

トリガー

controllers.HomeController.index

および

http://localhost:9000/admin/index

トリガー

controllers.admin.HomeController.index

次へ: リバースルーティングのアグリゲーション


このドキュメントにエラーを見つけましたか?このページのソースコードはこちらにあります。ドキュメントガイドラインを読んだら、遠慮なくプルリクエストを送信してください。質問や共有するアドバイスがありますか?コミュニティフォーラムにアクセスして、コミュニティとの会話を始めてください。