강의

멘토링

로드맵

인프런 커뮤니티 질문&답변

갈색곰님의 프로필 이미지
갈색곰

작성한 질문수

스프링 MVC 2편 - 백엔드 웹 개발 활용 기술

@ControllerAdvice

GlobalException 클래스 설정 관련 문의

작성

·

53

·

수정됨

0

[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? 예
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예
3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예

[질문 내용]
안녕하세요.
영한님 강의를 듣고 한 가지 궁금한 점이 있습니다.

강의에서 "보다 디테일한 예외가 잡힌다"고 설명해주셨는데,
혹시 @Order(0) 설정을 하지 않으면 GlobalExceptionHandler에서만 예외가 처리가 잡히는데요,
즉, 예외 처리 클래스를 여러 개로 분리했다면 @Order를 지정하지 않으면 세부 예외 처리 핸들러가 아닌 글로벌 핸들러로만 잡히는 이유가 클래스 분리 때문인지 궁금합니다.

 

@RestControllerAdvice
@Order(0)
public class BoardExceptionHandler {

    /**
     * 게시판을 찾을 수 없을 때 발생하는 예외 처리
     */
    @ExceptionHandler(BoardNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleBoardNotFound(BoardNotFoundException ex) {
        ErrorResponse response = ErrorResponse.builder()
            .code("BOARD_NOT_FOUND")
            .message(ex.getMessage())
            .status(HttpStatus.NOT_FOUND.value())
            .timestamp(LocalDateTime.now())
            .details(Collections.singletonList("게시판 ID를 확인해주세요."))
            .build();

        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
    }

    /**
     * 게시판 수정 / 삭제 권한이 없을 때 발생하는 예외 처리
     */
    @ExceptionHandler(BoardPermissionDeniedException.class)
    public ResponseEntity<ErrorResponse> handleBoardPermissionDenied(BoardPermissionDeniedException ex) {
        ErrorResponse response = ErrorResponse.builder()
            .code("BOARD_PERMISSION_DENIED")
            .message(ex.getMessage())
            .status(HttpStatus.FORBIDDEN.value())
            .timestamp(LocalDateTime.now())
            .details(Collections.singletonList("해당 게시글에 대한 권한을 확인해주세요."))
            .build();

        return ResponseEntity.status(HttpStatus.FORBIDDEN).body(response);
    }
}
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 글로벌 예외 처리
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGenericException(Exception ex) {
        ErrorResponse response = ErrorResponse.builder()
            .code("INTERNAL_SERVER_ERROR")
            .message("서버에서 오류가 발생했습니다.")
            .status(HttpStatus.INTERNAL_SERVER_ERROR.value())
            .timestamp(LocalDateTime.now())
            .details(Collections.singletonList(ex.getClass().getName()))
            .build();

        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
    }
}

답변 2

2

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. 갈색곰님

둘다 글로벌로 지정되어 있다면 우선순위가 필요합니다.

대안은 다음과 같습니다.

  1. 두 컨트롤러를 합친다.

  2. @ControllerAdvice의 속성 (basePackages, annotations 등)을 사용해 적용 범위를 좁힌다.

2번과 같이 범위를 지정하면 Spring은 예외가 발생했을 때 다음과 같은 순서로 핸들러를 찾습니다.

  1. 가장 구체적인 핸들러 우선: Spring은 발생한 예외가 특정 컨트롤러나 패키지로 범위가 좁혀진 @RestControllerAdvice에 해당하는지 먼저 확인합니다.

  2. 전역 핸들러 확인: 만약 범위가 지정된 핸들러에서 해당 예외를 처리할 수 없다면, 그때 비로소 범위가 없는 전역 @RestControllerAdvice(GlobalExceptionHandler)를 확인합니다.

감사합니다.

갈색곰님의 프로필 이미지
갈색곰
질문자

답변 감사합니다 영한님 :)

0

안녕하세요, 인프런 AI 인턴입니다.
갈색곰님, 예외 처리 클래스에서 @Order 어노테이션을 사용하면 스프링에서 예외 처리를 위한 필터나 AOP 어드바이스의 실행 순서를 정할 수 있습니다. 예외 핸들러를 여러 개로 분리하여 사용하는 경우, @Order를 사용하여 순서를 지정하지 않는다면 기본 순서에 따라 처리가 이루어질 수 있습니다.

기본적으로, 스프링은 여러 개의 ExceptionHandler가 있을 때 보다 구체적인 예외 핸들러를 먼저 실행하며, 구체적인 예외 핸들러가 없는 경우 더 상위의 예외 핸들러로 처리를 이어나갑니다. 만약 @Order를 사용하지 않았다면 순서가 보장되지 않으며, 실행 순서는 주로 클래스 파일의 컴파일 순서나 등록 순서에 영향을 받을 수 있습니다. 따라서, @Order(0)를 설정해 줌으로써 해당 예외 핸들러가 높은 우선순위로 적용되도록 보장하는 것입니다.

이와 관련하여, 스프링 문서의 “Web > Servlet Web Applications > The “Spring Web MVC Framework” > Error Handling” 섹션을 참고하시면 더 많은 정보를 얻으실 수 있습니다:
Spring Boot Reference Document - Error Handling

추가적인 질문이 있다면 언제든지 문의해 주세요!

갈색곰님의 프로필 이미지
갈색곰
질문자

'스프링은 여러 개의 ExceptionHandler가 있을 때 보다 구체적인 예외 핸들러를 먼저 실행하며, 구체적인 예외 핸들러가 없는 경우 더 상위의 예외 핸들러로 처리를 이어나갑니다.'
이렇게 답변했는데, 위의 BoardExceptionHandler 클래스의 경우, Excpetion 의 자식 예외인 RuntimeException 으로 설정하고, GlobalExceptionHandler 클래스는 Exception 으로 설정했는데 @Order(0)을 설정하지 않으면 모두 GlobalException 으로 잡혀서 핸들러 클래스를 나누면 @Order(0)을 구현하는게 필수인지 궁금합니다.

갈색곰님의 프로필 이미지
갈색곰

작성한 질문수

질문하기