Loading...
Spring Framework Reference Documentation 7.0.2의 Exceptions의 한국어 번역본입니다.
아래의 경우에 피드백에서 신고해주신다면 반영하겠습니다.
감사합니다 :)
See equivalent in the Reactive stack
@Controller 및 @ControllerAdvice 클래스는 다음 예제에서 보는 것처럼 controller 메서드로부터의 exception을 처리하기 위한
@ExceptionHandler 메서드를 가질 수 있습니다:
1import java.io.IOException; 2 3import org.springframework.http.ResponseEntity; 4import org.springframework.stereotype.Controller; 5import org.springframework.web.bind.annotation.ExceptionHandler; 6 7@Controller 8public class SimpleController { 9 10 @ExceptionHandler(IOException.class) 11 public ResponseEntity<String> handle() { 12 return ResponseEntity.internalServerError().body("Could not read file storage"); 13 } 14 15}
1import org.springframework.http.ResponseEntity 2import org.springframework.stereotype.Controller 3import org.springframework.web.bind.annotation.ExceptionHandler 4import java.io.IOException 5 6@Controller 7class SimpleController { 8 9 @ExceptionHandler(IOException::class) 10 fun handle() : ResponseEntity<String> { 11 return ResponseEntity.internalServerError().body("Could not read file storage") 12 } 13 14}
exception은 top-level exception이 전파되는 것과 매칭될 수 있습니다(예를 들어, 직접적으로
IOException이 발생하는 경우) 또는 wrapper exception 안의 nested cause와 매칭될 수 있습니다(예를 들어,
IllegalStateException 안에 감싸진 IOException). 5.3부터는, 이전에는 immediate cause만 고려되던 것과 달리,
임의의 cause level에서 매칭될 수 있습니다.
exception 타입을 매칭하기 위해서는, 앞선 예제에서 보는 것처럼 target exception을 메서드 argument로 선언하는 것이 바람직합니다. 여러 exception 메서드가 매칭되는 경우, root exception 매칭이 일반적으로 cause exception 매칭보다 선호됩니다.
보다 구체적으로는, ExceptionDepthComparator가
발생한 exception 타입으로부터의 depth를 기준으로 exception을 정렬하는 데 사용됩니다.
대안으로, annotation 선언에서 매칭할 exception 타입을 좁힐 수도 있습니다. 다음 예제에서 보는 것처럼 말입니다:
1@ExceptionHandler({FileSystemException.class, RemoteException.class}) 2public ResponseEntity<String> handleIoException(IOException ex) { 3 return ResponseEntity.internalServerError().body(ex.getMessage()); 4}
1@ExceptionHandler(FileSystemException::class, RemoteException::class) 2fun handleIoException(ex: IOException): ResponseEntity<String> { 3 return ResponseEntity.internalServerError().body(ex.message) 4}
다음 예제에서 보는 것처럼, 매우 generic한 argument signature와 함께 특정 exception 타입의 list를 사용할 수도 있습니다:
1@ExceptionHandler({FileSystemException.class, RemoteException.class}) 2public ResponseEntity<String> handleExceptions(Exception ex) { 3 return ResponseEntity.internalServerError().body(ex.getMessage()); 4}
1@ExceptionHandler(FileSystemException::class, RemoteException::class) 2fun handleExceptions(ex: Exception): ResponseEntity<String> { 3 return ResponseEntity.internalServerError().body(ex.message) 4}
root exception 매칭과 cause exception 매칭의 구분은 놀라울 수 있습니다. 앞서 보여준
IOExceptionvariant에서, 메서드는 일반적으로 argument로 실제FileSystemException또는RemoteException인스턴스와 함께 호출됩니다. 이 둘 모두가IOException을 상속하기 때문입니다. 그러나 이러한 매칭되는 exception이IOException자체인 wrapper exception 안에서 전파되는 경우, 넘겨지는 exception 인스턴스는 그 wrapper exception입니다.handle(Exception)variant에서는 동작이 더 단순합니다. wrapping 시나리오에서는 항상 wrapper exception과 함께 호출되며, 실제로 매칭되는 exception은 그 경우ex.getCause()를 통해 찾아야 합니다. 넘겨지는 exception은 이러한 exception이 top-level exception으로 발생할 때에만 실제FileSystemException또는RemoteException인스턴스입니다.
일반적으로 argument signature에서 가능한 한 구체적으로 작성하여,
root와 cause exception 타입 사이의 mismatch 가능성을 줄이기를 권장합니다.
multi-matching 메서드를 signature를 통해 각각 하나의 특정 exception 타입과 매칭되는
개별 @ExceptionHandler 메서드로 나누는 것을 고려하십시오.
multi-@ControllerAdvice 구성에서, 해당 order와 함께 우선순위를 가진 @ControllerAdvice에
primary root exception 매핑을 선언하는 것을 권장합니다. root exception 매칭이
cause보다 선호되지만, 이는 주어진 controller 또는 @ControllerAdvice 클래스의
메서드들 사이에서 정의됩니다.
이는 더 높은 우선순위를 가진 @ControllerAdvice bean에서의
cause 매칭이 더 낮은 우선순위의 @ControllerAdvice bean에서의 어떤 매칭(예를 들어, root)보다
선호된다는 것을 의미합니다.
마지막으로, @ExceptionHandler 메서드 구현은 exception 인스턴스를 원래 형태로
다시 던짐으로써 주어진 exception 인스턴스를 처리하는 것을 포기하도록 선택할 수 있습니다.
이는 root-level 매칭에만 관심이 있거나, 정적으로는 결정할 수 없는 특정 context 내의
매칭에만 관심이 있는 시나리오에서 유용합니다.
다시 던져진 exception은
해당 @ExceptionHandler 메서드가 처음부터 매칭되지 않았던 것처럼 남은 resolution chain을 통해
전파됩니다.
Spring MVC에서 @ExceptionHandler 메서드에 대한 지원은 DispatcherServlet
레벨의 HandlerExceptionResolver 메커니즘 위에 구축되어 있습니다.
See equivalent in the Reactive stack
exception 타입뿐만 아니라, @ExceptionHandler 메서드는 producible media 타입도 선언할 수 있습니다.
이것은 일반적으로 HTTP 클라이언트의 "Accept" HTTP 요청 헤더에서 요청된 media 타입에 따라 error response를
세분화할 수 있게 해줍니다.
애플리케이션은 동일한 exception 타입에 대해 annotation에 직접 producible media 타입을 선언할 수 있습니다:
1@ExceptionHandler(produces = "application/json") 2public ResponseEntity<ErrorMessage> handleJson(IllegalArgumentException exc) { 3 return ResponseEntity.badRequest().body(new ErrorMessage(exc.getMessage(), 42)); 4} 5 6@ExceptionHandler(produces = "text/html") 7public String handle(IllegalArgumentException exc, Model model) { 8 model.addAttribute("error", new ErrorMessage(exc.getMessage(), 42)); 9 return "errorView"; 10}
1@ExceptionHandler(produces = ["application/json"]) 2fun handleJson(exc: IllegalArgumentException): ResponseEntity<ErrorMessage> { 3 return ResponseEntity.badRequest().body(ErrorMessage(exc.message, 42)) 4} 5 6@ExceptionHandler(produces = ["text/html"]) 7fun handle(exc: IllegalArgumentException, model: Model): String { 8 model.addAttribute("error", ErrorMessage(exc.message, 42)) 9 return "errorView" 10}
여기서, 메서드는 동일한 exception 타입을 처리하지만 duplicate로 거부되지 않습니다. 대신, "application/json"을 요청하는 API 클라이언트는 JSON error를 받게 되고, browser는 HTML error view를 받게 됩니다.
각각의 @ExceptionHandler annotation은 여러 producible media 타입을 선언할 수 있으며,
error handling phase 동안의 content negotiation이 어떤 content 타입이 사용될지를 결정합니다.
See equivalent in the Reactive stack
@ExceptionHandler 메서드는 다음 argument를 지원합니다:
| Method argument | Description |
|---|---|
| Exception 타입 | 발생한 exception에 접근하기 위한 것입니다. |
HandlerMethod | exception을 발생시킨 controller 메서드에 접근하기 위한 것입니다. |
WebRequest, NativeWebRequest | Servlet API를 직접 사용하지 않고도 요청 parameter 및 요청과 session attribute에<br>일반적으로 접근하기 위한 것입니다. |
jakarta.servlet.ServletRequest, jakarta.servlet.ServletResponse | 특정 요청 또는 response 타입을 선택합니다(예를 들어, ServletRequest 또는<br>HttpServletRequest 또는 Spring의 MultipartRequest 또는 MultipartHttpServletRequest). |
jakarta.servlet.http.HttpSession | session의 존재를 강제합니다. 그 결과, 이러한 argument는 절대 null이 아닙니다.<br>session access는 thread-safe하지 않다는 점에 유의하십시오.<br>여러 요청이 동시에 session에 접근하는 것이 허용되는 경우,<br>RequestMappingHandlerAdapter 인스턴스의 synchronizeOnSession 플래그를 true로 설정하는 것을 고려하십시오. |
java.security.Principal | 현재 인증된 사용자 — 알려진 경우 특정 Principal 구현 클래스일 수도 있습니다. |
| HttpMethod | 요청의 HTTP 메서드입니다. |
java.util.Locale | 사용 가능한 가장 구체적인 LocaleResolver에 의해 결정된 현재 요청 locale입니다 —<br>사실상, 설정된 LocaleResolver 또는 LocaleContextResolver입니다. |
java.util.TimeZone, java.time.ZoneId | LocaleContextResolver에 의해 결정된, 현재 요청과 연관된 time zone입니다. |
java.io.OutputStream, java.io.Writer | Servlet API에 의해 노출되는 raw response body에 접근하기 위한 것입니다. |
java.util.Map, org.springframework.ui.Model, org.springframework.ui.ModelMap | error response를 위한 model에 접근하기 위한 것입니다. 항상 비어 있습니다. |
RedirectAttributes | redirect 시 사용할 attribute(즉, query string에 추가될 attribute)와 redirect 이후의 요청까지<br>임시로 저장될 flash attribute를 지정합니다.<br>Redirect Attributes 및 Flash Attributes를 참조하십시오. |
@SessionAttribute | class-level @SessionAttributes 선언의 결과로 session에 저장된 model attribute와는 대조적으로,<br>어떤 session attribute에든 접근하기 위한 것입니다.<br>자세한 내용은 @SessionAttribute를 참조하십시오. |
@RequestAttribute | 요청 attribute에 접근하기 위한 것입니다. 자세한 내용은<br>@RequestAttribute를 참조하십시오. |
See equivalent in the Reactive stack
@ExceptionHandler 메서드는 다음과 같은 return value를 지원합니다:
| Return value | Description |
|---|---|
@ResponseBody | return value는 HttpMessageConverter 인스턴스를 통해 변환되고 response에<br>작성됩니다. @ResponseBody를 참조하십시오. |
HttpEntity<B>, ResponseEntity<B> | return value는 전체 response(HTTP 헤더와 body 포함)가<br>HttpMessageConverter 인스턴스를 통해 변환되고 response에 작성되어야 함을 지정합니다.<br>ResponseEntity를 참조하십시오. |
ErrorResponse, ProblemDetail | body에 상세 정보를 포함하는 RFC 9457 error response를 렌더링하기 위한 것입니다.<br>Error Responses를 참조하십시오. |
String | ViewResolver 구현으로 resolve되어 implicit model과 함께 사용될 view name입니다 —<br>implicit model은 command 객체 및 @ModelAttribute 메서드를 통해 결정됩니다.<br>handler 메서드는 또한 Model argument를 선언함으로써(앞에서 설명한) programmatically하게<br>model을 확장할 수도 있습니다. |
View | command 객체 및 @ModelAttribute 메서드를 통해 결정되는 implicit model과 함께<br>렌더링에 사용할 View 인스턴스입니다. handler 메서드는 또한 Model argument를<br>선언함으로써(앞에서 설명한) programmatically하게 model을 확장할 수 있습니다. |
java.util.Map, org.springframework.ui.Model | implicit model에 추가될 attribute로, view name은<br>RequestToViewNameTranslator를 통해 암묵적으로 결정됩니다. |
@ModelAttribute | view name이 RequestToViewNameTranslator를 통해 암묵적으로 결정되는,<br>model에 추가될 attribute입니다.<br>@ModelAttribute는 optional이라는 점에 유의하십시오. 이 table의 마지막에 있는<br>“Any other return value”를 참조하십시오. |
ModelAndView 객체 | 사용할 view와 model attribute 및 선택적으로 response status입니다. |
void | void return 타입(또는 null return value)을 가진 메서드는 ServletResponse, OutputStream argument<br>또는 @ResponseStatus annotation도 가지고 있는 경우 response를 완전히 처리한 것으로 간주됩니다.<br>controller가 positive한 ETag 또는 lastModified timestamp check를 수행한 경우에도<br>마찬가지입니다(자세한 내용은 Controllers를 참조하십시오).<br>위의 어느 것도 해당되지 않는 경우, void return 타입은 REST controller의 경우 “no response body”를,<br>HTML controller의 경우 default view name selection을 의미할 수도 있습니다. |
| Any other return value | return value가 위의 어느 것과도 매칭되지 않고(simple 타입이 아니며<br>BeanUtils#isSimpleProperty에 의해 결정됨),<br>기본적으로 model에 추가될 model attribute로 취급됩니다. simple 타입인 경우에는<br>resolve되지 않은 상태로 남습니다. |
Validation
Controller Advice