본문 바로가기
Spring

@RestControllerAdvice 예외 처리

by setung 2021. 10. 31.

기본적으로 스프링은 요청에 대해서 예외가 발생하면 Whitelabel Error Page가 보여진다 

하지만 일반 사용자한테 저런 에러 페이지를 보여주는 것보다 의미 있는(?), 알 수 있는 문구를 보여주면 좋을 것이다.

 

스프링에서는 @RestControllerAdvic를 사용해서 예외를 깔끔하게 처리할 수 있다. 

예외가 발생하면 미리 정의해놓은 응답으로 보낼 수 있다.

 

간단하게 예제를 만들어 보겠다.

ErrorCode

@RequiredArgsConstructor
@Getter
public enum ErrorCode {

    NOT_FOUND_USER(HttpStatus.NOT_FOUND, "회원을 찾을 수 없습니다."),
    NEED_TO_LOGIN(HttpStatus.UNAUTHORIZED, "로그인이 필요합니다.");

    private final HttpStatus httpStatus;
    private final String description;

}

에러 코드를 보관하는 enum 클래스이다. Http 상태와 설명을 가지고 있다. 필요에 따라 이 클래스에서 에러 코드를 추가하면 된다. Enum 클래스를 사용하기 전에는 하나하나 예외 클래스를 만들었었는데 관리하기가 까다로웠는데 Enum은 깔끔하다.

 

CustomException

@Getter
public class CustomException extends RuntimeException {

    private final ErrorCode errorCode;

    public CustomException(ErrorCode errorCode) {
        this.errorCode = errorCode;
    }

    public CustomException(ErrorCode errorCode, String message) {
        super(message);
        this.errorCode = errorCode;
    }
}

 

RuntimeExcepion을 상속하는 CustomException을 만들었다. RuntimeException에 간략히 설명하자면 Unchecked Exception으로 예외 처리를 강제하지 않는다. 서버 특성상 상태를 유지하지 않기 때문에 잘못된 요청이 들어오면 바로잡기보단 예외를 던지고 끝내는게 깔끔하다. 

 

ErrorResponse

@Getter
@Builder
public class ErrorResponse {
    private final LocalDateTime timestamp = LocalDateTime.now();
    private final int status;
    private final String error;
    private final String code;
    private final String message;
    private final String description;

    public static ResponseEntity<ErrorResponse> toResponseEntity(CustomException e) {
        ErrorCode errorCode = e.getErrorCode();
        return ResponseEntity
                .status(errorCode.getHttpStatus())
                .body(ErrorResponse.builder()
                        .status(errorCode.getHttpStatus().value())
                        .error(errorCode.getHttpStatus().name())
                        .code(errorCode.name())
                        .message(errorCode.getDetail())
                        .description(e.getMessage())
                        .build()
                );
    }
}

예외 발생 시 반환하는 응답 객체이다.

(여기서 좀 삽질을 했는데 @Getter가 없으면 제대로 작동이 안 한다. 내부적으로 get 프로퍼티가 필요한가 보다)

 

GlobalExceptionHandler

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = {CustomException.class})
    protected ResponseEntity<ErrorResponse> handleCustomException(CustomException e) {
        return ErrorResponse.toResponseEntity(e);
    }

}

@RestControllerAdvice을 클래스명 위에 추가해준다.

@ExceptionHandler의 value에 처리하고 싶은 예외 클래스를 기입하면 된다. 

CustomException.class 예외가 발생하면 handleCustomException 메소드가 실행이 되어 응답 객체를 반환한다.

 

AdviseController

@RestController
@RequestMapping("/advise")
public class AdviseController {

    @GetMapping
    public String throwException() {
        throw new CustomException(ErrorCode.NEED_TO_LOGIN);
    }

}

테스트를 해보니 정상적으로 ErrorResponse 객체가 json으로 반환되었다.

 

 

참고 : Spring Exception Handling :: 뱀귤 블로그 (tistory.com)

 

'Spring' 카테고리의 다른 글

Spring의 @Transactional  (0) 2021.12.15
JDK Dynamic Proxy와 CGLIB  (0) 2021.12.07
Spring AOP  (0) 2021.12.02
Spring Boot에 Redis Cache 적용해보기  (0) 2021.11.25
Spring JPA Specification을 사용해 유연하게 조회 API 만들기  (3) 2021.11.08

댓글