개발 일지

exception handler 도입기

B.E Dev 2024. 3. 1. 19:59

1. 문제 상황

💡 excepiton이 발생할 때 response가 읽기 힘든 형태로 내려짐
  • OS: MacOs
  • 기타 정보 : Java 17, Spring Boot 2.7.9

1. exception 발생

@GetMapping("/exception")
public void throwException() {
    throw new RuntimeException("테스트 에러 발생");
}

2. 에러 메세지가 아래와 같이 리턴됨

기본 에러 response가 한 눈에 보기 어려운 형태로 되어있어 exception handler를 정의할 필요성을 느끼게 되었습니다.


2. 해결 방법

@ControllerAdvice를 사용하여 에러를 처리

@ControllerAdvice란?

@ControllerAdvice는 Spring MVC에서 예외 처리를 담당하는 어노테이션입니다. 이 어노테이션을 사용하면 전역적으로 예외를 처리할 수 있는 클래스를 정의할 수 있습니다. 이 클래스에서는 @ExceptionHandler를 사용하여 특정 예외에 대한 처리 방법을 지정할 수 있습니다.

 

@ControllerAdvice를 사용한 exception handler 구현

1
Response dto 생성
@Getter
public class ExceptionResponse {

    private final String message;
    private final int status;
    private final HttpStatus error;
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    private final LocalDateTime timestamp;

    public ExceptionResponse(String message, HttpStatus httpStatus) {
        this.message = "[ERROR] " + message;
        this.status = httpStatus.value();
        this.error = httpStatus;
        this.timestamp = LocalDateTime.now();
    }
}

 

이번 예제에서 쓸 에러 메세지의 format은 위와 같습니다.

 

2
@ControllerAdvice로 Exception Handler 구현
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    public ResponseEntity<Object> handleMethodArgumentNotValidException(
            MethodArgumentNotValidException e) {
        HttpStatus status = HttpStatus.BAD_REQUEST;
        BindingResult bindingResult = e.getBindingResult();
        List<FieldError> fieldErrors = bindingResult.getFieldErrors();
        List<String> errorMessages = new ArrayList<>();

        for (FieldError fieldError : fieldErrors) {
            String errorMessage = fieldError.getField() + ": " + fieldError.getDefaultMessage();
            errorMessages.add(errorMessage);
        }

        ExceptionResponse response = new ExceptionResponse(errorMessages.toString(),
                status);

        return new ResponseEntity<>(response, status);
    }
}

 

@ControllerAdvice를 붙인 클래스를 정의해주시면 됩니다.

위의 코드는 폼 유효성 검사나 DTO 객체의 유효성 검사를 통과하지 못했을 때 발생하는 에러를 핸들링하는 코드입니다.

 

번외
feign client로 받은 오류 처리
@ExceptionHandler(FeignException.class)
public ResponseEntity feignExceptionHandler(FeignException e) throws JsonProcessingException {
    String responseJson = e.contentUTF8();
    Map<String, String> responseMap = objectMapper.readValue(responseJson, Map.class);

    return new ResponseEntity<>(responseMap, HttpStatus.valueOf(e.status()));
}

 

이렇게 하면 feign client로 받은 에러 response를 그대로 내려줄 수 있게 됩니다.

 

마치며

이번 글에서는 Spring 프로젝트에서 exception handler를 정의하고 에러메세지를 전역적으로 처리하는 방법에 대해 알아봤습니다.