스프링에서의 예외 처리 방법

jiji·2023년 11월 19일
0

Spring Boot Project 🌱

목록 보기
11/16

🔥 기본적인 예외처리 방법

ResponseEntity를 통해 404 상태 코드와 함께 메시지를 반환하도록 처리

// 컨트롤러
    try {
        PostResponseDTO postDto = boardService.findById(postId);
        return ResponseEntity.ok(postDto);
    } catch (NoSuchElementException e) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body("게시글을 찾을 수 없습니다.");
    }
    
// 서비스
	Optional<Post> postOptional = postRepository.findById(postId);
    Post post = postOptional.orElseThrow(() -> new NoSuchElementException("게시글을 찾을 수 없습니다."));

NoSuchElementException은 Java에서 원소를 찾을 때 해당 원소가 없을 경우 발생하는 예외입니다.

🔥 Global Exception Handler

💡 전역 에러 핸들러(Global Exception Handler) 란?
HTTP Status 코드로 정상코드가 아닌 오류코드로 반환하였을 시 실제 에러가 발생하기에 이를 위해 중간에 GlobalExcpetion을 통해 Exception 발생 시에도 HTTP Status 코드로 정상 코드를 보내고 커스텀한 코드를 보냄으로써 실제 Client 내에서 이를 처리할 수 있게 돕기 위함입니다.

@ControllerAdvice

  • @Controller로 선언한 지점에서 발생한 에러를 도중에 @ControllerAdivce로 선언한 클래스 내에서 이를 캐치하여 Controller 내에서 발생한 에러를 처리할 수 있도록 하는 어노테이션입니다. 
  • @ControllerAdivce는 Spring AOP를 이용한 어노테이션입니다.
  • Controller 내부에서 호출한 Service에서 예외가 발생하더라도 잡아낸다
@ControllerAdvice
public class GlobalExceptionHandler {  

	@ExceptionHandler(NoSuchElementException.class)
    public ResponseEntity<String> handleNoSuchElementException(NoSuchElementException e) {
      return ResponseEntity.status(HttpStatus.NOT_FOUND).body("게시글을 찾을 수 없습니다.");
    }
}

// service
  private Post returnPost(Long postId) {
    return boardRepository.findById(postId)
       .orElseThrow(NoSuchElementException::new);
  }

해당 예외가 발생하면 클라이언트에게 NOT_FOUND(404) 상태 코드와 함께 예외 메시지를 반환합니다.

@RestControllerAdvice

  • @RestController로 선언한 지점에서 발생한 에러를 도중에 @RestControllerAdvice로 선언한 클래스 내에서 이를 캐치하여 Controller 내에서 발생한 에러를 처리할 수 있도록 하는 어노테이션입니다. 
  • @ControllerAdivce는 Spring AOP를 이용한 어노테이션입니다.

@ExceptionHandler

  • 특정 에러 발생 시 Controller에 발생하였을 경우 해당 에러를 캐치하여 클라이언트로 오류를 반환하도록 처리하는 기능을 수행합니다.

🧐 Custom Exception : 사용자 정의 예외

표준 예외를 적극적으로 사용하자
커스텀 예외의 이름만 봐도 어떤 예외인지 알아볼 수 있다. 하지만 표준 예외를 사용하고 errorMessage 로 오류 상황을 나타내는 정도로도 충분히 표현이 가능하다면, 굳이 커스텀 예외를 사용하지 않는것이 좋다.

반대로 CustomException을 받는 곳에서 처리하기 쉽기 위해 추가로 에러에 관한 정보를 넣어주거나, 여러 타입의 Exception이 발생할 수 있는 코드에서 한가자로 Exception 타입으로 묶어 처리할때는 custome exception을 사용할만 하다.

표준 예외를 사용하면 가독성이 높아진다.
NullPointerException : null을 허용하지 않는 메서드에 null을 건냈을 때
IndexOutBoundsException : 범위 밖의 index에 접근할 때
IllegalArgumentException : 허용하지 않는 값이 인수로 건네졌을 때
IllegalStateException : 객체가 메서드를 수행하기에 적절하지 않은 상태일 때
UnsupportedOperationException : 요청받은 작업을 지원하지 않는 경우 일 때

🔥 HandlerExceptionResolver

이렇게 모든 코드에 try-catch를 사용하는 것은 비효율적이다.
스프링은 예외처리를 추상화한 HandlerExceptionResolver 인터페이스를 만들었다. (에러 처리를 메인 로직으로 부터 분리)

public interface HandlerExceptionResolver {
    ModelAndView resolveException(HttpServletRequest request, 
            HttpServletResponse response, Object handler, Exception ex);
}
  • 스프링 프레임워크에서 예외를 처리하는 방식을 커스터마이즈할 수 있는 인터페이스
  • 인터페이스를 구현하는 클래스는 예외가 발생했을 때 특정한 방식으로 처리하도록 도와줍니다.
  • HandlerExceptionResolver를 구현하는 클래스에서는 resolveException 메서드를 오버라이드하여 예외 처리 로직을 구현할 수 있습니다.
  • Object 타입인 handler
    예외가 발생한 컨트롤러(핸들러)

@ResponseStatus

에러 HTTP 상태를 변경

// ex. 특정 예외에 대해 404 Not Found 상태 코드를 반환하고자 할 때
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
    // 예외 클래스 내용...
}
  • 상태코드만 변경 가능하다
  • 단일 예외에만 적용 가능하다
  • 명확한 의미전달이 어렵다
참조
https://adjh54.tistory.com/79 [Contributor9:티스토리]

0개의 댓글