Spring Framework - 예외처리

h.Im·2024년 8월 30일

Springboot 기초

목록 보기
10/17
post-thumbnail

@ExceptionHandler

@ExceptionHandler는 Spring MVC 컨트롤러에서 발생하는 예외를 처리하기 위해 사용할 수 있습니다. 예외 발생 시, 사용자에게 적절한 응답을 반환할 수 있도록 도와줍니다. 예제 코드로 살펴보겠습니다.

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

// 사용자 정의 예외 클래스
class ResourceNotFoundException extends RuntimeException {
    public ResourceNotFoundException(String message) {
        super(message);
    }
}

// 컨트롤러 클래스
@RestController
public class MyController {

    @GetMapping("/resource/{id}")
    public String getResource(@PathVariable("id") int id) {
        if (id <= 0) {
            throw new ResourceNotFoundException("Resource not found with ID: " + id);
        }
        return "Resource with ID: " + id;
    }

    // ResourceNotFoundException 처리 메서드
    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<String> handleResourceNotFoundException(ResourceNotFoundException ex) {
        return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
    }

    // 다른 예외 처리 메서드 추가 가능
    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleGeneralException(Exception ex) {
        return new ResponseEntity<>("An error occurred: " + ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
  • RuntimeException을 상속받는 ResourceNotFoundException 클래스를 작성하였습니다.
  • @ExceptionHandler(ResourceNotFoundException.class) 어노테이션을 handleResourceNotFoundException 함수에 작성함으로써, ResourceNotFoundException 예외 처리를 해당 함수가 담당하게 됩니다.
  • /resource/{id}에 GET 요청이 들어왔을 때, 예제 코드 기준으로 id가 0이하라면 ResourceNotFoundException이 발생합니다.
  • 그 외 일반적인 예외 처리는 @ExceptionHandler(Exception.class) 어노테이션이 붙은 handleGeneralException 함수가 담당하게 됩니다.

자바에서는 예외를 처리하기 위해 Exception 클래스 계층을 사용하며, RuntimeException은 그 중 하나입니다. ResourceNotFoundException 클래스에서 super(message)를 호출하였기 때문에 handleResourceNotFoundException 내부에서 ex.getMessage()를 호출하였을 때 "Resource not found with ID: " 문구가 반환될 수 있는 구조입니다.


@RestControllerAdvice

위에서는 컨트롤러 단위로 예외 처리를 하는 방법을 살펴 보았는데, 컨트롤러가 많아지면 @ExceptionHandler를 반복적으로 사용하는 비효율성이 발생할 수 있습니다. 이때 @RestControllerAdvice를 사용하는 것이 대안이 될 수 있습니다.

@RestControllerAdvice는 Spring MVC에서 예외 처리를 전역적으로 관리할 수 있도록 도와주는 어노테이션입니다.

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;

// 사용자 정의 예외 클래스
class ResourceNotFoundException extends RuntimeException {
    public ResourceNotFoundException(String message) {
        super(message);
    }
}

// 컨트롤러 클래스
@RestController
public class MyController {

    @GetMapping("/resource/{id}")
    public String getResource(@PathVariable("id") int id) {
        if (id <= 0) {
            throw new ResourceNotFoundException("Resource not found with ID: " + id);
        }
        return "Resource with ID: " + id;
    }
}

// 전역 예외 처리 클래스
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<String> handleResourceNotFoundException(ResourceNotFoundException ex) {
        return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleGeneralException(Exception ex) {
        return new ResponseEntity<>("An error occurred: " + ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

이전 코드에서는 MyController 내부에 에러 핸들러를 작성하였는데, 이번 코드는 컨트롤러 외부에 GlobalExceptionHandler가 작성되어 있습니다.
전역적으로 처리될만한 에러 케이스는 위 방식으로 작성하면 중복 코드를 줄일 수 있습니다.

RestControllerAdvice 어노테이션 이름에서 유추할 수 있듯이(Advice) 이러한 방식도 AOP의 일종이라고 볼 수 있어 보입니다!

0개의 댓글