[ Spring ] CustomException 도입

Wooju Kang ·2025년 3월 30일

[ 기능구현 ] Spring

목록 보기
1/1
post-thumbnail

GIF 출처 : https://sigridjin.medium.com/spring-transaction-관리에-대한-메모-f391fd2885b4

🖥 Contents


1 ) 개요

2 ) CustomException 도입하기

3 ) 총평

4 ) 참고 블로그 및 코드




1 ) 개요


첫 스프링 프로젝트 이후 두번째 프로젝트 부터는 RESTful API를 도입하게 되면서 여러 코드 변화를 맞이하게 되었다. 또한 여러 헤커톤 및 연합동아리 프로젝트를 겪으며 많은 것을 습득하게 되었는데 JWT 로그인 구현을 하면서 ResponseEntity의 사용 , Spring Filter , Httpstatus 처리하기 등 다양한 경험을 할 수 있었다.

그 중 이번 포스팅에서는 CustomException에 대해 다뤄보고자 한다.



2 ) CustomException 도입하기


먼저 등록하고자 하는 에러 케이스에 대한 에러 코드를 생성해야한다.

① ErrorCode

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

@RequiredArgsConstructor
@Getter
public enum ErrorCode {


    USER_NOT_FOUND(HttpStatus.NOT_FOUND,"해당 사용자를 찾을 수 없습니다."),

    private final HttpStatus httpStatus;
    private final String message;
}

해당 클래스의 필드는 Http상태코드를 담는 HttpSatus 객체와 String 타입의 객체 필드를 가진다. 이후에 RuntimeException을 상속하는 Exception클래스를 생성하여 해당 예외 처리시에 상태를 나타낼 수 있게 한다.

② CustomException

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public class CustomException extends RuntimeException{

    private ErrorCode errorCode;

}

다음으로 response에 담을 상태코드 , 메시지를 초기화한 후 ResponseEntity에 담아 리턴한다. 이때 , Builder를 통해 필드를 초기화 하는 error메소드를 통해 Handler클래스에서 초기화 로직을 생략한다.

③ ErrorResponse

import lombok.Builder;
import lombok.Getter;
import org.kangwooju.skeleton_user.common.exception.CustomException;
import org.kangwooju.skeleton_user.common.exception.ErrorCode;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;


@Builder
@Getter
public class CustomErrorResponse {

    private final HttpStatus httpStatus;
    private final String code;
    private final String message;

    public CustomErrorResponse(ErrorCode errorCode){
        this.httpStatus = errorCode.getHttpStatus();
        this.code = errorCode.name();
        this.message = errorCode.getMessage();
    }

    public static ResponseEntity<CustomErrorResponse> error(CustomException e){
        return ResponseEntity
                .status(e.getErrorCode().getHttpStatus()) // status 설정
                .body(CustomErrorResponse // body 설정
                        .builder()
                        .httpStatus(e.getErrorCode().getHttpStatus())
                        .code(e.getErrorCode().name())
                        .message(e.getErrorCode().getMessage())
                        .build());
    }
}

마지막으로 전역 예외처리 클래스임을 명시하는 @RestControllerAdvice 어노테이션을 사용하고 특정 예외 클래스를 처리하는 @ExceptionHandler를 통해 사용하고자 하는 예외 클래스를 명시한다.

④ GlobalExceptionHandler

import org.kangwooju.skeleton_user.common.dto.response.CustomErrorResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(CustomException.class)
    public ResponseEntity<CustomErrorResponse> handleCustomException(CustomException e){

        return CustomErrorResponse.error(e);
    }
}



3 ) 총평


response에 상태코드를 담아 던지는 것은 가능하나 모든 케이스에 대한 예외를 던지는 것은 어려우며 케이스에 따라 기존에 존재하는 상태코드를 던져줘야한다. 즉 , 서로 다른 사유더라도 하나의 상태코드로 처리될 수 있다는 것이다.

이때 , 해당 에러가 어떤 사유에 의해서 발생하였는지를 나타내기 위해CustomException을 도입하였고 이를 통해 케이스별 예외처리를 할 수 있는 장점을 가지고 있다. 또한 enum 타입의 클래스 한 곳에 예외를 모아서 보관할 수 있어 유지보수에 용이하다는 장점이 있다.



4 ) 참고 블로그 및 코드



profile
배겐드 📡

0개의 댓글