비즈니스 로직은 서비스 계층에 있다.

 

 

 

비즈니스 로직 예외 던지기(throw) 및 예외 처리

 

 

➤ 체크 예외(Checked Exception)와 언체크 예외(Unchecked Exception)

 

애플리케이션에서 발생하는 예외는 크게 Checked ExceptionUnchecked Exception으로 구분된다.

 

▶️ Checked Exception

  • 발생한 예외를 잡아서(catch) 체크한 후 해당 예외를 복구하거나 회피하거나 하는 등의 구체적인 처리를 해야하는 예외이다.
  • 대표적인 예 : ClassNotFoundException

 

 

▶️ Unchecked Exception

  • 예외를 잡아서(catch) 해당 예외에 대한 어떤 처리를 할 필요가 없는 예외이다.
  • 명시적으로 잡아서 어떤 처리를 할 필요는 없다.
  • 대표적인 예 : NullPointerException, ArrayIndexOutOfBoundsException

 

 

코드를 잘못 작성해서 생기는 이런 오류들은 모두 RuntimeException을 상속한 예외들이다.

Java나 Spring에서 수많은 RuntimeException을 지원하지만 RuntimeException을 이용해서

직접 예외(Exception)을 만들어야 하는 경우도 있다.

 

 

 

➤ 의도적으로 예외를 던질 수 (throw) 있는 상황

 

  • 백엔드 서버와 외부 시스템과의 연동에서 발생하는 예외 처리
  • 시스템 내부에서 조회하려는 리소스(자원)가 없는 경우

 

의도적으로 예외를 던져서 클라이언트 쪽에 발생한 에러 정보를 알려줄 수 있다.

 

 

 

➤ 의도적인 예외 throw / catch

 

java에서 throw 키워드는 예외를 메서드 바깥으로 던져준다.

던져진 예외는 메서드 바깥 즉, 메서드를 호출한 지점으로 던져지게 된다.

 

그렇다면 서비스 계층에서 예외를 던지면 어디로 던져질까?

서비스 계층의 메서드는 API 계층인 Controller의 Handler Method가 이용한다.

-> 서비스 계층에서 던져진 예외는 Controller의 Handler Method 쪽에서 잡아서 처리할 수 있다.

 

따라서 Controller에서 발생하는 예외 처리를 위한 Exception Advice 클래스에 서비스 계층에서 던진 예외도 작성해서 처리하면 된다.

 

 

✅ 서비스 계층에서 의도적으로 던질 수 있는 예외는 1가지만 존재하진 않는다.

예를 들어 아래의 경우 모두 예외 상황이 생길 수 있다.

  • 회원 정보가 존재하지 않을 경우
  • 회원 등록 시 이미 존재하는 회원일 경우
  • 로그인 패스워드 검증에서 일치하지 않는 경우

 

이럴 때 handle에러이름Exception()과 같이 메서드 이름을 짓는 것은 적절하지 않다.

그리고 추상적인 RuntimeException 을 그대로 전달 받는 것도 바람직 하진 않다.

 

서비스 계층에서 RuntimeException 을 그대로 throw하고, Exception Advice에서 RuntimeException을 그대로 catch 하는 것은 예외의 의도가 명확하지 않고 구체적으로 어떤 예외가 발생했는지에 대한 정보를 얻는 것이 어렵다.

 

 

 

사용자 정의 예외(Custom Exception) 사용

 

ExceptionCode 를 enum으로 미리 직접 작성해둔다.

BusinessLogicException 클래스를 생성하여 RuntimeException을 상속한다.

super() 상위 클래스 생성자로 RuntimeException에 구체적인 예외 정보 (Exception Code)를 던진다.

 

Exception Advice 클래스에서

메서드 명이 서비스 계층의 비즈니스 로직 처리에서 발생하는 예외를 처리하는 것을 목적으로 한다.

-> handleBusinessLogicException

 

RuntimeException을 파라미터로 전달 받던 것을 BusinessLogicException을 전달 받는 것으로 변경한다.

 

@ResponseStatus(HttpStatus.NOT_FOUND) 제거

ResponseStatus는 고정된 HttpStatus를 지정하므로 다양한 Status를 동적으로 처리할 수 없다.

-> 대신 ResponseEntity를 사용해서 커스텀한 예외 코드(상태)를 전달한다.

 

 

 

▶️ @RestControllerAdvice 에서 ResponseStatus vs ResponseEntity

 

@ResponseStatus : 

한가지 유형으로 고정된 예외를 처리할 경우 HttpStatus를 지정해서 사용

 

@ResponseEntity :

BusinessLogicException 처럼 다양한 유형의 Custom Exception을 처리하고자 할 경우

 

 

▶️ of() 정적 팩토리 메서드

 

new를 직접 사용하지 않고 클래스의 인스턴스를 생성한다.

장점 : 이름을 통해 객체의 의미를 알 수 있다.

 

 

 

 

 

읽어주셔서 감사합니다^^ 좋은하루 되세요 🤗