inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

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

@ControllerAdvice

GlobalException 클래스 설정 관련 문의

85

갈색곰

작성한 질문수 10

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);
    }
}

spring mvc

답변 2

2

김영한

안녕하세요. 갈색곰님

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

대안은 다음과 같습니다.

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

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

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

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

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

감사합니다.

2

갈색곰

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

0

인프런 AI 인턴

안녕하세요, 인프런 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

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

0

갈색곰

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

이미지 업로드와 db 트랜잭션 묶는법

0

43

1

Could not resolve org.springframework.boot:spring-boot-starter-validation:2.4.4

0

53

2

MessageSourceTest 코드

0

47

1

인터셉터 에러 설정

0

48

1

resolveArgument()메서드 질문

0

57

1

43강 검증1 에서 실패 로직 관련 질문있습니다.

0

57

2

타임리프 3.X 버전 rendering, serializer 에러 해결 방법

2

133

3

스프링 빈에 등록이 안되는거 같은데 어떻게 하면 좋을까요?ㅠㅠ

0

90

3

pdf 오타 문의

0

57

1

ItemUpdateForm 검증 관련 질문입니다.

0

48

1

22page 링크 주소 변경

0

59

2

특정 데이터와 파일을 함께 저장 시, 테이블 구조 질문

0

53

1

섹션3번 수업에 대한 질문입니다.

0

80

2

@Autowired 보다 더 좋은 방법이 어떤 걸까요?

0

85

2

타입컨버터 가 람다랑 비슷해 보이는데 저의 생각이 맞는지?.

0

65

1

자바스크립트 인라인에서 객체 직렬화 시 오류가 납니다

0

142

3

스프링부트 - 오류페이지2 에서 500.html 에서 쓰인 객체 질문

0

63

1

톰캣 에러 페이지가 안보입니다.

0

103

2

apiEceptionController에서 센드 에러 호출하면 안되는지?

0

81

1

세션 타임아웃시 쿠키 삭제 방법이 없나요?

0

118

2

ApiExceptionController 질문드립니다.

0

64

1

셀렉박스 챕터에서 option value에 ==배송 방식 선택== 이것을 넣은 이유가 궁금함, 이렇게 구상해도 되는지?

0

66

1

MemberRepository 필드의 fianl 선언 유무

0

85

2

혹시 index.html 에서는 fragment 사용이 안되는건가요

0

58

1