ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 예외처리전략 (Exception Handler)
    Spring 2021. 9. 5. 20:25

    스프링에서 예외처리를 해주자. 

    예외발생 데이터타입을 일관된 형태로 생성해서 반응하도록 설정해준다. 

    Error Response

    먼저 예외의 형태를 잡아주는 클래스를 작성해준다. 메세지와 상태, 시간정보를 담고있다. 발생된 에러를 다음의 형태로 반환할 것이다. 

    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    
    @Data
    @NoArgsConstructor
    public class ErrorResponse {
    
        private String message;
        private int status;
        private long timestamp;
    }

     

    Global Exception Handler

    발생된 예외 형태에 따라서 처리를 해주는 exception handler를 작성해준다. @Controller Advice 어노테이션을 이용해서 모든 예외를 한 곳에서 처리할 수 있게 된다. 각각의 예외는 @ExceptionHandler를 통해서 예외클래스를 처리해준다. 

    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.MethodArgumentNotValidException;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
    
    @ControllerAdvice
    public class GlobalExceptionHandler {
    
    	//@Valid or @Validated 바인딩 에러시 발생 
        @ExceptionHandler(MethodArgumentNotValidException.class)
        protected ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(MethodArgumentNotValidException e){
            ErrorResponse errorResponse = new ErrorResponse();
            HttpStatus status = HttpStatus.BAD_REQUEST;
            errorResponse.setStatus(status.value());
            errorResponse.setMessage(e.getMessage());
    
            return new ResponseEntity<>(errorResponse, status);
        }
        
        //@ModelAttribute로 바인딩 에러시에 발생
        @ExceptionHandler(BindException.class)
        protected ResponseEntity<ErrorResponse> handleBindException(BindException e){
            ErrorResponse errorResponse = new ErrorResponse();
            HttpStatus status = HttpStatus.BAD_REQUEST;
            errorResponse.setStatus(status.value());
            errorResponse.setMessage(e.getMessage());
    
            return new ResponseEntity<>(errorResponse, status);
        }
    
    	//enum 타입 불일치로 바인딩 에러시에 발생 (ex. @RequestParam enum에러)
        @ExceptionHandler(MethodArgumentTypeMismatchException.class)
        protected ResponseEntity<ErrorResponse> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e){
            ErrorResponse errorResponse = new ErrorResponse();
            HttpStatus status = HttpStatus.BAD_REQUEST;
            errorResponse.setStatus(status.value());
            errorResponse.setMessage(e.getMessage());
    
            return new ResponseEntity<>(errorResponse, status);
        }
        
        //지원하지 않는 HTTP 메소드 호출시 발생
        @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
        protected ResponseEntity<ErrorResponse> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
     		ErrorResponse errorResponse = new ErrorResponse();
            HttpStatus status = HttpStatus.BAD_REQUEST;
            errorResponse.setStatus(status.value());
            errorResponse.setMessage(e.getMessage());
    
            return new ResponseEntity<>(errorResponse, status);
        }
    
        @ExceptionHandler(UserNotFoundException.class)
        public ResponseEntity<ErrorResponse> handleUserNotFoundException(UserNotFoundException e){
            ErrorResponse errorResponse = new ErrorResponse();
            HttpStatus status = HttpStatus.BAD_REQUEST;
            errorResponse.setStatus(status.value());
            errorResponse.setMessage(e.getMessage());
    
            return new ResponseEntity<>(errorResponse, status);
        }
        
        //Authentication 권한이 없는 경우 발생(security에서 발생시킨다)
        @ExceptionHandler(AccessDeniedException.class)
        protected ResponseEntity<ErrorResponse> handleAccessDeniedException(AccessDeniedException e) {
            ErrorResponse errorResponse = new ErrorResponse();
            HttpStatus status = HttpStatus.BAD_REQUEST;
            errorResponse.setStatus(status.value());
            errorResponse.setMessage(e.getMessage());
    
            return new ResponseEntity<>(errorResponse, status);
        }
    
        @ExceptionHandler(IllegalAccessException.class)
        protected ResponseEntity<ErrorResponse> handleIllegalAccessException(IllegalAccessException e){
            ErrorResponse errorResponse = new ErrorResponse();
            HttpStatus status = HttpStatus.BAD_REQUEST;
            errorResponse.setStatus(status.value());
            errorResponse.setMessage(e.getMessage());
    
            return new ResponseEntity<>(errorResponse, status);
        }
    
        @ExceptionHandler(Exception.class)
        protected ResponseEntity<ErrorResponse> handleException(Exception e){
            ErrorResponse errorResponse = new ErrorResponse();
            HttpStatus status = HttpStatus.NOT_FOUND;
            errorResponse.setStatus(status.value());
            errorResponse.setMessage(e.getMessage());
    
            return new ResponseEntity<>(errorResponse, status);
        }
    }

     

     

    Custom Error

    위에서 작성된 에러케이스 중 User Not Found 에러의 경우 custom으로 작성해주었다. 상위에러를 상속받아서 정의해준다. 

    public class UserNotFoundException extends RuntimeException {
    
        public UserNotFoundException(String message) {
            super(message);
        }
    
        public UserNotFoundException(String message, Throwable cause) {
            super(message, cause);
        }
    
        public UserNotFoundException(Throwable cause) {
            super(cause);
        }
    }

    에러를 발생시킬 경우에 다음과 같이 사용해준다. 

        public UserDTO get(Integer id) throws UserNotFoundException {
            try {
                User user = repo.findById(id).get();
                UserDTO userDTO = new UserDTO(user);
                return userDTO;
            }catch (NoSuchElementException ex){
                throw new UserNotFoundException("This User doesn't exist");
            }

     

Designed by Tistory.