
GIF 출처 : https://sigridjin.medium.com/spring-transaction-관리에-대한-메모-f391fd2885b4
1 ) 개요
2 ) CustomException 도입하기
3 ) 총평
4 ) 참고 블로그 및 코드
첫 스프링 프로젝트 이후 두번째 프로젝트 부터는 RESTful API를 도입하게 되면서 여러 코드 변화를 맞이하게 되었다. 또한 여러 헤커톤 및 연합동아리 프로젝트를 겪으며 많은 것을 습득하게 되었는데 JWT 로그인 구현을 하면서 ResponseEntity의 사용 , Spring Filter , Httpstatus 처리하기 등 다양한 경험을 할 수 있었다.
그 중 이번 포스팅에서는 CustomException에 대해 다뤄보고자 한다.
먼저 등록하고자 하는 에러 케이스에 대한 에러 코드를 생성해야한다.
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클래스를 생성하여 해당 예외 처리시에 상태를 나타낼 수 있게 한다.
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public class CustomException extends RuntimeException{
private ErrorCode errorCode;
}
다음으로 response에 담을 상태코드 , 메시지를 초기화한 후 ResponseEntity에 담아 리턴한다. 이때 , Builder를 통해 필드를 초기화 하는 error메소드를 통해 Handler클래스에서 초기화 로직을 생략한다.
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를 통해 사용하고자 하는 예외 클래스를 명시한다.
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);
}
}
response에 상태코드를 담아 던지는 것은 가능하나 모든 케이스에 대한 예외를 던지는 것은 어려우며 케이스에 따라 기존에 존재하는 상태코드를 던져줘야한다. 즉 , 서로 다른 사유더라도 하나의 상태코드로 처리될 수 있다는 것이다.
이때 , 해당 에러가 어떤 사유에 의해서 발생하였는지를 나타내기 위해CustomException을 도입하였고 이를 통해 케이스별 예외처리를 할 수 있는 장점을 가지고 있다. 또한 enum 타입의 클래스 한 곳에 예외를 모아서 보관할 수 있어 유지보수에 용이하다는 장점이 있다.