@RestControllerとは?画面ではなくデータを返す仕組み
新人
「先輩、SpringでWebアプリを作っていると、@RestControllerっていうアノテーションを見かけるんですが、あれって何なんですか?」
先輩
「お、いいところに気づいたね。@RestControllerは、HTMLの画面じゃなくてデータを直接返すためのアノテーションなんだよ。」
新人
「えっ?普通は画面が表示されるんじゃないんですか?」
先輩
「そう、普通の@ControllerだとHTMLのテンプレートが表示されるけど、@RestControllerはJSONや文字列を直接レスポンスとして返すことができるんだ。」
新人
「じゃあ、それぞれの違いや使い方を詳しく知りたいです!」
先輩
「よし、それじゃあ今回は@RestControllerと@Controllerの違いや、Springでどのように使われているのかをしっかり学んでいこう。」
1. @RestControllerとは?画面ではなくデータを返す仕組み
Springでは、Webアプリケーションのコントローラを作成する際に、@Controllerというアノテーションをよく使います。しかし、近年ではREST APIを使った開発が主流となっており、HTML画面ではなくJSON形式のデータを直接レスポンスとして返すケースが増えています。
そこで登場するのが@RestControllerです。これは、Springにおいてデータ中心のAPI開発を行う際に使われるアノテーションで、内部的には@Controllerと@ResponseBodyを組み合わせたものです。
ただし、本記事ではあくまで@Controller構成で解説を行い、@RestControllerは参考情報として扱います。初心者がまず理解すべきなのは、レスポンスとしてデータを返す仕組みの基本です。
以下は、Springの@Controllerを使ってデータを返すシンプルなサンプルです。
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class HelloController {
@GetMapping("/hello")
@ResponseBody
public String sayHello() {
return "こんにちは、REST APIの世界へようこそ!";
}
}
このコードでは、/helloというURLにGETリクエストを送ると、「こんにちは、REST APIの世界へようこそ!」という文字列がそのままHTTPレスポンスとして返されます。
@ResponseBodyを付けることで、SpringはHTMLテンプレートを探すのではなく、メソッドの戻り値をそのままレスポンスとして返すようになります。これが@RestControllerの基本的な動作のひとつです。
2. HTMLを返す@Controllerとの違い
Springでは、@Controllerを使うと通常はHTMLファイルを返す仕組みになっています。たとえば、Thymeleafなどのテンプレートエンジンを使えば、ビューを表示する形のWebアプリケーションを作成できます。
しかし、REST APIを開発する際には、画面表示ではなく、文字列やJSON形式のデータを返す必要があります。そのため、HTMLを返す方法とデータを返す方法を明確に区別する必要があります。
以下は、HTMLテンプレートを返す従来の@Controllerの例です。
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class PageController {
@GetMapping("/page")
public String showPage() {
return "welcome";
}
}
この例では、/pageにアクセスすると、resources/templates/welcome.htmlというHTMLファイルが表示されます。これは、Spring Bootとテンプレートエンジンを使った典型的な画面表示の方法です。
一方で、@ResponseBodyを使えば、同じ@Controllerでもレスポンスとしてデータを返すことができます。次の例をご覧ください。
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class DataController {
@GetMapping("/data")
@ResponseBody
public String sendData() {
return "これはHTMLではなく、テキストデータです。";
}
}
この場合、画面ではなく「これはHTMLではなく、テキストデータです。」という文字列が直接HTTPレスポンスとして返されます。REST APIとしての役割を持つこうしたレスポンスは、画面表示ではなくフロントエンドアプリケーションなどに向けてデータを返すために使われます。
つまり、HTMLを返すのが従来の@Controllerの基本ですが、@ResponseBodyを併用することで、データ中心のレスポンスを実現できるという点がポイントです。@RestControllerはこれを簡潔に記述できる便利なアノテーションですが、初心者はまず@Controllerと@ResponseBodyの動きを理解することが大切です。
3. @ResponseBodyとは?@Controllerとの併用方法
SpringでREST APIを作成する際に、非常に重要なアノテーションが@ResponseBodyです。このアノテーションをメソッドに付けることで、戻り値がHTMLテンプレートとして解釈されずに、HTTPレスポンスの本文としてそのまま返されるようになります。
たとえば、文字列を返すメソッドがある場合、@ResponseBodyを付けなければ、Springはその文字列をテンプレート名だと解釈しようとします。しかし@ResponseBodyを付けることで、データとしてレスポンスを返すように明示できます。
以下は、@Controllerと@ResponseBodyを組み合わせた基本的な例です。
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class MessageController {
@GetMapping("/message")
@ResponseBody
public String getMessage() {
return "これは@ResponseBodyを使ったレスポンスです。";
}
}
このコードを実行して/messageにアクセスすると、「これは@ResponseBodyを使ったレスポンスです。」というテキストが表示されます。これはHTMLのテンプレートではなく、プレーンテキストとして返されるREST APIの動きに近いものです。
つまり、@Controllerに@ResponseBodyを組み合わせることで、Springでは画面ではなくデータを返す処理が簡単に実現できるというわけです。
4. @RestControllerを使うとどうなる?(実は内部的に@ResponseBody付きになる)
先ほどの章で紹介した@ResponseBody@RestControllerというアノテーションです。
@RestControllerは、実は内部的に@Controllerと@ResponseBodyが組み合わさったアノテーションです。つまり、@RestControllerをクラスに付ければ、クラス内のすべてのメソッドで@ResponseBodyが自動的に有効になるという仕組みです。
ただし本記事では、@RestControllerを使わずに@Controller + @ResponseBodyで構成するルールのため、あくまで理解の参考として紹介します。
以下のように記述すれば、Springでは自動的にレスポンスとしてデータが返されます。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AutoController {
@GetMapping("/auto")
public String autoMessage() {
return "これは@RestControllerで返される自動レスポンスです。";
}
}
このコードでは、クラスに@RestControllerを付けることで、@ResponseBodyなしでもレスポンスとして文字列を返すことができます。ただし、初心者の方にはこの仕組みの裏側を理解するためにも、@Controllerと@ResponseBodyを明示的に使う方法から始めることをおすすめします。
5. 文字列やオブジェクトをレスポンスとして返す仕組み(JSONレスポンス)
REST APIでは、文字列だけでなく、複雑なデータ構造をJSON形式で返すことがよくあります。Springでは、Javaのオブジェクトを返すだけで、自動的にJSONレスポンスに変換してくれる便利な仕組みが備わっています。
たとえば、ユーザー情報を含むオブジェクトを返したい場合、以下のように記述することでJSONとしてレスポンスが生成されます。
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UserController {
static class User {
public String name;
public int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
}
@GetMapping("/user")
@ResponseBody
public User getUser() {
return new User("田中太郎", 28);
}
}
このように、@ResponseBodyを使ってJavaのオブジェクトを返すと、Springは自動的にJacksonというライブラリを使ってJSONに変換してくれます。
{"name":"田中太郎","age":28}
この仕組みを活用すれば、SpringでREST APIを作成する際に、わざわざJSON文字列を組み立てる必要はありません。Javaのオブジェクトを返すだけで済むため、開発効率が大きく向上します。
また、実際のアプリケーションでは、一覧のデータをListやMapでまとめて返すケースもあります。次のようなコードも可能です。
import java.util.List;
import java.util.Arrays;
@Controller
public class MemoController {
@GetMapping("/memos")
@ResponseBody
public List<String> getMemos() {
return Arrays.asList("買い物リスト", "勉強のメモ", "読書メモ");
}
}
["買い物リスト","勉強のメモ","読書メモ"]
このように、Springでは非常に簡単にJSONレスポンスを返すことができるので、フロントエンドや外部システムとの連携にも活用しやすくなっています。
6. REST APIを作る上でよくあるつまずき(文字化け、レスポンスの形式ミスなど)
SpringでREST APIを作成する際には、いくつかのポイントで初心者がつまずくことがあります。特にレスポンスの文字化けや、JSON形式が正しく返らないといったトラブルはよくある問題です。ここではその原因と対処法について解説します。
文字化けの問題
日本語の文字列をレスポンスとして返すと、ブラウザやクライアントで文字化けが起こることがあります。これは主に文字コード(エンコーディング)の設定が正しくない場合に発生します。
Spring Bootを使用している場合、通常はUTF-8でレスポンスが返されますが、設定が古かったり、プロジェクトの依存関係が不完全だったりするとISO-8859-1になることがあります。
このようなときは、application.propertiesに以下の設定を追加することで解決できます。
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
また、Javaファイルの文字コードや、Gradleの設定ファイルもUTF-8になっているか確認することが大切です。
レスポンス形式のミス
初心者がよく間違えるのが、JSON形式で返すつもりが文字列になってしまうケースです。これは、Javaのクラスを使わずに手書きの文字列を返してしまうことが原因です。
以下のように、手動でJSON文字列を返すのは非推奨です。
@GetMapping("/wrong")
@ResponseBody
public String wrongResponse() {
return "{\"name\":\"田中\"}";
}
この方法では、構文ミスやエスケープの漏れなどでレスポンスが不正になる可能性があります。SpringのREST APIでは、必ずJavaオブジェクトとして返すことで、正しいJSONレスポンスが得られます。
7. よく使うHTTPメソッドとレスポンスの形式
REST APIでは、HTTPメソッドを使い分けて処理の意味を表現します。たとえば「取得」「追加」「更新」「削除」といった操作は、それぞれGET、POST、PUT、DELETEというメソッドで表します。
Springでは、これらに対応するアノテーションが用意されており、それを使うことで直感的にREST APIの設計ができます。
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.*;
@Controller
@RequestMapping("/items")
public class ItemController {
private List<String> items = new ArrayList<>(Arrays.asList("ノート", "ペン", "消しゴム"));
@GetMapping
@ResponseBody
public List<String> getItems() {
return items;
}
@PostMapping
@ResponseBody
public String addItem(@RequestParam String name) {
items.add(name);
return "追加しました:" + name;
}
@PutMapping
@ResponseBody
public String updateItem(@RequestParam int index, @RequestParam String name) {
if (index >= 0 && index < items.size()) {
items.set(index, name);
return "更新しました:" + name;
} else {
return "指定されたインデックスは存在しません";
}
}
@DeleteMapping
@ResponseBody
public String deleteItem(@RequestParam int index) {
if (index >= 0 && index < items.size()) {
String removed = items.remove(index);
return "削除しました:" + removed;
} else {
return "削除に失敗しました";
}
}
}
このように、HTTPメソッドに対応するアノテーションを適切に使うことで、APIの意味が明確になります。これにより、フロントエンドや外部システムとの連携もスムーズになります。
8. REST APIの基本的な流れ(フロントエンド → リクエスト送信 → Springがレスポンス)
最後に、REST APIがどのような流れで動作するのかを見てみましょう。基本的な流れは次の通りです。
- 1. フロントエンドがURLに向けてリクエストを送信
- 2. Springのコントローラがそのリクエストを受け取る
- 3. 必要な処理を実行して、レスポンスとしてデータを返す
この一連の流れは、ユーザーがボタンをクリックしたり、画面を開いたりしたときに自動で発生します。以下は、Spring側のコードの一例です。
@Controller
public class ApiController {
@GetMapping("/info")
@ResponseBody
public String getInfo() {
return "これはREST APIの基本的なレスポンスです。";
}
}
フロントエンドではJavaScriptやHTMLからfetchやXMLHttpRequestを使ってこのURLにアクセスし、受け取ったレスポンスを画面に表示したり、別の処理に使ったりします。
<script>
fetch('/info')
.then(response => response.text())
.then(data => {
document.getElementById('result').innerText = data;
});
</script>
このように、Springで作成したREST APIは、フロントエンドからのリクエストを受けて必要な情報をレスポンスとして返す重要な役割を担っています。
特に画面ではなくデータをやり取りするアプリケーションでは、この非同期通信の仕組みを正しく理解することが欠かせません。