1. test 1
  2. test 2
  3. test 3
  4. test 4
  5. test 5
  6. test 6
  7. test 7
  8. test 8
コース一覧
Spring Boot入門
例外をHTTPに変換する

Spring Boot入門

Java で Web API サーバーを作るための Spring Boot の入門コースです。DI コンテナ、REST コントローラ、リクエスト検証、レイヤ分割、Spring Data JPA、例外ハンドリング、テストまでを扱います。毎レッスン、Spring が裏側でやっている判断そのものを pure Java の関数として自分で書き、フレームワークが何を肩代わりしてくれているのかを手触りで理解できる構成にしました。約 12 時間 (1 日 30 分 × 24 日) で 48 レッスンを修了できます。

1
Spring Bootとは何か
01. Spring Bootで何が作れるのか10分
02. サーブレットからフレームワークへ15分
03. ルーティング表という発想15分
04. プロジェクトの構成10分
05. 起動のしくみと自動設定15分
06. パスのマッチング15分
2
DIコンテナ
01. newで書くと何が困るのか15分
02. コンストラクタインジェクション15分
03. インターフェースへの依存15分
04. @Componentと@Bean15分
05. 自作のDIコンテナ20分
06. Beanのスコープとライフサイクル15分
3
RESTコントローラ
01. RESTという設計方針15分
02. @RestControllerの役割15分
03. @GetMappingとパス変数15分
04. クエリパラメータの受け取り15分
05. @PostMappingとリクエストボディ15分
06. ステータスコードの選び方15分
07. ResponseEntityで組み立てる15分
4
リクエストとレスポンスの変換
01. JSONとオブジェクトの往復15分
02. DTOとエンティティを分ける15分
03. recordでDTOを書く15分
04. 入力検証の基本15分
05. 検証エラーをまとめて返す15分
06. アノテーションによる検証15分
5
レイヤ構成とビジネスロジック
01. 3層アーキテクチャ10分
02. @Serviceに置くもの15分
03. 状態遷移をルールにする15分
04. 料金計算のような業務ロジック15分
05. @Transactionalとは何か15分
06. トランザクションの巻き戻し15分
6
データアクセス
01. @Entityとテーブルの対応15分
02. リポジトリという抽象15分
03. メソッド名からクエリを作る20分
04. 検索条件の組み立て15分
05. ページングと並び替え15分
06. N+1問題15分
7
例外処理と横断的関心事
01. 例外をHTTPに変換する15分
02. @ExceptionHandlerと@ControllerAdvice15分
03. エラーレスポンスの形を決める15分
04. フィルタとインターセプタ15分
05. ログとリクエストの追跡15分
06. 設定値の外部化15分
8
テストと仕上げ
01. テストの種類と使い分け15分
02. Serviceの単体テスト15分
03. モックで依存を差し替える15分
04. MockMvcでエンドポイントを試す15分
05. 本番へ出すための次の一歩10分

例外をHTTPに変換する

このレッスンでは、業務のことばで投げられた例外を HTTP のステータスコードへ翻訳する設計を身につけます。

業務の失敗と HTTP の失敗は別のことばです

Service 層は業務のことばで失敗を表します。「その利用者は存在しない」「そのメールアドレスはすでに使われている」「残高が足りない」といった具合です。一方 HTTP のクライアントが理解できるのは 404、409、400 といった 3 桁の数字です。この 2 つの世界をつなぐ翻訳の層がどこかに必要になります。

翻訳をどこに置くかで、コードの見通しは大きく変わります。Service の中で ResponseEntity を組み立ててしまうと、Service が HTTP を知ってしまい、バッチ処理やメッセージ受信から同じ Service を呼びたくなったときに困ります。逆に Controller のすべてのメソッドで try と catch を書くと、同じ変換が何十か所にも散らばります。

Service は業務例外を投げ、外側が翻訳します

現実的な落としどころは、Service が業務例外を投げ、Web の入口に近い層が例外の型を見てステータスを決める形です。

Java

public class UserNotFoundException extends RuntimeException { private final long userId; public UserNotFoundException(long userId) { super("user not found. id=" + userId); this.userId = userId; } public long getUserId() { return userId; } }

