【Spring Boot】例外ハンドリング(ControllerAdvice)をやさしく解説

Java入門・実践
スポンサーリンク
スポンサーリンク

はじめに

Spring Boot で API を作っていると、
例外が発生したときにどう返すか がとても重要になります。

  • try-catch を Controller に書くべき?
  • エラーのレスポンス形式はどう統一する?
  • バリデーションエラーはどう扱う?

こういった疑問を解決してくれるのが
@ControllerAdvice@ExceptionHandler です。

この記事では、例外ハンドリングの基本を
やさしく・実務寄り で整理していきます。

まずはコードから見ていきましょう。


ControllerAdvice とは

一言でいうと、

「アプリ全体の例外処理を一箇所にまとめる仕組み」

です。

  • Controller ごとに try-catch を書かなくていい
  • エラーレスポンスを統一できる
  • バリデーションエラーもまとめて処理できる

API の品質が一気に上がります。


基本のコード例

例外クラス

Java
public class UserNotFoundException extends RuntimeException {
    public UserNotFoundException(String message) {
        super(message);
    }
}

ControllerAdvice

Java
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException e) {
        ErrorResponse error = new ErrorResponse("USER_NOT_FOUND", e.getMessage());
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
    }
}

ErrorResponse DTO

Java
public class ErrorResponse {
    private String code;
    private String message;
}

これで、
UserNotFoundException が発生したら 404 を返す
という仕組みが完成します。


ControllerAdvice の役割を具体的に整理する

例外処理を一箇所にまとめる

Controller に try-catch を書く必要がなくなります。

Java
throw new UserNotFoundException("ユーザーが見つかりません");

Service で例外を投げるだけで OK。

エラーレスポンスを統一できる

API のエラー形式がバラバラだと、 フロントエンドがとても困ります。

ControllerAdvice を使えば、 全 API のエラー形式を統一 できます。

例:

Java
{
  "code": "USER_NOT_FOUND",
  "message": "ユーザーが見つかりません"
}

バリデーションエラーをまとめて処理できる

@Valid のエラーは MethodArgumentNotValidException が発生します。

Java
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidation(MethodArgumentNotValidException e) {
    String message = e.getBindingResult().getFieldError().getDefaultMessage();
    ErrorResponse error = new ErrorResponse("VALIDATION_ERROR", message);
    return ResponseEntity.badRequest().body(error);
}

これで、 バリデーションエラーも統一された形式で返せる ようになります。

予期しない例外もキャッチできる

Java
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleException(Exception e) {
    ErrorResponse error = new ErrorResponse("INTERNAL_ERROR", "予期しないエラーが発生しました");
    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}

実務でよくあるアンチパターン

Controller に try-catch を書きまくる

→ コードが読みにくくなる
→ 例外処理が散らばる
→ レスポンス形式がバラバラになる

例外を握りつぶしてしまう

Java
try {
    ...
} catch (Exception e) {
    return null;
}

→ デバッグ不能になります。

エラー形式が API ごとに違う

→ フロントが地獄を見る


ControllerAdvice をもっと活かすポイント

エラーコードを定義する

Java
"USER_NOT_FOUND"
"VALIDATION_ERROR"
"INTERNAL_ERROR"

ログを適切に出す

  • 業務エラー → warn
  • システムエラー → error

ResponseEntity と組み合わせる

ステータスコードを明確にできます。

まとめ

ControllerAdvice は、
「例外処理を一箇所にまとめ、API の品質を上げる仕組み」
です。

  • try-catch を Controller に書かなくていい
  • エラーレスポンスを統一できる
  • バリデーションエラーもまとめて処理
  • 予期しない例外もキャッチ
  • Service で例外を投げるだけで OK

難しく聞こえますが、
「例外処理を一箇所に集めるための仕組み」
と理解できれば十分です。


decopon
decopon

ControllerAdvice を理解すると、
API のエラー処理が一気にきれいになります。
例外を“どこで投げて、どこで受け取るか”が整理されるだけで、
設計も保守もぐっと楽になります。
あなたの開発が、今日より少しだけ楽になりますように。

moco
moco

困ったときに全部受け止めてくれる場所…
ControllerAdvice さん、やさしいね。

コメント

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