問題Spring Webは、スプリングアプリケーションからapplication/problem+json応答を簡単に作成できるライブラリのセットです。問題ライブラリとSpring Web MVCの例外処理またはSpring WebFluxの例外処理を接続して、最小限の開発者の努力を必要としながらシームレスに作業するように、ニッチを埋めます。そうすることで、それは小さなが繰り返しのタスクを実行することを目指しています。
このライブラリの仕組みは、アドバイス特性と呼ばれるものに基づいています。アドバイス特性は、単一のメソッドインターフェイスに配置されたデフォルトのメソッドとして実装された、小さな再利用可能な@ExceptionHandlerです。これらのアドバイス特性は自由に組み合わせることができ、 @ControllerAdviceに共通のベースクラスを使用する必要はありません。
?詳細な紹介については、Baeldung:問題のガイドスプリングWebライブラリをご覧ください!
AdviceTraitが提供する問題処理プロセスは、必要性が生じるたびにカスタマイズできるように構築されています。次のすべての側面(およびその他)は、適切なアドバイス特性インターフェイスを実装することでカスタマイズできます。
| 側面 | 方法 | デフォルト |
|---|---|---|
| 創造 | AdviceTrait.create(..) | |
| ロギング | AdviceTrait.log(..) | WARNとして4xx、スタックトレースを含むERRORとして5xx |
| コンテンツネゴシエーション | AdviceTrait.negotiate(..) | application/json 、 application/*+json 、 application/problem+jsonおよびapplication/x.problem+json |
| 後退する | AdviceTrait.fallback(..) | application/problem+json |
| 後処理 | AdviceTrait.process(..) | n/a |
次の例は、 Problemにparameter拡張フィールドを追加することにより、 MissingServletRequestParameterAdviceTraitをカスタマイズします。
@ ControllerAdvice
public class MissingRequestParameterExceptionHandler implements MissingServletRequestParameterAdviceTrait {
@ Override
public ProblemBuilder prepare ( Throwable throwable , StatusType status , URI type ) {
var exception = ( MissingServletRequestParameterException ) throwable ;
return Problem . builder ()
. withTitle ( status . getReasonPhrase ())
. withStatus ( status )
. withDetail ( exception . getMessage ())
. with ( "parameter" , exception . getParameterName ());
}
}このようなコントローラーがあると仮定します。
@ RestController
@ RequestMapping ( "/products" )
class ProductsResource {
@ RequestMapping ( method = GET , value = "/{productId}" , produces = APPLICATION_JSON_VALUE )
public Product getProduct ( String productId ) {
// TODO implement
return null ;
}
@ RequestMapping ( method = PUT , value = "/{productId}" , consumes = APPLICATION_JSON_VALUE )
public Product updateProduct ( String productId , Product product ) {
// TODO implement
throw new UnsupportedOperationException ();
}
}次のHTTPリクエストは、それぞれ対応する応答を生成します。
GET /products/123 HTTP/1.1
Accept: application/xml HTTP/1.1 406 Not Acceptable
Content-Type: application/problem+json
{
"title" : " Not Acceptable " ,
"status" : 406 ,
"detail" : " Could not find acceptable representation "
} POST /products/123 HTTP/1.1
Content-Type: application/json
{} HTTP/1.1 405 Method Not Allowed
Allow: GET
Content-Type: application/problem+json
{
"title" : " Method Not Allowed " ,
"status" : 405 ,
"detail" : " POST not supported "
}続行する前に、Zalando/問題のスタックトレースと因果チェーンに関するセクションをお読みください。
スタックトレースを有効にする場合は、次のようにProblemModuleを構成してください。
ObjectMapper mapper = new ObjectMapper ()
. registerModule ( new ProblemModule (). withStackTraces ());問題の因果チェーンはデフォルトで無効になりますが、必要に応じてオーバーライドできます。
@ ControllerAdvice
class ExceptionHandling implements ProblemHandling {
@ Override
public boolean isCausalChainsEnabled () {
return true ;
}
}注その時点でアプリケーションコンテキストに完全にアクセスできるため、[構成]をapplication.ymlに外部化し、Springのserver.error.include-stacktraceプロパティを再利用することもできます。
両方の機能、因果チェーン、スタックトレースを有効にすると、次のようになります。
{
" title " : " Internal Server Error " ,
" status " : 500,
" detail " : " Illegal State " ,
" stacktrace " : [
" org.example.ExampleRestController.newIllegalState(ExampleRestController.java:96) " ,
" org.example.ExampleRestController.nestedThrowable(ExampleRestController.java:91) "
],
" cause " : {
" title " : " Internal Server Error " ,
" status " : 500,
" detail " : " Illegal Argument " ,
" stacktrace " : [
" org.example.ExampleRestController.newIllegalArgument(ExampleRestController.java:100) " ,
" org.example.ExampleRestController.nestedThrowable(ExampleRestController.java:88) "
],
" cause " : {
" title " : " Internal Server Error " ,
" status " : 500,
" detail " : " Null Pointer " ,
" stacktrace " : [
" org.example.ExampleRestController.newNullPointer(ExampleRestController.java:104) " ,
" org.example.ExampleRestController.nestedThrowable(ExampleRestController.java:86) " ,
" sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) " ,
" sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) " ,
" sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) " ,
" java.lang.reflect.Method.invoke(Method.java:483) " ,
" org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) " ,
" org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) " ,
" org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) " ,
" org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) " ,
" org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) " ,
" org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) " ,
" org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) " ,
" org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) " ,
" org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) " ,
" org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) " ,
" org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) " ,
" org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) " ,
" org.junit.runners.ParentRunner.run(ParentRunner.java:363) " ,
" org.junit.runner.JUnitCore.run(JUnitCore.java:137) " ,
" com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117) " ,
" com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234) " ,
" com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74) "
]
}
}
} Springを使用すると、 @ControllerAdvice ControllerAdviceの範囲をコントローラーの特定のサブセットに制限できます。
@ ControllerAdvice ( assignableTypes = ExampleController . class )
public final class ExceptionHandling implements ProblemHandlingこれを行うことで、特定の種類の例外を処理する機能を失います。
HttpRequestMethodNotSupportedExceptionHttpMediaTypeNotAcceptableExceptionHttpMediaTypeNotSupportedExceptionNoHandlerFoundExceptionこの制限を春から継承するため、無制限の@ControllerAdviceを使用することをお勧めします。
質問、懸念、バグレポートなどがある場合は、このリポジトリの問題トラッカーに問題を提出してください。
貢献するには、単にプルリクエストを行い、追加または変更の簡単な説明(1〜2文)を追加します。詳細については、貢献ガイドラインを確認してください。