Spring Bootでコントローラーを作成して、カスタムの方法でallエラー/例外を処理する場合、-カスタムの例外を含むのどちらの手法を推奨しますか?
コントローラはSpring BootのErrorController
を実装する必要がありますか?
コントローラはSpringのResponseEntityExceptionHandler
を拡張する必要がありますか?
両方:両方の機能を含む両方のクラスを実装および拡張する単一のコントローラー?
両方:2つの別個のコントローラー。1つはErrorController
を実装し、もう1つはResponseEntityExceptionHandler
を拡張していますか?
この投稿の理由は、次の属性の all を使用してSpring Bootで例外処理の方法を見つけるためです。
Throwable
sをキャッチする必要があります。Throwable
をキャッチする場合、しないスタックトレースまたは他の実装の詳細をクライアントに公開したいever(明示的にコーディングされている場合を除く)そのように)。Throwable
sをクラスごとに個別に処理できるはずです。その他の指定されていないタイプの場合、デフォルトの応答を指定できます。 (確かに、これは /が@ExceptionHandler
で可能なことです。しかしErrorController
?)両方のコントローラー(上記の1と2を参照)にResponseEntity
オブジェクトを返すメソッドが含まれている可能性があることに気づきました。これにより、発生した例外を処理し、クライアントに応答を返します。だから彼らは理論的には同じ結果を生み出すことができるのでしょうか?
テクニック1と2の使用に関するチュートリアルはいくつかありますが、両方のオプションを検討したり、それらを比較したり、一緒に使用したりする記事は見当たらないため、さらにいくつかの質問が生じます。
それらを一緒に検討する必要がありますか?
これら2つの提案された手法の主な違いは何ですか?類似点は何ですか?
1つは他のより強力なバージョンですか?他の人ができないこと、またはその逆ができることはありますか?
一緒に使用できますか?これが必要になる状況はありますか?
それらが一緒に使用される場合、例外はどのように処理されますか?両方のハンドラーを通過しますか?後者の場合、どれですか?
それらが一緒に使用され、例外がスローされた場合 inside コントローラー(一方または他方)例外処理中、その例外はどのように処理されますか?他のコントローラーに送信されますか?例外は理論的にはコントローラー間でバウンスを開始したり、他の種類の非回復ループを作成したりできますか?
Spring BootがSpringのResponseEntityExceptionHandler
を内部でどのように使用するか、またはSpring BootアプリケーションでSpring Bootがどのように使用されることを期待するかについて、信頼できる/公式のドキュメントはありますか?
ResponseEntityExceptionHandler
だけですでに十分である場合、ErrorController
が存在するのはなぜですか?
SpringのResponseEntityExceptionHandler
を@ExceptionHandler
アノテーションと一緒に見ると、さまざまなタイプの例外を個別に処理し、よりクリーンなコードを使用する方がより強力なようです。ただし、Spring BootはSpringの上に構築されているため、次のことを意味します。
ErrorController
を拡張する代わりにResponseEntityExceptionHandler
を実装する必要がありますか?ErrorController
は、さまざまな種類の例外を個別に処理することを含め、ResponseEntityExceptionHandler
でできるすべてのことを実行できますか?Spring Bootアプリケーションには、エラー処理のためのデフォルト設定 ErrorMvcAutoConfiguration があります。
追加の構成が提供されていない場合の基本的な動作:
BasicErrorController
はデフォルトで「/ error」に接続されています。アプリケーションにカスタマイズされた「エラー」ビューがない場合、いずれかのコントローラーから例外がスローされた場合、ユーザーはBasicErrorControllerによって情報が入力された/ errorホワイトラベルページに移動します。
アプリケーションにErrorController
を実装するコントローラーがある場合、それはreplacesBasicErrorController
です。
エラー処理コントローラーで例外が発生した場合は、Spring例外フィルターを通過し(詳細は以下を参照)、最後に何も見つからない場合、この例外は、基になるアプリケーションコンテナー(例: Tomcat。基になるコンテナーは例外を処理し、その実装に応じていくつかのエラーページ/メッセージを表示します。
BasicErrorController
javadoc には興味深い情報があります。
ErrorAttributesをレンダリングする基本的なグローバルエラーコントローラー。より具体的なエラーは、Spring MVC抽象化(例:@ ExceptionHandler)を使用するか、サーブレットサーバーのエラーページを追加することで処理できます。
BasicErrorController
またはErrorController
の実装はグローバルエラーハンドラーです。 @ExceptionHandlerと組み合わせて使用できます。
ここで ResponseEntityExceptionHandler にアクセスします
@ExceptionHandlerメソッドを介してすべての@RequestMappingメソッドにまたがる一元化された例外処理を提供したい@ControllerAdviceクラスの便利な基本クラス。この基本クラスは、Spring MVCの内部例外を処理するための@ExceptionHandlerメソッドを提供します。
言い換えると、これはResponseEntityExceptionHandler
が既に便利なクラスであり、Spring MVC例外処理がすでに含まれていることを意味します。そして、コントローラーの例外を処理するカスタムクラスの基本クラスとして使用できます。カスタムクラスを機能させるには、@ControllerAdvice
で注釈を付ける必要があります。
@ControllerAdvice
で注釈されたクラスは、グローバルエラーハンドラー(BasicErrorController
またはErrorController
実装)と同時に使用できます。 @ControllerAdvice
注釈付きクラス(ResponseEntityExceptionHandler
を拡張できない、または拡張できない)がいくつかの例外を処理しない場合、例外はグローバルエラーハンドラーに送られます。
これまでのところ、ErrorHandler
コントローラーと@ControllerAdvice
で注釈されたものについて見てきました。しかし、それははるかに複雑です。私は質問で本当に貴重な洞察を見つけました- 複数の@ControllerAdvice @ExceptionHandlersの優先順位の設定 。
編集:
シンプルに保つには:
私はSpringのErrorControllerに過度に精通していないことを認めますが、指定された目標を見ると、Springの@ControllerAdviceを使用してそれらすべてをきれいに達成できると思います。以下は、私が自分のアプリケーションでそれをどのように使用しているかの例です。
@ControllerAdvice
public class ExceptionControllerAdvice {
private static final String INCOMING_REQUEST_FAILED = "Incoming request failed:";
private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionControllerAdvice.class);
private final MessageSource source;
public ExceptionControllerAdvice2(final MessageSource messageSource) {
source = messageSource;
}
@ExceptionHandler(value = {CustomException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public ErrorMessage badRequest(final CustomException ex) {
LOGGER.error(INCOMING_REQUEST_FAILED, ex);
final String message = source.getMessage("exception.BAD_REQUEST", null, LocaleContextHolder.getLocale());
return new ErrorMessage(HttpStatus.BAD_REQUEST.value(), message);
}
@ExceptionHandler(Throwable.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public ErrorMessage internalServerError(final Exception ex) {
LOGGER.error(INCOMING_REQUEST_FAILED, ex);
final String message =
source.getMessage("exception.INTERNAL_SERVER_ERROR", null, LocaleContextHolder.getLocale());
return new ErrorMessage(HttpStatus.INTERNAL_SERVER_ERROR.value(), message);
}
}