CustomException 만들기

5w31892p·2022년 12월 22일
0

Spring

목록 보기
9/30

만들게 된 계기는
숙련차 과제로 예외처리로 지정한 message 와 statusCode 400을 client에 반환하라고 했다.

여러 구글링을 통해 아래 정리된 블로그를 따라하여 구현했다.
Rest API 만들기

물론 내가 만든 코드는 아니지만 내가 사용하였으므로 각 클래스 들이 어떻게 쓰이는지
정확히 이해하고 넘어가고자 쓰는 글이다.


1. Enum class

여기서 내가 사용할 각 코드들을 custom 했다.

...

private final HttpStatus status;
private final int statusCode;
private String message;
...

내가 실제 커스텀 할 것들을 인스턴스 변수로 지정한다.
그리고 난 후 인스턴스 초기화 메서드로 각 매개변수가 있는 생성자를 만들어준다. (Alt + ins)


...

INVALID_TOKEN(HttpStatus.BAD_REQUEST, 400, "토큰이 유효하지 않습니다."),
UNAUTHENTICATED_TOKEN(HttpStatus.BAD_REQUEST, 400, "작성자 또는 관리자만 삭제 및 수정할 수 있습니다."),
DUPLICATE_USERNAME(HttpStatus.BAD_REQUEST, 400, "중복된 사용자가 존재합니다."), 

...

생성자까지 만든 후 위와 같이 내가 사용할 Exception이름을 주고 그 안에서 인스턴수 변수로 지정한 것들을 쓰임새에 맞게 커스텀한다.

enum을 사용한 이유
리팩토링 시 변경 범위가 최소화 되고, 관리가 한 곳에서 되고, 명시적으로 적기 때문에 해당 값이 무슨 의미인지 알기 쉽기 때문에 사용했다.


2. Response class

응답 클래스를 작성한다.
어떠한 것들을 응답할 것인지 응답할 것들을 인스턴스변수로 두고,
단축키로 생성자 만든 후 그 위에 @Bilder를 적는다.
그리고 아래와 같이 enum class를 매개변수로 받는 생성자를 만든다.
후에 만든 생성자는 리턴 값으로 필요시 꺼내 쓸 수 있다.

...

public CustomStatus(StatusEnum e) {
    this.statusCode = code.getStatusCode();
    this.message = code.getMessage();
}

@Bilder

생성자 인자를 메서드 체인을 통해 명시적으로 대입하여 생성자를 호출할 수 있게 빌더 클래스를 생성해준다.
즉, @Builder를 통해 사용하면 반드시 필요한 값이 있어야 객체가 생성됨을 보장할 수 있어 안전성을 높일 수 있다.


3. CustomException class

내가 의도한 예외 상황에 사용하기 위하여 만들었다.
RuntimeException을 상속 받았고, 인스턴스 변수 생성 후 생성자를 만들어준다.
그리고 RuntimeException을 상속 받았기 때문에 super로 enum 안의 메시지를 가져오게끔 적는다.
예외 지정할 때 여기서 꺼내 사용한다.

...

public CustomStatus(StatusEnum e) {
    super(e.getMessage());
    this.error = e;
}

super()
자식 클래스의 생성자에서 부모 클래스의 생성자를 호출하기 위해서 사용
첫줄에 사용


4. Exception handler

@RestControllerAdvice를 사용해 공통된 오류 메시지 형식으로 응답하도록 구현했다.
는 클래스 상단에 쓴다.
각 RuntimeException, AccessDeniedException 등도 따로 지정해 둔다.

@ExceptionHandler({CustomStatus.class})
public ResponseEntity<StatusResponse> exceptionHandler(HttpServletRequest request, final CustomStatus e) {
    return ResponseEntity
            .status(e.getError().getStatus()) // 상태 지정
            .body(StatusResponse.builder() // 이 builder는 위에 2번에서 적어둔 빌더를 뜻함
                    .statusCode(e.getError().getStatusCode()) // 지정해둔 생성자 아래 상태코드 지정
                    .message(e.getError().getMessage()) // 메시지 지정
                    .build()); // 이 것은 2번 클래스를 뜻하는 빌더이다.
}

아직 확실하게 안에 쓰이는 것들이 낯설긴 하지만 어떤 구조로 어떻게 돌아가는지 확실하게 알게 되었다.

나중에 사용하기 편하기 위해서
아예 내가 따로 모든 코드를 커스텀해서 깃허브에 올려두면 어떨까 생각도 든다.

조금 좋은 생각 같아 시간 여유가 될 때 따로 만들어 깃허브에 push해둬야겠다.

0개의 댓글