본문 바로가기

Back/Spring

[에러-잡기] @ExceptionHandler를 통한 예외 처리

에러 핸들링에 대해서 공부하는 와중에 정말로 이해하고 쉬운 예시를 보여주는 블로그를 찾았다.

이론 정리도 할 겸 해당 블로그 주소와 함께 예시를 가져와 봤음.

스프링 공식 문서를 정리한 것이라고 한다.

@ExceptionHandler를-통한-예외처리

 

[스프링부트] @ExceptionHandler를 통한 예외처리

@ExceptionHandler는 Controller계층에서 발생하는 에러를 잡아서 메서드로 처리해주는 기능이다.Service, Repository에서 발생하는 에러는 제외한다.간단한 예시부터 살펴보자.이렇게 @Controller로 선언된 클

velog.io

 

 

큰 틀에서 보자면 기존 방식 >> 새로운 방식으로 전환하는 방향으로 예시가 적혀있다.

컨트롤러 내부에서 발생한 에러를 컨트롤러에서 매번 처리하기 보다는, 예외 처리 클래스를 구성해서 처리하는 방식이다.

 

리팩토링 순서를 이렇게 된다.

 

  1. 에러 발생 시 보낼 정보를 담는 DTO를 생성
  2. 에러 코드를 처리할 ENUM 클래스를 생성
  3. 에러를 담당할 개별 예외 처리 클래스를 생성
  4. 전역적으로 예외 처리를 담당할 전역 예외 처리 클래스를 생성하여 개별 예외 처리 클래스를 주입

 

1. DTO

글에는 적혀 있지 않지만 이런 방식일 것이라고 추측했다.

@AllArgsConstructor
@Getter
@Setter
public class ErrorDto {

    private int status;
    private String message;
}

 

 

2. Enum

일단 Enum 클래스에는 @Setter를 안 붙여주는 것도 인상적이다. 확실히 외부에서 변경할 이유가 없긴 하다.

눈여겨 봐야할 점은 404 에러는 다양한 경우의 수를 상정했다는 점이다.

@AllArgsConstructor
@Getter
public enum ErrorCode {

    //400 BAD_REQUEST 잘못된 요청
    INVALID_PARAMETER(400, "파라미터 값을 확인해주세요."),
    
    //404 NOT_FOUND 잘못된 리소스 접근
    DISPLAY_NOT_FOUND(404, "존재하지 않는 전시회 ID 입니다."),
    FAIR_NOT_FOUND(404, "존재하지 않는 박람회 ID 박람회입니다."),
    FESTIVAL_NOT_FOUND(404, "존재하지 않는 페스티벌 ID 페스티벌입니다."),
    
    // ... write something
    
    private final int status;
    private final String message;
}

 

3. CustomException Class

해당 클래스는 위처럼 404 에러를 다양한 경우로 잡을 경우 필요한 클래스다.

기본 제공되는 404 에러 외에도 이것이 정의된 에러라는 것을 알려야 하기 때문인 듯하다.

전역 예외 처리 클래스에서는 이 클래스를 사용한다.

@AllArgsConstructor
@Getter
public class CustomException extends RuntimeException {
    private final ErrorCode errorCode;
}

 

4. Global Exception Class

에러 발생 시 반환할 값으로 에러 코드(status), 에러 내용(message), 처리 결과(httpStatus) 세 개가 설정됐다.

HttpStatus는 별도로 String 타입으로 치환했던데 이 부분을 인지해야겠다.

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler({ CustomException.class })
    protected ResponseEntity handleCustomException(CustomException ex) {
        return new ResponseEntity(new ErrorDto(ex.getErrorCode().getStatus(), ex.getErrorCode().getMessage()), HttpStatus.valueOf(ex.getErrorCode().getStatus()));
    }

    @ExceptionHandler({ Exception.class })
    protected ResponseEntity handleServerException(Exception ex) {
        return new ResponseEntity(new ErrorDto(INTERNAL_SERVER_ERROR.getStatus(), INTERNAL_SERVER_ERROR.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
    }
}