사용자정의 exception과 Response 방법

프로젝트

목록 보기
37/39
post-thumbnail

💡 사용자 정의 Exception?

  • 사용자 정의 Exception들은 RuntimeException을 상속받는다.
    개발자는 컴파일러가 감지하지 못하는 예외만 예의주시하면 된다. 이게 바로 RuntimeException이다.
    • 왜냐하면, RuntimeException은 컴파일러에 의해 감지가 안되므로, 예외가 발생하면 프로그램이 죽는다.
  • 예외를 처리할 수 있는 방법은 크게 2개가 있는데, try-catchthrows다.
    둘 중 하나를 쓰던지 안써도 되는데, 예외 처리를 했건 안했건 런타임 Exception이기 때문에 컴파일이 되긴한다.
    하지만, 여기서 예외가 생기면 프로그램이 죽어버리니까 문제가 되는 것이다.
  • 그래서 이 때 이를 바로 잡아주기 위해서 의미 있는 이름으로 throw로 예외를 강제발생시켜준다.
    throw로 예외를 강제발생시켜준 후, throws를 통해 메서드로 예외를 떠넘긴다. 부모익셉션을 메서드에 throws로 던져줘도 된다.(부모는 즉 사용자정의 여러개쓰지 않고, RuntimeException 하나로 처리)
    이렇게 하면, 메서드로 던져진 예외가 JVM까지 가지 않고, 메인메서드인 SpringApplication까지만 가서 프로그램이 죽지 않도록 방지해준다.

💡 Response 방식

  • Exception이 발생할 때, 에러코드(ErrorCode)와 상세정보 메시지- (details)를 담아서 보내주고, 우리는 JSON으로 응답하는 Restful방식을 사용하므로, @RestControllerAdvice를 사용하여 예외에 대한 응답도 JSON형식으로 보내준다. Exception이 발생하게 되면 ExceptionHandler가 이를 잡아오고, JSON형식과 에러코드를 ResponseEntity에 담아서 컨트롤러에서 보내준다.

프로젝트에 적용한 사용자 정의 Exception과 Response하는 방법

  1. 사용자의 요청이 들어오면 Controller에서 service를 호출함
  2. service에서 throw Exception(에러코드, 메시지) 를 던지면, GlobalExceptionHandler(말 그대로 exception 핸들러)가 controller에서 던진 예외(controller가 service를 호출하므로)를 잡아오고
    exception을 던질 때 같이 보내줬던 에러코드와 메시지(detail)를 같이 가져와서

GlobalExceptionHandler

↳ GlobalExceptionHandler에서 exception을 통해 가져온 에러코드와 메시지를 ErrorResponse 객체의 변수에 넣어줌

ErrorResponse ⬇︎⬇︎⬇︎

  1. 그 후 핸들러가 ErrorResponse를 담아서 ResponseEntity<>(response, HttpStatus.에러코드)로 컨트롤러에 보내서 사용자에게 에러를 넘겨준다.
  2. 이 에러는 사용자가 볼 수 있음 → 프론트에서 보여지도록 하면 된다.

Return new ResponseDetails

: exception을 던지지 않고 에러 코드 & 메시지를 응답할 경우
: 이 두개가 다른 점은 https://velog.io/@serringg/%EC%97%90%EB%9F%AC-return%EA%B3%BC-exception%EC%9D%98-%EC%B0%A8%EC%9D%B4 에 적어놨다.

  1. throw와 비슷하게 throw exception 대신 return new ResponseDetails(메시지, 에러코드, 경로); 를 던져주는 방식

  2. service에서 분기처리를 할 때, exception 대신 ResponseDetails의 생성자를 이용해서 값을 넣어준다.

  • 위의 사진은 ResponseDetails의 생성자.
    잘 보면 ErrorResponse의 변수들과 매우 흡사하다.
  • service에서 return new ResponseDetails(data, httpStatus, path); 에 맞춰 값을 잘 넣어준다. httpStatus는 ErrorCode 클래스에서 잘 보고 상황에 맞는 값을 넣어주면 됨
  • 여기서 log.info에 [ userId : {} , userPoint : {} ] 가 생소할 수 있다. log.info("메시지 userId : {} , userPoint : {}", 값1, 값2) 가 있을 경우, 값1 값2는 {}의 순서대로 잘 들어가서
    나중에 로그에 메시지 userId : {값1}, userPoint : {값2} 와 같이 잘 들어간다.

Controller에서 처리 방법

  • controller에서는 ResponseDetails값을 넣어 ResponseEntity의 형태로 값을 내보낸다.
  • controller에서 service를 호출할 때
    ResponseDetails responseDetails = orderService.getOrderByUserId(user, num) 와 같이 하는데, orderService의 getOrderByUserId 메서드에서 성공했던 값이던 에러가 나서 httpStatus 400 코드 값을 포함하던간에
    service에서 return new ResponseDetails(data, httpStatus, path) 로 값을 잘 넘겨줬다면 에러코드 값과 상관없이 그 결과를 controller를 통해 사용자에게 값을 보여준다.
  • controller에서 ResponseDetails responseDetails = service.메서드 일 때, throws는 어차피 transactional달아서 중간에 예외 던지고 롤백할거라 return 400하는거 아니면 마지막에 200으로 내보낸 성공응답만 내보낼 것임
profile
백엔드를 공부하고 있습니다.

0개의 댓글