Book/스프링부트 핵심가이드

스프링부트에서 커스텀 예외 설정하기

블로그 주인장 2023. 11. 25.

커스텀 예외

스프링부트에서 표준 예외가 아닌 사용자가 직접 구현하는 커스텀 예외 처리하는 방법에 대해 알아보겠습니다.


커스텀 예외란?


  • 커스텀 예외를 만들어서 사용하면 네이빙에 개발자의 의도를 담을 수 있기에 이름만으로도 어느정도 예외 상황을 짐작할 수 있다.
  • 커스텀 예외를 사용하면 애플리케이션에 발생하는 예외를 개발자가 직접 관리하기 수월해진다.
  • 커스텀 예외는 개발자가 직접 코드로 관리하기 때문에 책임 소재를 애플리케이션 내부로 가져올 수 있게 된다.
  • 이를 통해 예외 상황이 발생한 경우 한 곳에서 처리하며 특정 상황에 맞는 예외 코드를 적용할 수 있게 된다.
  • 표준 예외를 사용하면 의도하지 않은 예외 상황도 정해진 예외 처리 코드에서 처리하기 때문에 어디에서 문제가 발생했는지 확인하기 어렵지만 커스텀 예외는 개발자가 관리하는 예외 처리 코드가 처리하지 않으므로 개발 과정에서 혼동할 여지가 줄어든다.

 

커스텀 예외 클래스 생성


  • 커스텀 예외는 예외가 발생하는 상황에 해당하는 상위 예외 클래스를 상속받는다.
  • 커스텀 예외는 상위 예외 클래스보다 구체적인 이름을 사용하기도 한다.

 

Exception 클래스와 Throwable 클래스

  • Exception 클래스는 부모 클래스인 Throwable 클래스의 생성자를 호출한다.
  • message 변수의 값을 detailMessage 변수로 받는다.
  • HttpStatus를 예외 클래스에 포함시키면 핸들러 안에서 선언해서 사용하는 것이 아닌 예외 클래스만 전달받으면 그 안에 내용이 포함되어 있는 구조 설계할 수 있다.

 

[예시] ExceptionClass 열거형

public class Constants {

    public enum ExceptionClass {
        PRODUCT("Product");

        private String exceptionClass;

        ExceptionClass(String exceptionClass) {
            this.exceptionClass = exceptionClass;
        }

        public String getExceptionClass() {
            return exceptionClass;
        }

        @Override
        public String toString() {
            return getExceptionClass() + "Exception";
        }

    }
}
  • 열거형을 별도로 생성해도 무관하지만 상수 개념으로 사용하기 때문에 확장성을 위해 Constants 라는 상수들을 통합 관리하는 클래스를 생성하고 내부에 ExceptionClass 선언했다.
  • ExceptionClass() 는 커스텀 예외 클래스에서 메시지 내부에 어떤 도메인에서 문제가 발생했는지 보여주는 데 사용된다.

 

[예시] 커스텀 예외 클래스

public class CustromException extends Exception {

    private Constants.ExceptionClass exceptionClass;
    private HttpStatus httpStatus;

    public CustromException(Constants.ExceptionClass exceptionClass
            , HttpStatus httpStatus, String message) {
        super(exceptionClass.toString() + message);
        this.exceptionClass = exceptionClass;
        this.httpStatus = httpStatus;
    }

    public Constants.ExceptionClass getExceptionClass() {
        return exceptionClass;
    }

    public int getHttpStatusCode() {
        return httpStatus.value();
    }

    public String getHttpStatusType() {
        return httpStatus.getReasonPhrase();
    }

    public HttpStatus getHttpStatus() {
        return httpStatus;
    }
}
  • 커스텀 예외 클래스는 ExceptionClass와 HttpStatus를 필드로 가진다.
  • 두 객체를 기반으로 예외 내용을 정의하며 클래스를 초기화한다.

 

[예시] CustomException을 처리하는 handleException( ) 메서드

@ExceptionHandler(value = CustomException.class)
public ResponseEntity<Map<String, String>> handlerException(CustomException e,
                                                            HttpServletRequest request) {
    HttpHeaders responseHeaders = new HttpHeaders();

    LOGGER.error("Advice 내 handleException 호출, {}, {}",
            request.getRequestURI(), e.getMessage());

    Map<String, String> map = new HashMap<>();
    map.put("error type", e.getHttpStatusType());
    map.put("code", Integer.toString(e.getHttpStatusCode()));
    map.put("message", e.getMessage());

    return new ResponseEntity<>(map, responseHeaders, e.getHttpStatus());
}
  • 기존에 작성했던 핸들러 메서드와 달리 예외 발생 시점에 HttpStatus를 정의해서 전달하기에 클라이언트 요청에 따라 유동적인 응답 코드를 설정할 수 있다는 장점이 있다.

 

[예시] CustomException을 발생시키는 Controller

@GetMapping("/custom")
public void getCustomException() throws CustomException {
    throw new CustomException(Constants.ExceptionClass.PRODUCT,
            HttpStatus.BAD_REQUEST, "getCustomException 메서드 호출");
}
  • CustomException을 throw 키워드로 던지면 커스텀 예외가 발생한다.
  • 괄호 내에 생성자를 정의한 것처럼 ExceptionClass 에서 도메인을 비롯해 HttpStatus를 통해 어떤 응답 코드를 사용할지와 세부 메시지를 전달한다.
  • 예외가 발생하는 상황에서 특정 값을 전달하는 구성이라면 상세한 메시지를 작성해서 전달하거나 커스텀 예외 클래스를 적절한 타입으로 변경하는 것도 좋다.
반응형

댓글