-
예외처리전략 ( ExceptionHandler ) 2Spring 2022. 1. 13. 18:17
https://dodop-blog.tistory.com/229
이전 글에서 예외처리 전략을 이용하여 예외발생 데이터타입을 일관된 형태로 생성해서 반응하도록 설정하는 방법을 알았다.
그런데 여기서 모든 customException을 RuntimeException을 상속받아 중복되는 NotFoundException의 경우에도 모두 ControllerAdvice(GlobalExceptionHandler)에서 일일이 처리해주어야 하는 상황이 발생되었다.
또한, 이전에 작성한 예외처리에서 정의되지 않은 예외의 처리코드를 요청 사용자의 오류임을 의미하는 404코드로 작성한 부분이 잘못되었다는 것을 알게 되었다. 이 부분을 수정해보자.
중복된 CustomException 처리
public class EntityNotFoundException extends RuntimeException { public EntityNotFoundException(String message) { super(message); } public EntityNotFoundException(String message, Throwable cause) { super(message, cause); } public EntityNotFoundException(Throwable cause) { super(cause); } }
먼저 중복될 예외의 대표 타입인 EntityNotFoundException을 작성해준다. 이 예외는 RuntimeException을 상속 받고 있다.
이와 같은 방식으로 대표 예외인 AuthException, BadRequestException, InvalidValudException 등을 작성해준다.
public class UserNotFoundException extends EntityNotFoundException { public UserNotFoundException(String message) { super(message); } public UserNotFoundException(String message, Throwable cause) { super(message, cause); } public UserNotFoundException(Throwable cause) { super(cause); } }
CustomException은 위의 대표 예외를 상속받도록 구현한다.
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(InvalidValueException.class) public ResponseEntity<ErrorResponse> handleInvalidValueException( InvalidValueException e) { ErrorResponse errorResponse = new ErrorResponse( HttpStatus.BAD_REQUEST.value(), e.getMessage()); return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); } @ExceptionHandler(BadRequestException.class) public ResponseEntity<ErrorResponse> handleBadRequestException(BadRequestException e) { ErrorResponse errorResponse = new ErrorResponse( HttpStatus.BAD_REQUEST.value(), e.getMessage()); return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); } @ExceptionHandler(EntityNotFoundException.class) protected ResponseEntity<ErrorResponse> handleEntityNotFoundException( EntityNotFoundException e) { ErrorResponse errorResponse = new ErrorResponse( HttpStatus.NOT_FOUND.value(), e.getMessage()); return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); } @ExceptionHandler(AuthException.class) public ResponseEntity<ErrorResponse> handleAuthException( OAuthProviderMissMatchException e) { ErrorResponse errorResponse = new ErrorResponse( HttpStatus.UNAUTHORIZED.value(), e.getMessage()); return new ResponseEntity<>(errorResponse, HttpStatus.UNAUTHORIZED); } }
GlobalExceptionHandler에서는 모돈 커스텀 예외를 작성해 줄 필요없이 다형성을 이용하여 대표 예외만을 처리하는 방식으로 작성함으로서 중복 처리를 방지할 수 있게 되었다.
정의되지 않은 예외 처리
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(RuntimeException.class) protected ResponseEntity<ErrorResponse> handleUncheckedException(RuntimeException e) { e.printStackTrace(); ErrorResponse errorResponse = new ErrorResponse( HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage()); return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR); } }
RuntimeException을 제외한 Exception은 checked 타입의 예외로 컴파일 시점에 오류를 발생할 수 있으므로 이를 제외한 unchecked타입(컴파일 시점에 오류를 알 수 없음)의 RuntimeException을 정의해준다. checked타입의 예외는 사용자 측의 오류와 같은 외적인 요인에 발생하는 방면 RuntimeException의 경우 개발자의 부주의로 인하여 발생하는 경우가 대부분을 차지한다. 따라서 custom처리 해주지 않은 그 외에 발생하는 정의 되지 않은 타입의 RuntimeException은 서버 측의 잘못을 명시하는 INTERNAL_SERVER_ERROR(500) 을 표시해주는 것이 옳다.
타입 Checked Exception
( RuntimeException을 제외한 모든 Exception)Unchecked Exception
( RuntimeException )처리 필수 여부 O X 오류 확인 시점 컴파일 시점 실행 시점 트랜잭션 처리 Roll back X Roll back O 상태 코드 4XX 사용자 요청 오류 5XX 서버 오류 'Spring' 카테고리의 다른 글
Service Layer의 단위테스트 작성 : (1) Mockito ② (0) 2022.02.03 Service Layer의 단위테스트 작성 : (1) Mockito ① (0) 2022.01.28 JPA 엔티티에 생성 시점, 수정 시점 Timestamp 추가하기 ( + Auditing) (0) 2022.01.13 JPA getById() 와 findById()의 차이 (0) 2022.01.12 테스트 코드 작성할 때 Junit5 사용시 JUnit Vintage 오류 발생 (0) 2022.01.11