JPA를 사용하여 Entity를 찾아오거나 , 로직상에 문제가 있을 때 예외 처리를 할 일이 많이 있다.
예외처리를 할때 같은 케이스의 예외인데 메시지가 다르게 나가는 점과 같은 예외에서도 다른 HttpStatus 상태코드를 내보낼 상황이 있을 수 있다는 점에서 통일화하여 메시지와 반환 객체를 구조화할 필요성을 느꼈다.
따라서 아래와 같이 커스텀 예외와 예외 핸들링을 해보았다.
1. 예외 정의 Enum 타입 ErrorDefinition
@Getter
public enum ErrorDefinition {
NOT_FOUND , ILLEGAL_ARGUMENT
}
2. ErrorCode Enum 타입
Enum 타입에 Http 상태 코드, 에러 분류 , 에러 메시지를 정의하였다.
@AllArgsConstructor
@Getter
public enum ErrorCode {
// DB 조회 실패 에러 코드
USER_NOT_FOUND(BAD_REQUEST, NOT_FOUND, "유저 정보를 찾을 수 없습니다."),
REVIEW_NOT_FOUND(BAD_REQUEST, NOT_FOUND, "리뷰 정보를 찾을 수 없습니다."),
MEDICINE_NOT_FOUND(BAD_REQUEST, NOT_FOUND, "영양제 정보를 찾을 수 없습니다."),
IMAGE_NOT_FOUND(BAD_REQUEST, NOT_FOUND, "이미지 정보를 찾을 수 없습니다."),
HASHTAG_NOT_FOUND(BAD_REQUEST, NOT_FOUND, "해쉬태그 정보를 찾을 수 없습니다."),
// 로직 실패 에러코드
REVIEW_DUPLICATION(BAD_REQUEST, ILLEGAL_ARGUMENT,"이미 후기를 작성한 영양제 입니다."),
ACCESS_BLOCKED(FORBIDDEN, ILLEGAL_ARGUMENT,"작성자만 접근 가능합니다.")
;
private final HttpStatus httpStatus;
private final ErrorDefinition errorDefinition;
private final String message;
}
3. 커스텀 예외 클래스
Enum 타입 ErrorCode 를 갖는 커스텀 예외를 만들었다. RuntimeException 을 상속받았다.
그리고 RuntimeException의 getMessage() 메서드를 오버라이드해서 ErrorCode의 메시지를 받을 수 있도록 하였다.
@AllArgsConstructor
@Getter
public class CustomException extends RuntimeException{
ErrorCode errorCode;
@Override
public String getMessage() {
return errorCode.getMessage();
}
}
4. 에러 객체
일반 에러를 인자로 받아 ResponeEntity를 만들 수 있는 static 메서드와 커스텀 예외를 인자로 받을 수 있는 static 메서드를 오버로딩하여 활용도를 높였다.
@Data
@AllArgsConstructor
@Builder
public class ErrorResult {
private int status;
private String code;
private String detail;
private String message;
//모든 예외에서 사용가능
public static ResponseEntity<ErrorResult> ofResponse(Exception e, HttpStatus httpStatus) {
return ResponseEntity
.status(httpStatus)
.body(ErrorResult.builder()
.status(httpStatus.value())
.code(e.fillInStackTrace().toString())
.message(e.getMessage())
.build()
);
}
// 커스텀에서 사용시
public static ResponseEntity<ErrorResult> ofResponse(ErrorCode e) {
return ResponseEntity
.status(e.getHttpStatus())
.body(ErrorResult.builder()
.status(e.getHttpStatus().value())
.code(e.getErrorDefinition().toString())
.detail(e.name())
.message(e.getMessage())
.build()
);
}
}
5. RestControllerAdvice
위에 만든 두 개의 static 메서드를 활용하는 예시
@RestControllerAdvice
@Order(1)
@Slf4j
public class GlobalCustomExceptionHandler {
//커스텀 익셉션 사용 예
@ExceptionHandler(CustomException.class)
public ResponseEntity<ErrorResult> validException(CustomException e) {
return ErrorResult.ofResponse(e.getErrorCode());
}
@ExceptionHandler(NullPointerException.class)
public ResponseEntity<ErrorResult> nullPointException(NullPointerException e) {
return ErrorResult.ofResponse(e, HttpStatus.valueOf(500));
}
}
'Spring' 카테고리의 다른 글
Spring boot 커스텀 메트릭 (프로메테우스/그라파나) (0) | 2024.05.06 |
---|---|
배포 서버 ClassNotFoundException 트러블 슈팅 (0) | 2024.05.02 |
Spring boot 의 외부 설정 (1) | 2024.04.27 |
Spring boot 의 내장 톰캣 (0) | 2024.04.21 |
서블릿 컨테이너, 애플리케이션 초기화 (1) | 2024.04.20 |