Spring MVCは、バージョン4.3以上で説明した動作のみを示す必要があります。 this JIRA issueを参照してください。以前は、Spring MVCはThrowable
の値を@ExceptionHandler
メソッドに公開しませんでした。 4.3以降
を参照してください、Spring MVCのは、それは、通常のExceptionHandlerExceptionResolver
プロセスにさらされる、あなたのハンドラメソッドからスローされたThrowable
をキャッチし、NestedServletException
でそれをラップします。
ここにそれがどのように動作するかの簡単な説明です:
- をチェックハンドラメソッドの
@Controller
クラスがどの@ExceptionHandler
メソッドが含まれている場合。
- この場合、
Exception
タイプ(NestedServletException
を含む)を処理できるものを解決しようとします。可能であれば、それを使用します(複数の一致が見つかった場合はソートが行われます)。できない場合、Exception
にはcause
が含まれていますが、アンラップして再度そのハンドラを検索しようとします。 cause
はThrowable
(またはそのサブタイプのいずれか)になりました。
- そうでない場合。
@ControllerAdvice
クラスをすべて取得し、Exception
タイプ(NestedServletException
を含む)のハンドラを見つけようとします。可能であれば、それを使用します。できない場合、Exception
にはcause
が含まれていますが、それをアンラップして、Throwable
タイプで再試行します。
この例では、MyController
はInternalError
をスローします。これはException
のサブクラスではないので、Spring MVCはNestedServletException
にラップします。
MyController
には@ExceptionHandler
のメソッドがないため、Spring MVCはスキップします。 注釈付きクラスExceptionsHandler
があるため、Spring MVCでチェックされます。@ExceptionHandler
注釈付きHandleDefaultException
メソッドはException
を処理できるため、Spring MVCはNestedServletException
を処理するように選択します。
HandleDefaultException
を削除すると、Spring MVCはException
を処理できるものを見つけられません。次に、NestedServletException
のラップを解除し、そのcause
を確認します。それはそのInternalError
を扱うことができるHandleInternalError
を見つけるでしょう。
これは扱いやすい問題ではありません。いくつかのオプションがあります:
NestedServletException
を処理する@ExceptionHandler
を作成し、InternalError
のチェックをしてください。
@ExceptionHandler(NestedServletException.class)
public ResponseEntity<String> HandleNested(NestedServletException ex) {
Throwable cause = ex.getCause();
if (cause instanceof InternalError) {
// deal with it
} else if (cause instanceof OtherError) {
// deal in some other way
}
}
あなたが処理したい異なるError
またはThrowable
タイプの束がありますしない限り、これは問題ありません。 (Spring MVCはデフォルトで他の動作を行い、500エラーコードを返す可能性があります)
また、 Spring MVCが最初に@ExceptionHandler
メソッドの@Controller
(または@RestController
)クラスをチェックしているという事実です。 InternalError
の@ExceptionHandler
メソッドをコントローラに移動するだけです。
@RestController
@RequestMapping("/myController")
public class MyController {
@RequestMapping(value = "/myAction", method = RequestMethod.POST)
public boolean myAction() {
throw new InternalError("");
}
@ExceptionHandler(value = InternalError.class)
public ResponseEntity<String> HandleInternalError(InternalError ex) {
...
}
}
今、春が最初MyController
にNestedServletException
のハンドラを見つけることを試みます。何も見つからないので、NestedServletException
をアンラップし、InternalError
を得ます。 InternalError
のハンドラを見つけて、HandleInternalError
を探します。
これは、複数のコントローラのハンドラメソッドがInternalError
を投げる場合、それぞれに@ExceptionHandler
を追加する必要があるという欠点があります。これはまた利点かもしれません。あなたの処理ロジックは、エラーをスローするものに近いでしょう。
あなたは4.2.6を使用していますか?あなたが記述する振る舞いは、4.3+でしか動作しません。 –