Masalah Spring Web adalah satu set perpustakaan yang memudahkan menghasilkan application/problem+json dari aplikasi Spring. Ini mengisi ceruk, karena menghubungkan perpustakaan masalah dan penanganan pengecualian Spring Web MVC atau penanganan pengecualian Spring Webflux sehingga mereka bekerja dengan mulus bersama, sambil membutuhkan upaya pengembang tambahan minimal. Dengan melakukan itu, ini bertujuan untuk melakukan tugas kecil namun berulang - sekali dan untuk semua.
Cara kerja perpustakaan ini didasarkan pada apa yang kami sebut ciri -ciri nasihat . Sifat saran adalah @ExceptionHandler kecil yang dapat digunakan kembali diimplementasikan sebagai metode default yang ditempatkan dalam antarmuka metode tunggal. Ciri -ciri saran tersebut dapat digabungkan secara bebas dan tidak perlu menggunakan kelas dasar umum untuk @ControllerAdvice Anda.
? Silakan periksa Baeldung: Panduan untuk Perpustakaan Web Spring Masalah untuk Pendahuluan Detail!
Proses penanganan masalah yang disediakan oleh AdviceTrait dibangun dengan cara yang memungkinkan untuk kustomisasi kapan pun diperlukan. Semua aspek berikut (dan banyak lagi) dapat disesuaikan dengan menerapkan antarmuka sifat saran yang sesuai:
| Aspek | Metode | Bawaan |
|---|---|---|
| Penciptaan | AdviceTrait.create(..) | |
| Logging | AdviceTrait.log(..) | 4xx sebagai WARN , 5xx sebagai ERROR termasuk jejak stack |
| Negosiasi konten | AdviceTrait.negotiate(..) | application/json , application/*+json , application/problem+json dan application/x.problem+json |
| Fallback | AdviceTrait.fallback(..) | application/problem+json |
| Pasca-pemrosesan | AdviceTrait.process(..) | n/a |
Contoh berikut menyesuaikan MissingServletRequestParameterAdviceTrait dengan menambahkan bidang ekstensi parameter ke Problem :
@ 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 ());
}
}Dengan asumsi ada pengontrol seperti ini:
@ 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 ();
}
}Permintaan HTTP berikut masing -masing akan menghasilkan respons yang sesuai:
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 "
}Sebelum Anda melanjutkan , silakan baca bagian tentang jejak tumpukan dan rantai kausal di Zalando/Masalah.
Jika Anda ingin mengaktifkan jejak tumpukan, harap konfigurasikan ProblemModule Anda sebagai berikut:
ObjectMapper mapper = new ObjectMapper ()
. registerModule ( new ProblemModule (). withStackTraces ());Rantai masalah akibat dinonaktifkan secara default , tetapi dapat ditimpa jika diinginkan:
@ ControllerAdvice
class ExceptionHandling implements ProblemHandling {
@ Override
public boolean isCausalChainsEnabled () {
return true ;
}
} Catatan Karena Anda memiliki akses penuh ke konteks aplikasi pada saat itu, Anda dapat mengeksternalisasi konfigurasi ke application.yml Anda.yml dan bahkan memutuskan untuk menggunakan kembali properti Spring's server.error.include-stacktrace .
Mengaktifkan kedua fitur, rantai kausal dan stacktraces, akan menghasilkan:
{
" 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 memungkinkan untuk membatasi ruang lingkup @ControllerAdvice ke subset pengontrol tertentu:
@ ControllerAdvice ( assignableTypes = ExampleController . class )
public final class ExceptionHandling implements ProblemHandlingDengan melakukan ini, Anda akan kehilangan kemampuan untuk menangani jenis pengecualian tertentu yaitu:
HttpRequestMethodNotSupportedExceptionHttpMediaTypeNotAcceptableExceptionHttpMediaTypeNotSupportedExceptionNoHandlerFoundException Kami mewarisi pembatasan ini dari musim semi dan karena itu merekomendasikan untuk menggunakan @ControllerAdvice yang tidak dibatasi.
Jika Anda memiliki pertanyaan, masalah, laporan bug, dll., Silakan ajukan masalah dalam pelacak masalah repositori ini.
Untuk berkontribusi, cukup buat permintaan tarik dan tambahkan deskripsi singkat (1-2 kalimat) dari penambahan atau perubahan Anda. Untuk detail lebih lanjut, periksa pedoman kontribusi.