【Spring Boot】@Controllerと@RestControllerの違い

Java

こんにちは、かつコーチです。

前回、Service層・Repository層の役割を整理しました。
今回はいよいよ、リクエストを最初に受け取る「入り口」であるControllerです。
Spring MVCには@Controller@RestControllerという似た名前のアノテーションがあり、初心者がつまずきやすいポイントの一つです。
この記事では、両者の違いと使い分けを、実際に動くコードで確認していきます。

@Controllerと@RestControllerとは?

Controllerの役割

Controllerとは、ブラウザなどから送られてきたリクエストを最初に受け取り、どの処理を実行して、どんな結果を返すかを決める役割のクラスです。
Webアプリを人間の受付に例えるなら、Controllerは「来客の要件を聞いて、担当部署(Service)に取り次ぐ受付係」のような存在です。

@Controllerが返すもの:画面(HTML)

@Controllerは、主に画面(HTML)を返すことを目的としたアノテーションです。
Thymeleafなどのテンプレートエンジンと組み合わせて使われます。

@Controller
public class HelloController {

    @GetMapping("/hello")
    public String hello(Model model) {
        model.addAttribute("message", "こんにちは、かつコーチです。");
        return "hello"; // "hello"という名前のテンプレート(hello.html)を返す
    }
}

このコードでは、メソッドが返す"hello"という文字列は、HTMLの内容そのものではなく、「templates/hello.htmlというテンプレートを表示してください」という画面の名前として解釈されます。

@RestControllerが返すもの:データ(JSON)

一方、@RestControllerは、HTMLではなくデータそのもの(主にJSON)を返すことを目的としたアノテーションです。
スマートフォンアプリのバックエンドや、フロントエンドのJavaScriptから呼び出されるAPIを作る際に使います。

@RestController
public class HelloApiController {

    @GetMapping("/api/hello")
    public Map<String, String> hello() {
        return Map.of("message", "こんにちは、かつコーチです。");
    }
}

このメソッドが返すMapは、画面名としては解釈されず、そのままJSON形式に変換されてレスポンスとして返されます。

{"message": "こんにちは、かつコーチです。"}

内部の仕組みと使い分け

@RestControllerの正体は@Controller + @ResponseBody

実は@RestControllerは、@Controller@ResponseBodyという2つのアノテーションを組み合わせたものです。

// Springのソースコード(簡略化したイメージ)
@Controller
@ResponseBody
public @interface RestController { ... }

@ResponseBodyは、「メソッドの戻り値を画面名としてではなく、レスポンスの中身(データ)として扱ってください」という指示です。
つまり、@Controllerのクラスの各メソッドに@ResponseBodyを1つずつ付けて回るのと、クラスに@RestControllerを1つ付けるのは、基本的に同じ結果になります。

@Controller
public class MixedController {

    @GetMapping("/page")
    public String page() {
        return "page"; // 画面を返す
    }

    @ResponseBody
    @GetMapping("/api/data")
    public Map<String, String> data() {
        return Map.of("key", "value"); // このメソッドだけJSONを返す
    }
}

使い分けの判断軸

用途使うアノテーション返すもの
画面(HTML)を表示するWebアプリ@Controllerテンプレート名(画面)
データをやり取りするREST API@RestControllerJSONなどのデータ
1つのクラスに両方が混在する場合@Controller + 個別に@ResponseBodyメソッドごとに切り替え

最近のWeb開発では、フロントエンド(React・Vueなど)とバックエンドを分離し、バックエンドはAPI専用にする構成も増えています。
その場合はほぼすべてのControllerが@RestControllerになりますが、Thymeleafで画面まで作る学習段階では、両方の使い分けをしっかり理解しておくことが重要です。

つまずきやすい設定・注意点

@RestControllerを使うべき場面で@Controllerを使い、画面が真っ白になる

初心者が最初につまずきやすいのが、JSONを返したいのに@Controllerのまま実装してしまうケースです。

❌ Before
@Controller
public class HelloApiController {

    @GetMapping("/api/hello")
    public String hello() {
        return "こんにちは、かつコーチです。";
    }
}

// エラー
Circular view path [こんにちは、かつコーチです。]:
would dispatch back to the current handler URL...

このコードでは、返した文字列がテンプレート名として解釈されてしまい、「そんな名前のテンプレートは存在しない」というエラーになります。
筆者も最初、テキストだけを返すAPIを作ろうとして@Controllerのまま書いてしまい、このCircular view pathエラーに戸惑った経験があります。
エラーメッセージだけを見ると原因が分かりにくいのですが、「戻り値が画面名として扱われている」ことに気づけば、すぐに解決できます。

✅ After
@RestController
public class HelloApiController {

    @GetMapping("/api/hello")
    public String hello() {
        return "こんにちは、かつコーチです。";
    }
}

@RestControllerに変更するだけで、戻り値がそのままレスポンスの中身として返されるようになります。

応用・一歩先の使い方

1つのアプリケーションの中で、画面を返すControllerとAPIを返すRestControllerを併用することも珍しくありません。
その場合、パッケージをcontroller.webcontroller.apiのように分けておくと、どちらの種類のControllerかがひと目で分かり、保守性が高まります。

com.example.demo.controller/
├── web/
│   └── HelloController.java       // @Controller
└── api/
    └── HelloApiController.java    // @RestController

まとめ

この記事のポイント

  • @Controllerは画面(HTML)を、@RestControllerはデータ(JSON)を返すことを目的とする
  • @RestController@Controller@ResponseBodyを組み合わせたもの
  • JSONを返したいのに@Controllerのままだと、戻り値が画面名として扱われエラーになる
  • 画面用とAPI用でパッケージを分けておくと保守性が上がる

次に読むべき記事

Controllerの種類が分かったら、次はリクエストを実際に処理する「@GetMapping・@PostMappingでリクエストを処理する」で、HTTPメソッドごとの扱い方を見ていきましょう。

タグ: Spring Boot, 初心者向け, フレームワーク基礎

タイトルとURLをコピーしました