스프링 부트의 예외 처리 방식
- 웹 서비스 애플리케이션에서는 외부에서 들어오는 요청에 담긴 데이터를 처리하는 경우가 많다.
- 그 과정에서 예외가 발생하면 예외를 복구해서 정상으로 처리하기보다는 요청을 보낸 클라이언트에 어떤 문제가 발생했는지 전달하는 경우가 많다.
예외가 발생했을 때 클라이언트에 오류 메시지를 전달하려면 각 레이어에서 발생한 예외를 엔드포인트 레벨인 컨트롤러로 전달해야 한다. 이렇게 전달받은 예외를 스프링 부트에서 처리하는 방식으로 크게 두 가지가 있다.
(Rest)ControllerAdvice
와@ExceptionHandler
를 통해 모든 컨트롤러의 예외를 처리ExceptionHandler
를 통해 특정 컨트롤러의 예외를 처리
@RestControllerAdvice
@RestController
@RequestMapping("/exception")
public class ExceptionController {
private final Logger LOGGER = LoggerFactory.getLogger(ExceptionController.class);
@GetMapping
public void getRuntimeException() {
throw new RuntimeException("getRuntimeException 메소드 호출");
}
@ExceptionHandler(value = RuntimeException.class)
public ResponseEntity<Map<String, String>> handleException(RuntimeException e,
HttpServletRequest request) {
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpStatus httpStatus = HttpStatus.BAD_REQUEST;
LOGGER.error("클래스 내 handleException 호출, {}, {}", request.getRequestURI(),
e.getMessage());
Map<String, String> map = new HashMap<>();
map.put("error type", httpStatus.getReasonPhrase());
map.put("code", "400");
map.put("message", e.getMessage());
return new ResponseEntity<>(map, responseHeaders, httpStatus);
}
@ControllerAdvice
나 @RestControllerAdvice
는 @Controller
나 @RestController
에서 발생하는 예외를 한 곳에서 관리하고 처리할 수 있게 하는 기능을 수행한다.
@ControllerAdvice
와 @RestControllerAdvice
의 차이는 @RestControllerAdvice
는 결괏값을 JSON 형태로 반환한다.
다음과 같이 별도 설정을 통해 예외를 관제하는 범위를 지정할 수도 있다.@RestControllerAdvice(basePackages = "com.springboot.valid_exception")
범위를 설정하지 않으면 전역 범위에서 예외를 처리하게 된다.
@ExceptionHandler
는 @Controller
나 @RestController
가 적용된 Bean에서 발생하는 예외를 찾아 처리하는 메서드를 정의할 때 사용한다.
어떤 예외 클래스를 처리할지는 value
속성으로 등록한다. value
는 배열 형식으로도 전달받을 수 있어 여러 예외 클래스를 등록할 수도 있다.
위 예제에서는 RuntimeException
이 발생하면 처리하도록 코드가 작성되어 있다.
그리고 Map
객체에 응답할 메시지를 구성하고 ResponseEntity
에 HttpHeader
, HttpStatus
, Body
값을 담아 전달한다.
위 핸들러 메서드는 다음과 같은 응답을 출력합니다.
{
"code": "400",
"error type": "Bad Request",
"message": "getRuntimeException 메소드 호출"
}
예외 타입 레벨에 따른 예외 처리 우선순위
만약 컨트롤러 또는 @ControllerAdvice
클래스 내에 동일하게 핸들러 메서드가 선언된 상태에서는 위 그림 처럼 더 구체적인 구현이 있는 예외 클래스가 우선순위를 갖게 된다.
다른 경우로는 다음과 같은 상황이 있다.
@ControllerAdvice의 글로벌 예외 처리와 @Controller 내의 컨트롤러 예외 처리에 동일한 타입의 예외 처리를 하게 되면 범위가 좁은 컨트롤러의 핸들러 메서드가 우선순위를 갖게 된다.
참고
- 스프링 부트 핵심 가이드 "스프링 부트를 활용한 애플리케이션 개발 실무" , 장정우, 2022
- https://github.com/kimjinmyeong/capstone-2023-40/tree/develop/api/src/main/java/com/thesurvey/api/exception
'Development > Spring' 카테고리의 다른 글
[Spring] 서버 간 통신하기: RestTemplate (0) | 2024.03.19 |
---|---|
[Spring] 스프링 액추에이터(Actuator) (0) | 2024.03.10 |
[Spring] 유효성 검사와 Hibernate Validator (0) | 2024.03.07 |
[Spring] 영속성 전이(Cascade)와 고아 객체(Orphan) (0) | 2024.03.05 |
[Spring] 연관 관계 매핑하기 (1) | 2024.03.05 |