[SpringBoot] Custom Exception 처리

RUNGOAT·2023년 3월 19일
3

SpringBoot

목록 보기
1/3

🔑 왜 Custom Exception을 사용하는가

  • 클라이언트와 서버 간 통신의 명확성을 높인다.
    상태 코드와 함께 error code와 설명을 Custom하여 문제의 원인을 명확히 전달한다.
  • 예외 처리를 효과적으로 관리한다.
    코드 중복을 방지하고 ErrorCode를 한 곳에서 관리할 수 있다.

- 문제 상황

  • Mailbox가 존재하지 않을 시 404 (NotFound)를 내려준다.
  • Mail이 존재하지 않을 시 404 (NotFound)를 내려준다.
  • Mail eml 파일이 존재하지 않을 시 404 (NotFound)를 내려준다.

클라이언트 단에서는 어떤 예외인지에 따라서 다르게 처리하는 로직이 필요하다. 그러나 해당 예외들이 전부 동일한 StatusCode를 제공한다.
이를 구별하기 위해 ErrorCodemessageCustom 정의하여 처리한다.


📢 코드 구현

1️⃣   ErrorCode

💡 사용할 ErrorCode를 정의한다.

import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor
public enum ErrorCode {

	USER_NOT_FOUND(HttpStatus.NOT_FOUND, "ACCOUNT-001", "사용자를 찾을 수 없습니다."),
    HAS_EMAIL(HttpStatus.BAD_REQUEST, "ACCOUNT-002", "존재하는 이메일입니다."),
    INVALID_PASSWORD(HttpStatus.BAD_REQUEST, "ACCOUNT-003", "비밀번호가 일치하지 않습니다."),
    // ...
    
    private final HttpStatus httpStatus;	// HttpStatus
    private final String code;				// ACCOUNT-001
    private final String message;			// 설명
}

2️⃣   CustomException

💡 ErrorCode를 담을 class 생성한다.

@Getter
@AllArgsConstructor
public class CustomException extends RuntimeException {
    ErrorCode errorCode;
}
  • RuntimeException 상속
  • Errorcode 속성 추가

3️⃣   CustomExceptionHandler

💡 Controller 전역에서 발생하는 Custom Error를 잡아줄 Handler를 생성한다.

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class CustomExceptionHandler {

    @ExceptionHandler(CustomException.class)
    protected ResponseEntity<ErrorResponseEntity> handleCustomException(CustomException e){
        return ErrorResponseEntity.toResponseEntity(e.getErrorCode());
    }
}

3.1 @ControllerAdvice

✅ 모든 @Controller 즉, 전역에서 발생할 수 있는 예외를 잡아 처리한다.

3.2 @ExceptionHandler(CustomException.class)

✅ 발생한 CustomException 예외를 잡아서 하나의 메소드에서 공통 처리한다.

3.3 @ControllerAdvice + @ExceptionHandler

모든 컨트롤러에서 발생하는 CustomException을 catch한다.


4️⃣   ErrorResponseEntity

💡 Custom Error 내용을 담을 Response Entity를 생성한다.

@Data
@Builder
public class ErrorResponseEntity {
    private int status;
    private String name;
    private String code;
    private String message;

    public static ResponseEntity<ErrorResponseEntity> toResponseEntity(ErrorCode e){
        return ResponseEntity
                .status(e.getHttpStatus())
                .body(ErrorResponseEntity.builder()
                		.status(e.getHttpStatus().value())
                        .name(e.name())
                        .code(e.getCode())
                        .message(e.getMessage())
                        .build());
    }
}
  • toResponseEntity(ErrorCode e)로 Custom Error 내용을 작성하여 Response를 반환한다.
  • 각 속성들은 필요에 따라 Custom하게 정의한다. (속성 생략 가능)

Response 결과 예시
{
"status": 404,
"name": "USER_NOT_FOUND",
"code": "ACCOUNT-001",
"message": "사용자를 찾을 수 없습니다."
}


5️⃣   사용

userRepository.findById({userId})
	.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
  • userId에 맞는 User가 없다면 USER_NOT_FOUND 예외를 발생시켜 Response를 클라이언트에게 보낸다.


📖 문서화

💡 클라이언트와 소통하기 위해 ErrorCode에 대한 문서화가 필요하다.


📌 참고

profile
📞피드백 너무나 환영

1개의 댓글

comment-user-thumbnail
2024년 3월 12일

안녕하세요 ! 게시글 너무 잘 봤고 이번 프로젝트에 적용하고 싶습니다 ㅎㅎ
혹시 이 경우 스웨거는 어떻게 적용하는지 여쭙고 싶습니다 !

답글 달기