5.コントローラー
学習目標
@Controllerと@GetMappingで URL のパスとメソッドを結びつけられる- メソッドが返したビュー名と、
templatesフォルダーの HTML ファイルが対応する仕組みを説明できる - 1 つのコントローラーに複数のパスを担当させられる
@RestControllerで、HTML の画面ではなくデータ(JSON など)を返せる
1. @Controller
Section titled “1. @Controller”ブラウザーからリクエストが届くと、Spring Boot は URL に対応するメソッドを呼び出します。このメソッドを持つクラスが コントローラー で、必要な処理を行ったあと、表示する画面を指定します。
画面の HTML はコントローラーには書きません。HTML は src/main/resources/templates に置いた テンプレート ファイルに書き、コントローラーはそのファイルを名前で指定します。
書店のホーム(/)を開くと、システム名を見出しに表示するページが返るところから作ります。完成後のファイル構成は次のとおりです。
Directorybookstore/
Directorysrc/main/java/com/example/bookstore/
- BookstoreApplication.java
- HomeController.java
Directorysrc/main/resources/
Directorytemplates/
- home.html
- about.html
Directorybooks/
- new.html
1-1. テンプレートの作成
Section titled “1-1. テンプレートの作成”コントローラーが返す HTML を、テンプレートとして先に作ります。templates/ の中に home.html を作り、次の内容を書きます。
<!DOCTYPE html><html lang="ja"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Spring Books</title></head><body> <h1>Spring Books</h1></body></html>templates/ 配下のファイルは、ブラウザーから /home.html のような URL で直接開けません。コントローラーが名前で指定したときに限り、Spring Boot が読み込んで HTML をブラウザーに返します。
1-2. コントローラーの宣言
Section titled “1-2. コントローラーの宣言”コントローラーは、クラスに @Controller を付けて宣言します。メソッドには、担当する URL のパスを示す @GetMapping を付けます。
@Controllerpublic class クラス名 { @GetMapping("パス") public String メソッド名() { return "ビュー名"; }}メソッドが返す文字列は ビュー名(view name)と呼ばれます。Spring Boot は、templates/ の中からビュー名と同じ名前の .html ファイルを読み込み、その中身がブラウザーへのレスポンスになります。return "home" なら templates/home.html が読み込まれます。
ホームのパス / を担当する HomeController です。
package com.example.bookstore;
import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.GetMapping;
@Controllerpublic class HomeController { @GetMapping("/") public String home() { return "home"; }}Spring Boot は、起動時に @SpringBootApplication に含まれる @ComponentScan の働きで、@Controller の付いたクラスを見つけ出し、リクエストを受け付けられるよう登録します。
@GetMapping("/") を付けた home メソッドは、/ への GET リクエストが届いたときに呼び出されます。メソッド名は任意で、Spring Boot は @GetMapping の引数からパスを判別します。
home メソッドが返す "home" がビュー名で、templates/home.html を指します。サーバーを起動し直し、ブラウザーで http://localhost:8080/ を開くと、画面に Spring Books と表示されます。
GET 以外の HTTP メソッドにも、それぞれ対応するアノテーションがあります。
| アノテーション | 対応する HTTP メソッド |
|---|---|
@GetMapping | GET(リソースの取得) |
@PostMapping | POST(データの送信) |
@PutMapping | PUT(リソースの更新) |
@DeleteMapping | DELETE(リソースの削除) |
フォームから送信されたデータを @PostMapping で受け取る方法は、@PostMapping によるフォーム受信 で扱います。
1-3. ビュー名とテンプレートの対応
Section titled “1-3. ビュー名とテンプレートの対応”ビュー名と読み込まれるテンプレートファイルの対応は、ビュー名の前に templates/、後ろに .html を付けたパスで決まります。
| メソッドの戻り値 | 読み込まれるテンプレート |
|---|---|
"home" | templates/home.html |
"about" | templates/about.html |
"books/new" | templates/books/new.html |
ビュー名にはサブフォルダーも書け、/ を含めるとフォルダー階層を表します。テンプレートが増えてきたら、関連するファイルをサブフォルダーにまとめます。
1-4. ルーティング
Section titled “1-4. ルーティング”1 つのコントローラーに、@GetMapping を付けたメソッドを複数書くことができます。それぞれのメソッドが、別々のパスを担当します。
HomeController に、サイトの説明を表示する /about と、本の登録フォームを置く /books/new を追加します。先に templates/about.html と templates/books/new.html を作成します。
<!DOCTYPE html><html lang="ja"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>このサイトについて</title></head><body> <h1>このサイトについて</h1></body></html><!DOCTYPE html><html lang="ja"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>本の登録</title></head><body> <h1>本の登録</h1></body></html>HomeController に 2 つのメソッドを加えます。
@Controllerpublic class HomeController { @GetMapping("/") public String home() { return "home"; }
@GetMapping("/about") public String about() { return "about"; }
@GetMapping("/books/new") public String newBook() { return "books/new"; }}/・/about・/books/new の 3 つのパスは、それぞれ別のメソッドに対応します。リクエストのパスを見て、対応するメソッドに振り分けるこの仕組みを ルーティング と呼びます。/books/new のように / を含むパスにも、return "books/new" のようにフォルダー階層を持つビュー名を返せば、templates/books/new.html が読み込まれます。
関連するパスを 1 つのコントローラーにまとめると、画面ごとに別のクラスを作らずに済みます。アプリが大きくなったら、HomeController・BookController のように、画面のまとまりごとにコントローラーを分けるのが一般的です。
2. @RestController
Section titled “2. @RestController”@Controller は、ビュー名に対応するテンプレートから HTML を組み立て、画面として返しました。ブラウザー上で動く JavaScript やスマートフォンアプリは、画面ではなくデータだけを受け取って処理します。プログラムが別のプログラムにデータを提供する仕組みを API(Application Programming Interface)と呼び、データを返すコントローラーには @RestController を使います。書店アプリはブラウザーに画面を返すため本文では @Controller を使い、本節では対比として @RestController を扱います。
2-1. 値の返却
Section titled “2-1. 値の返却”@RestController を付けると、メソッドの戻り値はビュー名ではなく、そのままレスポンスのボディになります。@Controller と違い、テンプレートは探されません。
package com.example.bookstore;
import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;
@RestControllerpublic class ApiController { @GetMapping("/api/hello") public String hello() { return "hello"; }}/api/hello を開くと、templates/ は探されず、hello という文字列がそのままブラウザーに表示されます。
2-2. JSON
Section titled “2-2. JSON”API がやり取りするデータの形式には、JSON(JavaScript Object Notation)が広く使われます。データをテキストで表す形式で、プログラミング言語を問わず読み書きでき、人間も読めます。このため、システム間でデータを受け渡す標準になっています。
JSON は、次の形でデータを表します。
- オブジェクト:
{ "名前": 値, ... }— 名前と値の組 - 配列:
[ 値, 値, ... ]— 値の並び - 値: 文字列(
"こころ")・数値(473)・真偽値(true)など
たとえば 1 冊の本は、次の JSON で表せます。
{ "title": "こころ", "price": 473, "stock": 5}@RestController は、メソッドがオブジェクトを返すと、そのフィールドを「名前: 値」に並べた JSON に自動で変換します。title・price・stock を持つ本のオブジェクトを返せば、上の JSON がそのまま返ります。
3. 発展: REST API
Section titled “3. 発展: REST API”@RestController で作る API は、REST という設計様式に沿って設計するのが一般的です。リソースを URL で表し、操作を HTTP メソッドで表します。