例外
次の例に示すように、@Controller
クラスおよび @ControllerAdvice クラスには、コントローラーメソッドからの例外を処理する @ExceptionHandler
メソッドを含めることができます。
Java
Kotlin
import java.io.IOException;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
@Controller
public class SimpleController {
@ExceptionHandler(IOException.class)
public ResponseEntity<String> handle() {
return ResponseEntity.internalServerError().body("Could not read file storage");
}
}
import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.ExceptionHandler
import java.io.IOException
@Controller
class SimpleController {
@ExceptionHandler(IOException::class)
fun handle() : ResponseEntity<String> {
return ResponseEntity.internalServerError().body("Could not read file storage")
}
}
例外マッピング
例外は、伝播されるトップレベルの例外 (たとえば、直接スローされる IOException
) またはラッパー例外内のネストされた原因 (たとえば、IllegalStateException
内にラップされた IOException
) と一致する可能性があります。5.3 以降では、任意の原因レベルで一致できますが、以前は直接の原因のみが考慮されていました。
例外の種類を一致させるには、前の例で示したように、ターゲットの例外をメソッド引数として宣言することが望ましいです。複数の例外メソッドが一致する場合、通常は原因の例外の一致よりもルートの例外の一致が優先されます。より具体的には、ExceptionDepthComparator
は、スローされた例外型からの深さに基づいて例外をソートするために使用されます。
または、次の例に示すように、アノテーション宣言により、一致するように例外型を絞り込むことができます。
Java
Kotlin
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handleIoException(IOException ex) {
return ResponseEntity.internalServerError().body(ex.getMessage());
}
@ExceptionHandler(FileSystemException::class, RemoteException::class)
fun handleIoException(ex: IOException): ResponseEntity<String> {
return ResponseEntity.internalServerError().body(ex.message)
}
次の例に示すように、非常に汎用的な引数シグネチャーを持つ特定の例外型のリストを使用することもできます。
Java
Kotlin
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handleExceptions(Exception ex) {
return ResponseEntity.internalServerError().body(ex.getMessage());
}
@ExceptionHandler(FileSystemException::class, RemoteException::class)
fun handleExceptions(ex: Exception): ResponseEntity<String> {
return ResponseEntity.internalServerError().body(ex.message)
}
ルートと原因の例外マッチングの違いは驚くべきことです。 前に示した
|
一般的に、引数シグネチャーをできるだけ具体的に指定することをお勧めします。これにより、ルートと原因の例外型間の不一致の可能性を減らします。マルチマッチングメソッドを個々の @ExceptionHandler
メソッドに分割し、それぞれのシグネチャーで単一の特定の例外型に一致させることを検討してください。
マルチ @ControllerAdvice
配置では、対応する順序で優先順位付けされた @ControllerAdvice
でプライマリルート例外マッピングを宣言することをお勧めします。ルート例外の一致は原因よりも優先されますが、これは特定のコントローラーまたは @ControllerAdvice
クラスのメソッド間で定義されます。つまり、優先度の高い @ControllerAdvice
Bean の原因一致は、優先度の低い @ControllerAdvice
Bean の一致(ルートなど)よりも優先されます。
最後になりましたが、@ExceptionHandler
メソッドの実装では、元の形式で例外を再スローすることにより、特定の例外インスタンスの処理を取り消すことを選択できます。これは、ルートレベルの一致、または静的に決定できない特定のコンテキスト内の一致のみに関心があるシナリオで役立ちます。指定された @ExceptionHandler
メソッドがそもそも一致していないかのように、再スローされた例外は残りの解決チェーンを介して伝搬されます。
Spring MVC での @ExceptionHandler
メソッドのサポートは、DispatcherServlet
レベルの HandlerExceptionResolver メカニズムに基づいて構築されています。
メディア型のマッピング
例外型に加えて、@ExceptionHandler
メソッドは生成可能なメディア型も宣言できます。これにより、通常は "Accept" HTTP リクエストヘッダーで HTTP クライアントによってリクエストされたメディア型に応じてエラーレスポンスを調整できます。
アプリケーションは、同じ例外型に対して、生成可能なメディア型をアノテーション上で直接宣言できます。
Java
Kotlin
@ExceptionHandler(produces = "application/json")
public ResponseEntity<ErrorMessage> handleJson(IllegalArgumentException exc) {
return ResponseEntity.badRequest().body(new ErrorMessage(exc.getMessage(), 42));
}
@ExceptionHandler(produces = "text/html")
public String handle(IllegalArgumentException exc, Model model) {
model.addAttribute("error", new ErrorMessage(exc.getMessage(), 42));
return "errorView";
}
@ExceptionHandler(produces = ["application/json"])
fun handleJson(exc: IllegalArgumentException): ResponseEntity<ErrorMessage> {
return ResponseEntity.badRequest().body(ErrorMessage(exc.message, 42))
}
@ExceptionHandler(produces = ["text/html"])
fun handle(exc: IllegalArgumentException, model: Model): String {
model.addAttribute("error", ErrorMessage(exc.message, 42))
return "errorView"
}
ここでは、メソッドは同じ例外型を処理しますが、重複として拒否されることはありません。代わりに、"application/json" をリクエストする API クライアントは JSON エラーを受け取り、ブラウザーは HTML エラービューを取得します。各 @ExceptionHandler
アノテーションは、生成可能なメディア型をいくつか宣言できます。エラー処理フェーズでのコンテンツネゴシエーションによって、どのコンテンツ型が使用されるかが決定されます。
メソッド引数
@ExceptionHandler
メソッドは、次の引数をサポートしています。
メソッド引数 | 説明 |
---|---|
例外型 | 発生した例外へのアクセス用。 |
| 例外を発生させたコントローラーメソッドへのアクセス用。 |
| サーブレット API を直接使用せずに、リクエストパラメーターとリクエストおよびセッション属性への汎用アクセス。 |
| 特定のリクエストまたはレスポンスの型を選択します(例: |
| セッションの存在を強制します。結果として引数は決して |
| 現在認証されているユーザー — 既知の場合、特定の |
| リクエストの HTTP メソッド。 |
| 現在のリクエストロケール。利用可能な最も具体的な |
|
|
| サーブレット API によって公開されている未加工のレスポンス本文へのアクセス用。 |
| エラーレスポンスのモデルへのアクセス用。常に空です。 |
| リダイレクト(クエリ文字列に追加される)の場合に使用する属性と、リダイレクト後のリクエストまで一時的に保存されるフラッシュ属性を指定します。リダイレクト属性およびフラッシュ属性を参照してください。 |
| クラスレベルの |
| リクエスト属性へのアクセス用。詳細については、 |
戻り値
@ExceptionHandler
メソッドは、次の戻り値をサポートしています。
戻り値 | 説明 |
---|---|
| 戻り値は |
| 戻り値は、完全なレスポンス(HTTP ヘッダーと本文を含む)が |
| 本文に詳細を含む RFC 9457 エラーレスポンスをレンダリングするには、エラーレスポンスを参照してください。 |
| 本文に詳細を含む RFC 9457 エラーレスポンスをレンダリングするには、エラーレスポンスを参照してください。 |
|
|
| 暗黙的なモデルと一緒にレンダリングするために使用する |
|
|
|
|
|
The view and model attributes to use and, optionally, a response status. |
|
上記のいずれにも当てはまらない場合、 |
その他の戻り値 | 戻り値が上記のいずれにも一致せず、(BeanUtils#isSimpleProperty (Javadoc) によって決定される)単純型ではない場合、デフォルトでは、モデルに追加されるモデル属性として扱われます。単純型の場合、未解決のままです。 |