팀프로젝트 예외처리(GlobalExceptionHandler) 전략

박화랑·2025년 4월 10일
2

Spring_6기

목록 보기
17/32

예외 처리 전체 흐름 설명

이번 친구 요청 기능을 구현하면서, 발생 가능한 다양한 예외 상황에 대해 전략적인 예외 처리 구조를 설계했습니다. 이 구조는 다음과 같은 흐름으로 구성되어 있습니다:


✅ 1. 예외 정의: ErrorCode Enum

먼저, 발생 가능한 모든 예외 상황을 ErrorCode라는 Enum으로 정의했습니다.
이 Enum에는 에러 메시지, HTTP 상태 코드가 함께 포함되어 있어 에러 정보의 일관성을 유지할 수 있습니다.

예시:

ALREADY_REQUESTED("이미 친구 요청을 보냈습니다", HttpStatus.CONFLICT),
REQUEST_NOT_FOUND("존재하지 않는 친구 요청입니다", HttpStatus.NOT_FOUND),
INVALID_CANCEL("취소할 수 없는 친구 요청 상태입니다", HttpStatus.BAD_REQUEST)

이 방식은 하드코딩된 메시지를 피하고, 중앙에서 에러 메시지를 관리할 수 있도록 해줍니다. 또한 예외처리를 추가하기 편하면서 재사용성을 증가시킬 수 있다는 장점이 있습니다.


✅ 2. 예외 발생: CustomException

비즈니스 로직(Service) 내에서 문제가 발생했을 때는 CustomException을 발생시킵니다.
이 예외는 ErrorCode를 포함하고 있어서, 어떤 예외가 어떤 이유로 발생했는지를 정확히 표현할 수 있습니다.

if (exists) {
    throw new CustomException(ErrorCode.ALREADY_REQUESTED);
}

✅ 3. 예외 처리: GlobalExceptionHandler

스프링의 @RestControllerAdvice를 활용해, 전체 애플리케이션에서 발생한 예외를 한 곳에서 통합 처리합니다.

핸들러 예시:

@ExceptionHandler(CustomException.class)
public ResponseEntity<ErrorResponseDto> handleCustomException(CustomException ex, HttpServletRequest request) {
    return ResponseEntity
        .status(ex.getErrorCode().getStatus())
        .body(ErrorResponseDto.from(ex.getErrorCode(), request.getRequestURI()));
}

여기서 핵심은, 예외가 발생했을 때 ResponseEntity로 구조화된 Dto 객체를 반환한다는 점입니다.


✅ 4. 예외 응답 포맷: ErrorResponseDto

우리는 단순히 Map<String, String> 형태가 아닌, ErrorResponseDto라는 전용 Dto를 통해 응답을 보냅니다.

이 Dto는 다음과 같은 정보를 포함합니다:

  • status: HTTP 상태 코드
  • error: 상태 이름 (예: BAD_REQUEST)
  • message: 사용자에게 보여질 메시지
  • path: 어떤 요청에서 오류가 발생했는지
  • timestamp: 에러 발생 시간
  • fieldErrors: 유효성 검사 실패 시 필드별 상세 에러 리스트
{
    "timestamp": "2025-04-10T15:09:16.523464",
    "status": 400,
    "error": "BAD_REQUEST",
    "message": "잘못된 입력값입니다",
    "path": "/api/users",
    "fieldErrors": [
        {
            "field": "password",
            "message": "비밀번호는 영문 대소문자, 숫자, 특수문자를 포함해 8자 이상 20자 이하이어야 합니다."
        },
        {
            "field": "email",
            "message": "이메일 형식이 아닙니다"
        }
    ]
}

✅ 왜 Dto로 예외 응답을 처리했는가?

마지막으로, 예외 응답을 단순 Map이 아닌 Dto를 사용한 이유는 다음과 같습니다:

  • 일관된 응답 구조 유지 – 모든 예외가 같은 형태로 반환
  • 복잡한 정보 전달 가능 – 복수 필드 에러(@Vaild 예외처리가 다수 일어나는 경우), 경로, 상태 코드 등 포함
  • 유지보수 용이 – 응답 포맷이 변경돼도 Dto만 수정하면 간단하게 처리 가능
  • Swagger 문서화 지원 – API 문서에서 명확한 응답을 제공

요약 멘트:

"이렇게 ErrorCode, CustomException, GlobalExceptionHandler, 그리고 ErrorResponseDto를 통해 예외를 체계적으로 처리함으로써, 사용자에게는 명확한 피드백을, 개발자에게는 유지보수성과 확장성을 제공할 수 있었습니다."


profile
개발자 희망생

0개의 댓글