§HTTPルーティング
§組み込み HTTP ルータ
ルータはクライアントから受け取った HTTP リクエストをアクション (コントローラクラス内の static かつ public なメソッド) の呼び出しへ変換するコンポーネントです。
HTTP リクエストは MVC フレームワークにとってイベントであるといえます。このイベントには大きく分けて次の二つの情報が含まれています。
- クエリストリングを含むリクエストパス (例えば、
/clients/1542
や/photos/list
) - HTTP メソッド (GET、POST など)
ルートは conf/routes
ファイルに定義しておくことでコンパイルされます。これは、ルート定義に関するエラーもブラウザで直接的に確認できるということです。
§routesファイルの文法
conf/routes
はルータによって読み込まれる設定ファイルです。このファイルには、アプリケーションが必要とする全てのルートをリストアップします。それぞれのルートは、HTTP メソッドと URI パターン、そしてそれらに割り当てられたアクションメソッドの呼び出しで表します。
実際のルート定義を見てみましょう。
GET /clients/:id controllers.Clients.show(id: Long)
アクション呼び出しでは、Scala のように引数名の後に型を指定する事に注意して下さい。
それぞれのルートでは、先頭に HTTP メソッド、その後に URI パターンが続きます。最後がアクション呼び出しの定義です。
#
の文字を使って、routes ファイルにコメントを残すこともできます。
# Display a client.
GET /clients/:id controllers.Clients.show(id: Long)
§HTTPメソッド
HTTP メソッドには、HTTP がサポートするあらゆるメソッド(GET
、POST
、PUT
、DELETE
、HEAD
)が指定できます。
§URIパターン
URI パターンはルートのリクエストパスの定義です。リクエストパスの一部を動的にすることができます。
§静的パス
例えば、リクエストを GET /clients/all
に完全一致させたいときは、次のように定義できます。
GET /clients controllers.Clients.list()
§動的パート
しかし、URL からクライアント ID を取得するような場合には、動的パートを追加する必要があります。
GET /clients/:id controllers.Clients.show(id: Long)
1 つの URI パターンには、2 つ以上の動的パートを含められます
動的パートのデフォルトのマッチ規則は正規表現でいうと [^/]+
です。したがって、:id
という動的パートはちょうど一つの URI パートにマッチします。
§複数の/
をまたぐ動的パート
動的パートを使って、URI パスの /
で分割された複数のセグメントをまとめてキャプチャしたいときは、.*
という正規表現に対応する *id
という文法が使えます。
GET /files/*name controllers.Application.download(name)
これで、GET /files/images/logo.png
というリクエストに対して、動的パート name
に images/logo.png
という値をキャプチャさせることができます。
§動的パートで独自の正規表現を使う
動的パートに独自の正規表現を使わせたい場合は、$id<regex>
という文法を利用します。
GET /clients/$id<[0-9]+> controllers.Clients.show(id: Long)
§アクションジェネレータメソッドの呼び出し
ルート定義の最後のパートは、アクションの呼び出しです。このパートでは、アクションメソッド呼び出しを定義する必要があります。
メソッドが一つも引数を取らない場合、単にメソッドの完全修飾名を指定します。
GET / controllers.Application.homePage()
アクションメソッドが引数を取る場合、対応する引数はリクエスト URI のパスまたはクエリストリングから抽出されます。
パスから抽出するためには、
# Extract the page parameter from the path.
# i.e. http://myserver.com/index
GET /:page controllers.Application.show(page)
また、クエリストリングから抽出するためには、
# Extract the page parameter from the query string.
# i.e. http://myserver.com/?page=index
GET / controllers.Application.show(page)
のように定義します。
このルートに対応する controllers.Application
コントローラの show
メソッドの定義は次のようになります。
public static Result show(String page) {
String content = Page.getContentOf(page);
response().setContentType("text/html");
return ok(content);
}
§引数の型
String
型の引数の場合、型の記述はオプションです。リクエストパラメータを特定の Scala 型に変換したいときは、明示的に型を追記することができます。
GET /client/:id controllers.Clients.show(id: Long)
このルートに対応するコントローラのアクションメソッドの引数には同じ型を使用します。
public static Result show(Long id) {
Client client = Client.findById(id);
return ok(views.html.Client.show(client));
}
ノート: 引数の型は後置形式で指定されます。またジェネリックスの型は Java の
<>
構文の代わりに[]
で指定されます。例えば、 Java でのList<String>
はList[String]
になります。
§引数に定数を渡す
アクションメソッドの引数に定数を渡したいときは、次のように記述します。
# Extract the page parameter from the path, or fix the value for /
GET / controllers.Application.show(page = "home")
GET /:page controllers.Application.show(page)
§デフォルト引数
受け取ったリクエストに値がないとき、代わりにデフォルト値を渡すこともできます。
# Pagination links, like /clients?page=3
GET /clients controllers.Clients.list(page: Integer ?= 1)
§ルートの優先度
リクエストに複数のルートがマッチしてしまうことがあります。そのような競合が発生した場合は、先に宣言された方のルートが優先されます。
§リバースルーティング
Java コード中で URL を生成するためにルータを使うことができます。これにより、URI パターンの定義をただ一つの設定ファイルに集約することができ、アプリケーションをリファクタリングする際の間違いを減らすことができます。
ルータは、routes ファイルから利用された全てのコントローラについて、routes
パッケージ以下に リバースコントローラ
を生成します。リバースコントローラは元になったコントローラと同じシグネチャで、play.mvc.Result
の代わりに play.mvc.Call
を返すようなメソッドを持っています。
play.mvc.Call
は HTTP 呼び出しを表していて、HTTP メソッドと URL の両方の情報を持っています。
例えば、次のようなコントローラを作成したとします。
package controllers;
import play.*;
import play.mvc.*;
public class Application extends Controller {
public static Result hello(String name) {
return ok("Hello " + name + "!");
}
}
そして、このコントローラを conf/routes
で次のようにマッピングしたとします。
# Hello action
GET /hello/:name controllers.Application.hello(name)
このとき、controllers.routes.Application
というリバースコントローラを利用することで、hello
というアクションメソッドの URL を逆引きすることができます。
// Redirect to /hello/Bob
public static Result index() {
return redirect(controllers.routes.Application.hello("Bob"));
}
§インポート
もし controller.Application
を毎回書く事に疲れたら、デフォルトのインポートを定義することができます。
val main = PlayProject(…).settings(
routesImport += "controller._"
)
次ページ: レスポンスの変更