티스토리 뷰

반응형

예외처리

프로그래밍을 할 땐 다양한 예외 상황이 발생한다.

이 예외 처리를 잘해야 좋은 프로그램이 될 수 있다.

예외 처리를 try-catch문을 사용하거나 다른 여러가지 방법들로 할수도 있지만, 이는 코드가 복잡해지고 유지보수 하기에도 어렵다는 문제점이 있다.

예외처리를 한번에 다른곳에서 처리하고 비즈니스 로직에서는 비즈니스 로직만 작성하여 코드가 복잡해지지 않도록 할 수 있다.

 

@ExceptionHandler

이 어노테이션은 메서드에 붙일 수 있는데, @Controller와 @RestController가 적용된 Bean에서 생기는 예외를 캐치하여 이 메서드에서 처리해주도록 한다.

메서드의 인자로 캐치하려는 예외 클래스를 작성하면 된다.

리턴 타입은 하고싶은대로 해도 된다.

@ExceptionHandler를 등록한 Controller나 RestController에서만 적용된다.

@RestController
@RequestMapping("/api")
public class CustomerRestController {
        /*
        ...
        */
        @ExceptionHandler
      public ResponseEntity<CustomerErrorResponse> handleException(Exception exc){
        CustomerErrorResponse error = new CustomerErrorResponse(
              HttpStatus.BAD_REQUEST.value(),
              exc.getMessage(),
              System.currentTimeMillis());

        return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
      }
}

 

@ControllerAdvice

그런데 위에서도 말했듯이 @ExceptionHandler를 등록한 그 클래스에서만 적용된다. 모든 Controller나 RestController에서 발생할 수 있는 예외를 잡아 한번에 처리해주는 어노테이션이 @ControllerAdvice와 @RestControllerAdvice이다.

새로운 클래스에 이 어노테이션을 붙이고, @ExceptionHandler로 예외 처리 메서드를 작성하면 된다. 모든 패키지 전역의 컨트롤러에서 발생하는 예외가 해당하는 메서드를 처리하게 된다.

@RestController나 @Controller에서 발생하는 예외들을 @ControllerAdvice + @ExceptionHandler 조합으로 캐치하여 처리할 수 있는 것이다.

@ControllerAdvice
public class CustomerRestExceptionHandler {
  @ExceptionHandler
  public ResponseEntity<CustomerErrorResponse> handleException(CustomerNotFoundException exc){
    CustomerErrorResponse error = new CustomerErrorResponse(
          HttpStatus.NOT_FOUND.value(),
          exc.getMessage(),
          System.currentTimeMillis());

    return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
  }

  @ExceptionHandler
  public ResponseEntity<CustomerErrorResponse> handleException(Exception exc){
    CustomerErrorResponse error = new CustomerErrorResponse(
          HttpStatus.BAD_REQUEST.value(),
          exc.getMessage(),
          System.currentTimeMillis());

    return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
  }
}

 

모든 Controller와 RestController의 예외를 잡지 않고 속성에서 패키지 단위로 지정할수도 있다.

@RestControllerAdvice("com.example.hello.rest")

 

 

에러를 잘 정의하기 위해서 에러 객체를 만들어서 처리하는 것도 좋다. 다음과 같이 에러 객체를 만들고

public class CustomerErrorResponse {
  private int status;
  private String message;
  private long timeStamp;

  public CustomerErrorResponse() {
  }

  public CustomerErrorResponse(int status, String message, long timeStamp) {
    this.status = status;
    this.message = message;
    this.timeStamp = timeStamp;
  }

  public int getStatus() {
    return status;
  }

  public void setStatus(int status) {
    this.status = status;
  }

  public String getMessage() {
    return message;
  }

  public void setMessage(String message) {
    this.message = message;
  }

  public long getTimeStamp() {
    return timeStamp;
  }

  public void setTimeStamp(long timeStamp) {
    this.timeStamp = timeStamp;
  }
}

 

 

RuntimeException 상속받아 Exception을 만든다.

public class CustomerNotFoundException extends RuntimeException{
  public CustomerNotFoundException() {
    super();
  }

  public CustomerNotFoundException(String message) {
    super(message);
  }

  public CustomerNotFoundException(String message, Throwable cause) {
    super(message, cause);
  }

  public CustomerNotFoundException(Throwable cause) {
    super(cause);
  }
}

 

 

위에서 만든 Exception 클래스를 인자로 넣어 @ExceptionHanlder 로 메소드를 만들 수 있다. 에러 객체를 만들어서 리턴한다.

@ExceptionHandler
public ResponseEntity<CustomerErrorResponse> handleException(CustomerNotFoundException exc){
  CustomerErrorResponse error = new CustomerErrorResponse(
        HttpStatus.NOT_FOUND.value(),
        exc.getMessage(),
        System.currentTimeMillis());

  return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}

 

 

RestController 클래스의 비즈니스 로직에서 간단하게 예외 발생시에 throw new CustomerNotFoundException; 하고 호출하면 된다. 이렇게 하면 아주 간단하게 에러 호출을 할 수 있다. 

@GetMapping("/customers/{customerId}")
public Customer getCustomer(@PathVariable int customerId){
  Customer theCustomer = customerService.getCustomer(customerId);
  if(theCustomer == null){
    throw new CustomerNotFoundException("Customer id not found - " + customerId);
  }
  return theCustomer;
}
반응형
댓글
반응형
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday