본문 바로가기
Spring

ExceptionHandler / ControllerAdvice 사용법

by 리승우 2022. 11. 3.

<참고이미지1>

 

@ExceptionHandeler

> 해당하는 컨트롤러에서 예외 발생 시, 해당하는 클래스의 에러를 잡는 역할을 한다. 

그 후 지정해놓은 메소드가 호출되며 처리가 된다. + 지정한 예외 또는 예외의 자식 클래스는 모두 잡을 수 있다.

 

> 추가 사항

해당 작업만을 진행하고 Postman으로 출력할 시 우측 상단의 Http상태코드값은 200 (정상출력코드) 으로 나올 것이다. 

이는 당연한 것이다. 에러를 잡았다한들, 그 처리에 대한 출력을 정상적으로 했기 때문이다. 

 

혹여 전달하는 Http 상태값 또한 오류에 대한 정보로 기재하여 출력하고 싶을 때는 

참고이미지1의 2개 사례와 같이 

 

@ResponseStatus(HttpStatus.BAD_REQUEST 

혹은

ResponseEntity(~~~, HttpStatus.BAD_REQUEST)를 활용하면 된다. 

 

하지만, 위와 같은 방법들은 개별적으로 에러코드 및 메시지를 지정해줘야한다. 

그러니, 재사용성을 강화하기 위해 아래와 같이 enum클래스로 에로코드를 명시해 둔 뒤

@Getter
@AllArgsConstructor
public enum ErrorCode {

    
    UNAUTHORIZED_401(HttpStatus.UNAUTHORIZED, "권한이 없습니다."),

    // 날짜 입력 오류
    DateTimeException_400(HttpStatus.BAD_REQUEST, "잘못된 날짜입니다."),

    /*
     * 해당 주석 위로 enum 코드 추가 바랍니다.
     * 코드 추가시 간편하게 진행하기 위해 생성한 미사용 코드입니다. 사용하지마세요.
     * 생성이유 : enum 마지막 요소에 ; 을 입력해야하기에, 끝부분에 추가하게 될 경우 ; 을 재입력해야함
     */
    DO_NOT_USED(null, null);


    private final HttpStatus httpStatus;
    private final String message;
}

 

아래와 같은 에러가 발생하면, 

RequestException 을 생성하는 코드를 작성한다. (파라미터는 ErrorCode내용으로 준다) 

private Folder folderObject(Long id) {
    return folderRepository.findById(id).orElseThrow(
            () -> new RequestException(ErrorCode.FOLDER_ID_NOT_FOUND_404)
    );
}

 

RequestException 생성자는 아래와 같은 로직으로 작동한다. 

해당 클래스는 RuntimeException을 상속받는다. 

그 후 ErrorCode를 매개변수로 받아 값을 초기화한다.

@Getter
public class RequestException extends RuntimeException{
    private final HttpStatus httpStatus;

    public RequestException(ErrorCode errorCode) {
        super(errorCode.getMessage());
        this.httpStatus = errorCode.getHttpStatus();
    }
}

 

@ControllerAdvice에서 RequestException에 해당하는 (RuntimeException 예외인 것들은)

예외들을 @ExceptionHandler 메소드에 따라 처리한다. 

 

ResponseDto.fails가 발생할 시, RequestException의 Status, Message값을 받아온다.

@RestControllerAdvice
public class RestApiExceptionHandler {
    @ExceptionHandler(value = { RequestException.class })
    public ResponseEntity<ResponseDto<Object>> handleApiRequestException(RequestException e) {

        return new ResponseEntity<>(ResponseDto.fails(e.getHttpStatus(), e.getMessage()),
                e.getHttpStatus()
        );
    }
}

 

ResponseDto.fails가 발생할 시, 매개변수로 RequestException의 HttpStatus, Message가 주어지며,

위 데이터가 Error 클래스 객체생성에 사용된다.

해당 데이터는 ResponseEntity의 데이터로 추가된다. 

    public static <T> ResponseDto<T> fails(HttpStatus httpStatus, String message) {
        return new ResponseDto<>(false, null, new Error(httpStatus,message));
    }
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Error {
    private HttpStatus httpStatus;
    private String message;
}

 

 

@RestControllerAdvice

> 여러 컨트롤러단에서 발생한 예외를 모아서 처리할 수 있는 컨트롤러 구역

@ControllerAdvice는 대상으로 지정한 여러 컨트롤러에 @ExceptionHandler, @InitBinder 기능을 부여해주는 역할을 한다.

특정클래스, 특정 애노테이션이 있는 컨트롤러, 특정 패키지를 직접 지정하여 적용할 수 있다.

지정을 생략하면 모든 컨트롤러에 적용된다.

 

 

해당 구역에 @ExceptionHandler를 모두 옮겨서 예외를 처리한다. 

 

최종정리

@ExceptionHandler 와 @ControllerAdvice를 조합하면 예외를 깔끔하게 해결할 수 있다. 

'Spring' 카테고리의 다른 글

JOIN종류 / ON절의 의미 / Query 조회기능 최적화 팁  (0) 2022.11.07
Elasticsearch란? (작성중)  (0) 2022.11.05
WebSocket / STOMP  (1) 2022.10.28
querydsl 사용법!  (0) 2022.10.27
Spring. Filter/Interceptor  (0) 2022.10.13

댓글