Skip to content
Playground

5.コントローラー

学習目標

  • @Controller@GetMapping で URL のパスとメソッドを結びつけられる
  • メソッドが返したビュー名と、templates フォルダーの HTML ファイルが対応する仕組みを説明できる
  • 1 つのコントローラーに複数のパスを担当させられる
  • @RestController で、HTML の画面ではなくデータ(JSON など)を返せる

ブラウザーからリクエストが届くと、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

コントローラーが返す HTML を、テンプレートとして先に作ります。templates/ の中に home.html を作り、次の内容を書きます。

src/main/resources/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 をブラウザーに返します。

コントローラーは、クラスに @Controller を付けて宣言します。メソッドには、担当する URL のパスを示す @GetMapping を付けます。

@Controller
public class クラス名 {
@GetMapping("パス")
public String メソッド名() {
return "ビュー名";
}
}

メソッドが返す文字列は ビュー名(view name)と呼ばれます。Spring Boot は、templates/ の中からビュー名と同じ名前の .html ファイルを読み込み、その中身がブラウザーへのレスポンスになります。return "home" なら templates/home.html が読み込まれます。

ホームのパス / を担当する HomeController です。

src/main/java/com/example/bookstore/HomeController.java
package com.example.bookstore;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public 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 メソッド
@GetMappingGET(リソースの取得)
@PostMappingPOST(データの送信)
@PutMappingPUT(リソースの更新)
@DeleteMappingDELETE(リソースの削除)

フォームから送信されたデータを @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 つのコントローラーに、@GetMapping を付けたメソッドを複数書くことができます。それぞれのメソッドが、別々のパスを担当します。

HomeController に、サイトの説明を表示する /about と、本の登録フォームを置く /books/new を追加します。先に templates/about.htmltemplates/books/new.html を作成します。

templates/about.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>
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>

HomeController に 2 つのメソッドを加えます。

HomeController.java
@Controller
public 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 つのコントローラーにまとめると、画面ごとに別のクラスを作らずに済みます。アプリが大きくなったら、HomeControllerBookController のように、画面のまとまりごとにコントローラーを分けるのが一般的です。

@Controller は、ビュー名に対応するテンプレートから HTML を組み立て、画面として返しました。ブラウザー上で動く JavaScript やスマートフォンアプリは、画面ではなくデータだけを受け取って処理します。プログラムが別のプログラムにデータを提供する仕組みを API(Application Programming Interface)と呼び、データを返すコントローラーには @RestController を使います。書店アプリはブラウザーに画面を返すため本文では @Controller を使い、本節では対比として @RestController を扱います。

@RestController を付けると、メソッドの戻り値はビュー名ではなく、そのままレスポンスのボディになります。@Controller と違い、テンプレートは探されません。

ApiController.java
package com.example.bookstore;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ApiController {
@GetMapping("/api/hello")
public String hello() {
return "hello";
}
}

/api/hello を開くと、templates/ は探されず、hello という文字列がそのままブラウザーに表示されます。

API がやり取りするデータの形式には、JSON(JavaScript Object Notation)が広く使われます。データをテキストで表す形式で、プログラミング言語を問わず読み書きでき、人間も読めます。このため、システム間でデータを受け渡す標準になっています。

JSON は、次の形でデータを表します。

  • オブジェクト: { "名前": 値, ... } — 名前と値の組
  • 配列: [ 値, 値, ... ] — 値の並び
  • : 文字列("こころ")・数値(473)・真偽値(true)など

たとえば 1 冊の本は、次の JSON で表せます。

{
"title": "こころ",
"price": 473,
"stock": 5
}

@RestController は、メソッドがオブジェクトを返すと、そのフィールドを「名前: 値」に並べた JSON に自動で変換します。titlepricestock を持つ本のオブジェクトを返せば、上の JSON がそのまま返ります。

@RestController で作る API は、REST という設計様式に沿って設計するのが一般的です。リソースを URL で表し、操作を HTTP メソッドで表します。