0Pricing
Java Academy · レッスン

@ControllerAdviceによるグローバル例外処理

@ExceptionHandlerと@ControllerAdviceを使い、すべてのコントローラーの例外処理を一元化します。

「@ControllerAdviceによるグローバル例外処理」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

グローバル処理がない場合の問題

グローバルな例外処理がないと、すべてのコントローラーメソッドに try-catch ブロックが必要になり、エラーレスポンスの作成が重複し、例外の詳細がクライアントに漏れる可能性があります。

@ControllerAdvice と @RestControllerAdvice

@ControllerAdvice はグローバル例外ハンドラークラスを定義します。@RestControllerAdvice は @ResponseBody を追加するため、すべてのハンドラーメソッドが自動的に JSON を返します。

@RestControllerAdvice
public class GlobalExceptionHandler {
    // @ExceptionHandler methods go here
}

@ExceptionHandler メソッド

メソッドに @ExceptionHandler(ExceptionType.class) を付けます。Spring はその型(およびサブクラス)の例外をメソッドに振り分けます。適切なステータスを設定した ResponseEntity を返します。

@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) {
    return ResponseEntity.status(HttpStatus.NOT_FOUND)
        .body(new ErrorResponse("NOT_FOUND", ex.getMessage()));
}

複数の例外型の処理

1 つのハンドラーに複数の例外型を列挙するか、共通の基底クラスを使用します。Spring は利用可能な中で最も具体的なハンドラーを選択します。

@ExceptionHandler({IllegalArgumentException.class, IllegalStateException.class})
public ResponseEntity<ErrorResponse> handleBadRequest(RuntimeException ex) {
    return ResponseEntity.badRequest()
        .body(new ErrorResponse("BAD_REQUEST", ex.getMessage()));
}

検証エラーの処理

@Valid で検証されたリクエストボディからフィールド単位のエラーを取り出すには、MethodArgumentNotValidException を捕捉します。

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, Object>> handleValidation(MethodArgumentNotValidException ex) {
    Map<String, String> fieldErrors = new LinkedHashMap<>();
    ex.getBindingResult().getFieldErrors().forEach(e ->
        fieldErrors.put(e.getField(), e.getDefaultMessage()));
    return ResponseEntity.badRequest()
        .body(Map.of("errors", fieldErrors, "status", 400));
}

制約違反の処理

サービス層で @Validated を使ってメソッドパラメーターを検証すると、ConstraintViolationException がスローされます。MVC の検証エラーとは分けて処理してください。

@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<Map<String, String>> handleConstraint(ConstraintViolationException ex) {
    Map<String, String> errors = new LinkedHashMap<>();
    ex.getConstraintViolations().forEach(v ->
        errors.put(v.getPropertyPath().toString(), v.getMessage()));
    return ResponseEntity.badRequest().body(errors);
}

HttpServletRequest へのアクセス

HttpServletRequest をパラメーターに追加すると、ログへの記録やエラーレスポンスへの追加に必要なリクエストの詳細(URL、メソッド、ヘッダー)を取得できます。

@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAll(Exception ex, HttpServletRequest req) {
    log.error("Unhandled error on {} {}", req.getMethod(), req.getRequestURI(), ex);
    return ResponseEntity.internalServerError()
        .body(new ErrorResponse("INTERNAL_ERROR", "Unexpected error"));
}

例外クラスへの @ResponseStatus

カスタム例外クラスに @ResponseStatus を付けると、ハンドラーメソッドを使わずに HTTP ステータスを自動設定できます。単純なケースに適しています。

@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
    public ResourceNotFoundException(String msg) { super(msg); }
}

@ControllerAdvice の適用範囲

@ControllerAdvice の属性を使って、対象を特定のパッケージ、アノテーション、または基底クラスに限定できます。

@RestControllerAdvice(basePackages = "com.example.api")
public class ApiExceptionHandler { ... }
@RestControllerAdvice(assignableTypes = {UserController.class, OrderController.class})
public class SpecificHandler { ... }

例外ハンドラーでのログ記録

適切なレベルで例外をログに記録します。ユーザーエラー(4xx)は WARN、予期しないエラー(5xx)は完全なスタックトレースとともに ERROR として記録します。

@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAll(Exception ex, HttpServletRequest req) {
    if (ex instanceof BusinessException) log.warn("Business error: {}", ex.getMessage());
    else log.error("Unexpected error on {}", req.getRequestURI(), ex);
    return ...
}

例外ハンドラーの優先順位

Spring は最も具体的なハンドラーを選択します。ResourceNotFoundException extends RuntimeException の場合、ResourceNotFoundException 用のハンドラーが RuntimeException 用のハンドラーより優先されます。

クイックチェック

特定の例外型をグローバルに処理するメソッドには、どのアノテーションを付けますか?

まとめ

@RestControllerAdvice と @ExceptionHandler を使用して、エラーハンドリングを一元化します。一貫したエラー構造の ResponseEntity を返します。バリデーション(MethodArgumentNotValidException)と制約違反(ConstraintViolationException)は別々に処理します。4xx は WARN、5xx は ERROR としてログに記録します。

よくある質問

「@ControllerAdviceによるグローバル例外処理」レッスンは無料ですか?

はい。「@ControllerAdviceによるグローバル例外処理」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「@ControllerAdviceによるグローバル例外処理」で何を学びますか?

@ExceptionHandlerと@ControllerAdviceを使い、すべてのコントローラーの例外処理を一元化します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「@ControllerAdviceによるグローバル例外処理」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Bean Validation:@NotNull、@Size、@Pattern
  2. カスタム制約アノテーション
  3. @ControllerAdviceによるグローバル例外処理
  4. RFC 7807 Problem Detailsと一貫したエラーレスポンス
← Java Academyに戻る