문제 스프링 웹은 스프링 애플리케이션에서 application/problem+json 응답을 쉽게 생성 할 수있는 라이브러리 세트입니다. 문제 라이브러리와 스프링 웹 MVC의 예외 처리 또는 스프링 웹 플럭스의 예외 처리를 연결하여 최소한의 추가 개발자 노력이 필요합니다. 그렇게함으로써 작지만 반복적 인 작업을 한 번에 수행하는 것을 목표로합니다.
이 도서관의 작동 방식은 우리가 조언 특성 이라고 부르는 것에 기초합니다. 조언 특성은 단일 메소드 인터페이스에 배치 된 기본 메소드로 구현 된 작고 재사용 가능한 @ExceptionHandler 입니다. 이러한 조언 특성은 자유롭게 결합 될 수 있으며 @ControllerAdvice 에 공통 기본 클래스를 사용할 필요는 없습니다.
? 자세한 소개를 위해 Baeldung : The Problem Spring Web Library에 대한 안내서를 확인하십시오!
AdviceTrait 에서 제공하는 문제 처리 프로세스는 필요할 때마다 사용자 정의를 허용하는 방식으로 구축됩니다. 다음과 같은 모든 측면 (및 그 이상)은 적절한 조언 트레이트 인터페이스를 구현하여 사용자 정의 할 수 있습니다.
| 측면 | 행동 양식) | 기본 |
|---|---|---|
| 창조 | AdviceTrait.create(..) | |
| 벌채 반출 | AdviceTrait.log(..) | 4xx WARN , 스택 추적을 포함한 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/Problem의 스택 트레이스 및 인과 체인 에 대한 섹션을 읽으십시오.
스택 추적을 활성화하려면 다음과 같이 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 ( assignableTypes = ExampleController . class )
public final class ExceptionHandling implements ProblemHandling이렇게하면 특정 유형의 예외를 처리 할 수있는 기능이 느슨해집니다.
HttpRequestMethodNotSupportedExceptionHttpMediaTypeNotAcceptableExceptionHttpMediaTypeNotSupportedExceptionNoHandlerFoundException 우리는이 제한을 봄부터 상속하므로 무제한 @ControllerAdvice 사용하는 것이 좋습니다.
질문, 우려, 버그 보고서 등이 있으면이 저장소의 문제 추적기에 문제를 제기하십시오.
기여하려면 단순히 풀 요청을 작성하고 추가 또는 변경에 대한 간단한 설명 (1-2 문장)을 추가하십시오. 자세한 내용은 기여 지침을 확인하십시오.