애플리케이션에서 발생하는 예외(Exception)는 크게 체크 예외(Check Exception)와 언체크 예외(Unchecked Exception)로 구분할 수 있다.
백엔드 서버와 외부 시스템과의 연동에서 발생하는 에러 처리
시스템 내부에서 조회하려는 리소스가 없는 경우
서비스 계층의 메서드는 API 계층인 Controller의 핸들러 메서드가 이용하므로 서비스 계층에서 던져진 예외는 Controller의 핸들러 메서드 쪽에서 잡아서 처리할 수 있다.
그러나 이미 Controller에서 발생하는 예외를 Exception Advice에서 처리하도록 공통화 해두었다면 서비스 계층에서 던진 예외 역시 Exception Advice에서 처리하면 된다.
throw 키워드를 사용하여 RuntimeException 객체에 적절한 예외 메시지를 포함한 후에 메서드 밖으로 던진다.
@Service
public class MemberService {
...
...
public Member findMember(long memberId) {
// (1)
throw new RuntimeException("Not found member");
}
...
...
}
Controller의 핸들러 메서드에 요청을 보내면 Service에서 RuntimeException을 던지고, ExceptionAdvice의 handleResourceNotFoundException() 메서드가 이 RuntimeException을 잡아서 예외 메시지를 출력할 수 있다.
@RestControllerAdvice
public class GlobalExceptionAdvice {
...
...
// (1)
@ExceptionHandler
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleResourceNotFoundException(RuntimeException e) {
System.out.println(e.getMessage());
return null;
}
}
예외 발생 시 RuntimeException과 같은 추상적인 예외가 아닌 InsufficentBalanceException 같은 해당 예외를 조금 더 구체적으로 표현할 수 있는 Custom Exception을 만들어서 예외 던지기가 가능하다.
import lombok.Getter;
public enum ExceptionCode {
MEMBER_NOT_FOUND(404, "Member Not Found");
@Getter
private int status;
@Getter
private String message;
ExceptionCode(int status, String message) {
this.status = status;
this.message = message;
}
}
import lombok.Getter;
public class BusinessLogicException extends RuntimeException {
@Getter
private ExceptionCode exceptionCode;
public BusinessLogicException(ExceptionCode exceptionCode) {
super(exceptionCode.getMessage());
this.exceptionCode = exceptionCode;
}
}
@Service
public class MemberService {
...
...
public Member findMember(long memberId) {
// (1)
throw new BusinessLogicException(ExceptionCode.MEMBER_NOT_FOUND);
}
...
...
}
@RestControllerAdvice
public class GlobalExceptionAdvice {
...
...
@ExceptionHandler
public ResponseEntity handleBusinessLogicException(BusinessLogicException e) {
System.out.println(e.getExceptionCode().getStatus());
System.out.println(e.getMessage());
return new ResponseEntity<>(HttpStatus.valueOf(e.getExceptionCode().getStatus()));
}
}