Web MVC — *リクエストがレスポンスになるまで*
Web MVC — *リクエストがレスポンスになるまで*
🎯 このレッスンを読んだあとに
このレッスンを最後まで読めば、以下の 3 つを自信を持ってできるようになります。
- ▸✅ @RestController + @RequestMapping で REST API 4 種 (GET/POST/PUT/DELETE) を実装
- ▸✅ @RequestBody / @PathVariable / @RequestParam の違いを理解して使い分ける
- ▸✅ @RestControllerAdvice でグローバル例外処理パターンを設定する
これらの学習目標をチェックリストとして手元に置き、すべてに答えられるようになったらレッスンを閉じてください。
リクエストは*どのように*処理されるか — DispatcherServlet のフロー
核心の一文
ブラウザが GET /users/42 リクエストを送ると、Spring は DispatcherServlet という交通整理係を経由して、適切なコントローラーへ転送します。
6 ステップのフロー
1. HTTP リクエスト到着 — 組み込み Tomcat が受け取る
2. DispatcherServlet — Spring の入口。すべてのリクエストがここを通る
3. HandlerMapping — 「この URL はどのコントローラーのどのメソッド?」
4. コントローラー実行 — ビジネスロジック + Service 呼び出し
5. レスポンスオブジェクト — DTO を返す → Jackson が JSON にシリアライズ
6. HTTP レスポンス — ブラウザへ
各ステップは Spring が自動的に処理します。開発者は @RestController クラスの中に @GetMapping("/users/{id}") メソッドを書くだけです。
Filter vs Interceptor vs AOP — 処理の途中に割り込む
リクエスト処理の途中に共通ロジック(認証・ロギング・圧縮)を挿入したい場合、3 つの選択肢があります。
Filter — サーブレット標準
DispatcherServlet の前に動作。HTTP レスポンス全体を扱います。
用途: すべてのリクエストに共通 — ロギング・圧縮・CORS・認証トークン抽出
Interceptor — Spring MVC レイヤー
DispatcherServlet の後、コントローラー呼び出しの前後に割り込みます。
用途: 特定のコントローラーパターンにのみ適用。URL ベースの権限管理・ロギング。
AOP — メソッド単位
特定のメソッド呼び出しの前後。最も細粒度。
@Transactional、@Cacheable などはすべて AOP ベースです。
いつ何を使う?
- ▸すべてのリクエストに共通 → Filter
- ▸URL パターンベース → Interceptor
- ▸特定のメソッド → AOP
まとめ
DispatcherServlet がすべてのリクエストを受け取り、適切なコントローラーへルーティングします。途中に共通ロジックを挿入したい場合は、Filter・Interceptor・AOP の中から選択してください。細粒度が必要なほど後ろの選択肢を使います。
@RestController + @GetMapping — *REST API を作る*
@Controller vs @RestController
従来の Spring の @Controller は View (HTML) を返していました。JSP や Thymeleaf などのテンプレートエンジンと組み合わせてサーバーサイドレンダリング (SSR) を行っていました。
@RestController はデータ (JSON) を返します。SPA やモバイルアプリと通信する REST API の標準。実質的には @Controller + @ResponseBody の組み合わせです。
返り値の UserDto オブジェクトが Jackson によって自動的に JSON に変換され、ブラウザへ送信されます。シンプルです。
HTTP メソッドマッピング
すべて @RequestMapping(method = RequestMethod.GET) の短縮形です。明示的な意味があるため、常に上記の短縮形を使いましょう。
パラメーターを受け取る 4 つの方法
1. @PathVariable — URL パスの変数:
2. @RequestParam — クエリ文字列:
3. @RequestBody — JSON 本文 (POST/PUT):
4. @RequestHeader / @CookieValue — HTTP ヘッダー・クッキー:
レスポンス — HTTP ステータスコードの明示
返り値だけ指定すると、デフォルトで 200 OK が返ります。別のステータスが必要な場合:
public UserDto create(@RequestBody CreateUserDto dto) { ... }
// またはより細かく:
@GetMapping("/{id}")
public ResponseEntity
return userService.findById(id)
.map(u -> ResponseEntity.ok(u)) // 200
.orElse(ResponseEntity.notFound().build()); // 404
}
java@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(EntityNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse notFound(EntityNotFoundException e) {
return new ErrorResponse("NOT_FOUND", e.getMessage());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse validation(MethodArgumentNotValidException e) {
return new ErrorResponse("VALIDATION_FAILED",
e.getBindingResult().getAllErrors().toString());
}
}
javapublic record CreateUserDto(
@NotBlank @Email String email,
@NotBlank @Size(min=8, max=100) String password,
@NotBlank String name
) { }
@PostMapping("/users")
public UserDto create(@RequestBody @Valid CreateUserDto dto) { ... }
``
バリデーション失敗 → MethodArgumentNotValidException が自動的にスロー → 上記の GlobalExceptionHandler がクリーンな 400 レスポンスを返します。
まとめ
- ▸@RestController
+@GetMappingで即座に REST API を構築 - ▸@PathVariable
・@RequestParam・@RequestBodyで入力を受け取る - ▸@ResponseStatus
・ResponseEntityでステータスコードを制御 - ▸@RestControllerAdvice
でグローバル例外処理 - ▸@Valid` + Bean Validation で入力バリデーション
🤖 AI にはこう依頼してみましょう
このレッスンの概念を理解していれば、AI に具体的な指示を出すことができます。漠然とした「直して」ではなく、語彙を持ったリクエスト — それがトークン節約の出発点です。
- ▸「このコントローラーに @ControllerAdvice ベースのグローバル例外処理を追加して」
- ▸「User CRUD API 4 つ (GET/POST/PUT/DELETE) のコントローラーを作って」
- ▸「このレスポンスを ResponseEntity でラップして、201 / 204 ステータスコードを正確に返すようにして」
なぜトークンが減るのか
概念を知らないと、AI の回答を受け取っても「それって何ですか?」と再度聞き返す必要があります。その「聞き返し」がトークンを消費します。概念を一度理解しておけば、会話が一発で終わります。