스프링부트 Exception Handling

dragonappear·2022년 1월 31일
0

Spring & SpringBoot

목록 보기
5/11


출처 및 참고:

  • "Spring boot 에러처리하기! (feat. @ExceptionHandler & @ControllerAdvice)",tistory(Alxndr),2020년11월12일수정,2022년1월13일작성,https://dev-alxndr.tistory.com/18

스프링 부트를 사용하면서 컨트롤러에서 발생하는 예외를 처리하는 방법을 알아보자

  1. @ExceptionHandler
  2. @ControllerAdvice

컨트롤러에서 발생하는 예외를 매번 try catch문으로 감싸면 난리난다~
공통로직, 반복적인것을 계속해야 하니까 엄청 귀찮아진다. 그럴때 쓰라는게 AOP이다.


@ExceptionHandler

먼저 커스텀하게 NotFoundException 클래스를 생성하자.
주로 런타임 중 발생하는 예외를 처리해야하는 경우가 많기 때문에 RuntimeException을 상속받고, code라는 멤버 변수를 필드로 가지고 있는다.

NotFoundException.java

public class NotFoundException extends RuntimeException {

      public final static int INDEX_NOT_FOUND = 101;
      public final static int BOARD_NOT_FOUND = 201;

      private final int code;

      public int getCode() {
          return code;
      }

      public NotFoundException(int code) {
          this.code = code;
      }

      public NotFoundException(int code, String message) {
          super(message);
          this.code = code;
      }
  }

ErrorCode.java

 public enum ErrorCode {

      INDEX_NOT_FOUND(1001, "인덱스가 존재하지 않습니다."),
      BOARD_NOT_FOUND(1002, "게시글을 찾을 수 없습니다.");

      private int errorCode;
      private String errorMessage;

      public String getErrorMessage() {
          return errorMessage;
      }

      public int getErrorCode() {
          return errorCode;
      }

      ErrorCode(int errorCode, String errorMessage) {
          this.errorCode = errorCode;
          this.errorMessage = errorMessage;
      }
  }

에러코드를 Enum으로 관리하여 필요한 에러코드를 뽑아서 사용할 수 있도록 만들었다.
이렇게 하면 좀 더 체계적으로 에러코들르 관리할 수 있을 것 같다.

IndexController.java

@GetMapping("/exception-test")
public ResponseEntity notFound() {
throw new NotFoundException(ErrorCode.INDEX_NOT_FOUND.getErrorCode(), ErrorCode.INDEX_NOT_FOUND.getErrorMessage());
}

@ExceptionHandler(NotFoundException.class)
public ResponseEntity<ErrorResult> notFoundException(NotFoundException e) {
	ErrorResult er = new ErrorResult();
	er.setCode(e.getCode());
	er.setStatus(HttpStatus.NOT_FOUND);
	er.setMessage(e.getMessage());
	return ResponseEntity.status(HttpStatus.NOT_FOUND).body(er);
}
  • /exception-test라는 엔드포인트를 가진 API를 만들고 NotFoundException을 발생시킨다. 그 때 위에서 만든 ErrorCode Enum 클래스에서 에러코드와 에러메시지를 받아서 넣어준다.
  • 그리고 아래에 ExceptionHandler 어노테이션을 가진 메서드를 만든다.
    • 위 메서드는 notfound() 에서 NotFoundException 예외를 처리한다.
  • 서버를 실행한 후 /exception-test를 실행시켜보면 아래와 같이 NotFoundException을 처리한다.

모든 클래스에서 메서드마다 발생하는 발생하는 @ExceptionHandler를 중복해서 만들어야 할까?


ControllerAdvice

여러 클래스에서 터진 Exception들을 처리할 수 있는 @ControllerAdivce를 어노테이션으로 가지는 클래스를 만들어보자.

@RestController
@ControllerAdvice
public class CustomizedResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(Exception.class)
    public final ResponseEntity<Object> handleAllExceptions(Exception ex, WebRequest request) {
        ExceptionResponse exceptionResponse =
                new ExceptionResponse(new Date(), ex.getMessage(), request.getDescription(false));

        return new ResponseEntity(exceptionResponse, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @ExceptionHandler(UserNotFoundException.class)
    public final ResponseEntity<Object> handleUserNotFoundException(Exception ex, WebRequest request) {
        ExceptionResponse exceptionResponse =
                new ExceptionResponse(new Date(), ex.getMessage(), request.getDescription(false));

        return new ResponseEntity(exceptionResponse, HttpStatus.NOT_FOUND);
    }

    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
                                                                  HttpHeaders headers,
                                                                  HttpStatus status,
                                                                  WebRequest request) {
        ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(),
                "Validation Failed", ex.getBindingResult().toString());

        return new ResponseEntity(exceptionResponse, HttpStatus.BAD_REQUEST);
    }
}
  • 위에서 만든 클래스로 인해 이제 여러 컨트롤러에서 발생하는 예외를 한 곳에서 처리할 수 있게 되었다.
    • AOP로 동작하기 때문에 이러한 처리가 가능해진다.

0개의 댓글