느리더라도 꾸준히

회고록(32) - MVC의 예외처리, 비즈니스로직에서의 의도된 예외처리 본문

(CodeStates)Daily memoir

회고록(32) - MVC의 예외처리, 비즈니스로직에서의 의도된 예외처리

테디규 2022. 12. 22. 03:24

1. 데일리 일기

이번주는 SPRING MVC를 컨텐츠로 공부하여 시간이 남았다. 처음에는 스프링에서 제공하는 스펙도 뒤져보고 공식문서도 읽었지만 어느 순간 부터 조금 해이해 지고 있다.

스펙의 개념을 이해하는거랑 내 손에 익는 건 다른 내용이라고 한다. 주말에 처음부터 끝까지 한번 스스로 다 쳐보면서 MVC 전부 리마인드 할수 있는 시간을 가져야 할 것 같다.

2. 오늘 배운 내용.

SpringMVC 에서의 예외 처리

@ExceptionHandler

SpringMVC 에서는 @ExceptionHandler 를 메서드 단위에 입력하여 예외를 처리할 수 있다.

기본적으로는 컨트롤러에 입력하여 사용할 수 있지만, 컨트롤러에게 예외처리의 역할을 마저 부여하게 된다.

또한 각 Controller 마다 해당 메서드를 선언해 주어야 하므로, 수많은 코드 중복이 일어난다.

@RestControllerAdvice

위의 컨트롤러에 너무 많은 역할을 주는 문제를 해결하기 위해, AOP에서 부가기능을 따로 Ascpect 클래스에 모아둔것 처럼 예외들을 처리해주는 부가기능을 모아둔 @RestControllerAdvice 를 클래스 단위로 적용할 수 있다.

동작 방식

Controller에서 Exception이 발생하게 되면 @RestControllerAdvice가 선언된 클래스로 들어오게 되는데 해당 예외는 구체타입을 기준으로 알맞은 파라미터를 가진 메서드를 호출시킨다.

장점

예외 처리를 공통화 시킴으로써 코드 중복을 막을 수 있다.

  • 여러 Controller의 예외를 가져오고 여러 ExceptionHandler 메서드들을 선언하고 있으므로 코즈 중복을 막을수 있다.

Exception의 정보를 가공해서 가져오는 Error Response 클래스

@ExceptionHandler 를 적용한 메서드에 Exception이 들어오지만, 해당 Exception들은 너무 복잡한 에러 정보를 가진 객체를 제공하므로 클라이언트나, 사용자에게 필요없는 에러 정보들을 제공 할수가 있습니다.

그러므로 사용자 정의 클래스로 선언하여, 여러 에러 정보를 가진 객체에서 필요한 정보만 뽑아서 가지고 있도록 할수 있습니다.

이 클래스들은 Error Response 바디에 사용되므로, Error Response 클래스라고 부르겠습니다.

  • 따지자면 이런 Error Response 클래스는 에러 정보를 제공하는 응답 DTO 클래스라고 볼수 있습니다. 그러므로 해당 클래스의 필드내용대로 응답 메세지 바디가 생성됩니다.
  • 필드에 자바 기본자료형들이 들어가면 응답메세지에서 Json 방식으로 변환합니다.
  • 필드에 객체나 컬렉션이 들어가게 된다면 응답메세지에서 배열안에 Json이 들어있는 방식으로 변환합니다.

장점

사용자 정의로 Error Response 클래스를 사용하면 클라이언트에게 필요한 정보를 더 친절하게 제공 할 수 있습니다.

비즈니스 로직에 대한 예외 처리

Checked Exception과 unChecked Exception

Checked Exception

  • 발생한 예외가 컴파일 시점에 체크하므로 예외를 처리하든 회피하든 어떠한 구체적인 처리를 해주어야 하는 예외입니다.
  • SQLException, ClassNotFoundException 등이 있습니다.
  • Unchecked Exception을 제외하면 모두 Checked Exception으로 봅니다.

Unchecked Exception

  • 예외를 잡아서 해당 예외에 대한 어떤 처리를 할 필요가 없는 예외를 의미합니다.
  • NullPointerException, ArrayIndexOutOfBoundsException 등이 있습니다.
  • 대부분 개발자의 실수로 발생하는 RuntimeException을 상속하는 예외들 입니다.

언제 필요할까?

Controller에서는 URI를 잘못입력하거나, http 메서드를 잘못매핑하거나, 요청메세지에서 가져온 데이터가 유효성 검증을 통과하지 못했거나 등 의 이유로 예외 처리를 해주어야 합니다.

그렇다면 Service 계층에서 예외를 처리해야하는 일이 언제가 있을까요?

회원 ID를 통해 DB에서 회원 조회를 했는데 회원이 존재하지 않는 경우가 있습니다. 이럴때는 비즈니스 로직으로 처리할 수 없는 문제이므로 얼른 예외를 발생시켜 클라이언트에게 해당 회원이 존재하지 않는다고 알려야 합니다.

즉 개발자가 의도적으로 예외를 던지는 것입니다. 그러므로 이때 RuntimeException을 사용하게 됩니다.

어떻게 예외 처리를 할까?

일반적으로 Controller 계층은 Sevice 계층의 메서드를 호출하여 연동 하고 있습니다. 그러므로 해당 메서드에서 예외 상황이 발생시 예외를 발생시키도록 하면됩니다.

@Service
public class MemberService {
    ...
		...

    public Member findMember(long memberId) {
        // TODO should business logic
				
				// (1)
        throw new RuntimeException("Not found member");
    }

		...
		...
}

사용자 정의 예외(Custom Exception)

위 코드처럼 RuntimException 으로 처리하게 되면 너무 상위 계층의 예외이므로 어떤 이유로 예외가 발생하게 되었는지 알수 없게 됩니다.

그리고 클라이언트는 해당 예외를 통해 얻는 정보로는 정확히 어떤 것이 문제인지 알기 힘듭니다.

그러므로 우리는 사용자 정의 예외를 만들어 원하는 정보를 넣을 수 있습니다.

  • 만약 정확하게 회원 아이디가 없는 예외를 만들어 응답상태 404 와 메세지 “해당 회원 정보는 저장소에 저장되어 있지 않습니다” 라고 했다고 합시다. 클라이언트는 상태코드와 메세지를 통해 어떠한 문제로 예외가 발생했는지 알 수 있을 것입니다.

정리후 모르겠는 내용

Comments