Java

@Service public class UserService { public User find(long id) { return repository.findById(id) .orElseThrow(() -> new UserNotFoundException(id)); } }

Service は 404 という数字を一度も書いていません。「見つからなかった」という業務の事実だけを表明しています。この例外を受け取った側が 404 へ翻訳します。次のレッスンで扱う @RestControllerAdvice が、その翻訳を 1 か所に集める仕組みです。

翻訳表を先に決めます

実務では、翻訳のルールを表として先に決めておくとぶれません。よく使う対応は次の通りです。

業務上の失敗例外の型ステータス
対象が存在しないNotFoundException404
入力が不正であるValidationException400
一意制約とぶつかったDuplicateKeyException409
認証されていないUnauthorizedException401
認証済みだが権限が足りないForbiddenException403
上記のどれでもない想定外の例外すべて500

401 と 403 の違いは頻出です。401 は「あなたが誰なのか分からない」、403 は「あなたが誰かは分かったが、それをする権限がない」です。ログインし直せば解決する見込みがあるのが 401、し直しても解決しないのが 403 と覚えると迷いません。

想定外は必ず 500 に落とします

翻訳表に載っていない例外を、それらしいステータスへ推測で割り当ててはいけません。表に無い例外は「こちらが想定していなかった不具合」であり、その正体は 500 です。4xx を返してしまうと、クライアント側は自分の入力が悪いのだと解釈して直そうとし、実際にはサーバーの不具合なので永遠に直りません。既定を 500 にしておくことは、不具合を不具合として表に出すための設計です。

同時に、500 の応答本文に例外のスタックトレースをそのまま載せないでください。内部のクラス名やライブラリの構成が漏れ、攻撃の手がかりになります。詳細はサーバーのログに残し、クライアントへは短いメッセージと追跡用の識別子だけを返す形が定石です。

演習で書くもの

Spring では例外の型からハンドラを探し、そこに書かれたステータスを応答に乗せます。その「型からステータスを決める」判断そのものを、ここでは対応表を持つ 1 つの関数として自分で書きます。表に無い名前が来たら 500 を返してください。

要件

  1. 表にある 5 つの例外名について、決められたステータスコードを返すこと
  2. 表に無い名前と null は 500 を返すこと
  3. 戻り値は int とし、文字列で返さないこと

入出力例

toStatus("NotFoundException") → 404 toStatus("ValidationException") → 400 toStatus("DuplicateKeyException") → 409 toStatus("UnauthorizedException") → 401 toStatus("ForbiddenException") → 403 toStatus("OutOfMemoryError") → 500 toStatus("notfoundexception") → 500 toStatus("") → 500

ヒント

Map<String, Integer> に対応表を作り、get で引くと if の連なりを避けられます

Map の get は見つからないと null を返します。その場合に 500 を返してください

null が渡される可能性があるので、get を呼ぶ前に引数の null を確かめます

生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/08/09

関連レッスン

  • @ExceptionHandlerと@ControllerAdvice

    ハンドラの適用範囲と選ばれ方を確認します。

  • エラーレスポンスの形を決める

    一貫したエラー本文を組み立てられるようになります。

  • フィルタとインターセプタ

    連なった処理を順に通すチェーンを実装します。

  • ログとリクエストの追跡

    リクエストを識別する ID を組み立て、追跡できるようにします。

このレッスンに出てくる用語

意味があいまいなまま進んだ語は、ここから読み直せます。

  • HTTPWeb の通信プロトコル、HTTPS は TLS で暗号化したもの
  • ステータスコード200/201/404 など結果を示す3桁の数値
  • 設計何をどう作るかを決める前工程
  • 処理計算や代入を表す長方形
  • メソッドクラスに属する関数
  • 認証「この人は本当に本人?」のチェック
  • サーバークライアント(ブラウザなど)がリクエストを送り、サーバーがレスポンスを返す。
  • スタック後入れ先出し(LIFO)のデータ構造
main.java
学習モード
エディタを読み込んでいます

メモ

例外をHTTPに変換する

⌘S で保存