-

[스프링부트 및 JPA] - 예외를 고의로 생성하고 CustomExceptionHandler로 낚아채기 본문

백엔드 기술 정리/스프링 부트

[스프링부트 및 JPA] - 예외를 고의로 생성하고 CustomExceptionHandler로 낚아채기

흣차 2022. 2. 11. 01:16
728x90
반응형

지난 포스팅에 이어서 진행해보도록 하겠습니다.

@ResponseBody 어노테이션을 달 경우 Controller가 붙혀져 있다 하더라도 return할 때 데이터를 return할 수 있다고 했었습니다.

그런데 이렇게 분기를 이용해서 return하게되면 file과 데이터를 다 return할 수는 없기 때문에 이 예외를 공통으로 처리하는 Handler가 필요해지게 됩니다.

그러므로 제가 해볼 것은 if문을 통해서 만약 에러가 발생했다면 이를 errorMap에 담아서 에러가 발생했다고 바로 return하지 않고 throw를 이용해서 나타낼 것입니다. 바로 이렇게요.

그리고 서버를 실행하고 오류를 일부러 발생시키면

다음과 같이 출력이 됩니다.

근데 회원가입하시면서 이렇게 뜨는 사이트를 혹시 보신적 있으신가요???

만약 이런게 뜬다면 제가 사용자였어도 회원가입을 포기하고 말 것입니다.

즉 이렇게 내보내는건 사용자 경험이 좋지 않다고 하여 UX가 안좋다고도 합니다.

 그래서 Exception이 터진 것을 가로채게 만들 것입니다.

즉, Handler를 만들어보겠습니다.

당연히 패키지를 만들어서 관리해주는 것이 좋습니다.

다음과 같이 프로젝트 내부에 handler패키지를 생성하고 클래스도 만듭니다.

ControllerExceptionHandler라는 것은 컨트롤러에서 발생한 예외들을 모두 이곳에서 관리하겠단 뜻입니다.

그리고 이렇게 어노테이션을 걸면, Controller에서 발생하는 모든 Exception을 다 낚아챕니다.

또한 데이터를 응답할 것이기 때문에 @RestController를 붙힙니다.

Handler이지만 어엿한 Controller의 범주에 속하기 때문에 그렇습니다.

그리고 클래스 내부에 validationException이라는 함수에 파라미터로 RuntimeException e를 넣고 return할 때에는 e.getMessage()를 return합니다.

그리고 어노테이션으로 @ExceptionHandler를 거는데 RuntimeException.class라고 적으면 RuntimeException이 발생하는 모든 예외를 ExceptionHandler가 낚아챕니다.

그리고 낚아채서 return할 때 에러 메세지를 띄우는 것입니다.

실제로 서버를 키고 오류를 일부러 발생시켜보면 

이런식으로 텍스트를 띄울 수도 있습니다.

그러니까, RuntimeException이라는 예외를 일부러 만들어서 throw  new 이렇게 던져버리는 상황을 연출해내면 스프링부트가 ExceptionHandler를 통해 이를 낚아채고 메세지도 같이 띄울 수 있는 것입니다.

꼭 다시 이해할 필요가 있습니다.

오류를 "일부러" 발생시켜서 예외를 낚아채게 한 방식에 대해서 말이지요.

자 그런데 이렇게 일부러 메세지를 발생시키면 우리가 어떤 에러가 떴는지 등에 대해서 모를 수 있습니다.

사용자들에게도 어떤게 에러가 났는지 알려줘야 하는데 그냥 "유효성 검사 실패함"이렇게 막무가내로 띄워버리면 이것 또한 사용자 경험(UX)에 좋지 않을 것입니다.

그러므로 어떻게 해주냐면, ex라는 패키지를 하나 만들어보겠습니다. (handler라는 패키지 내부에)

그리고 그 내부에 CustomValidationException이라는 클래스를 만들고 RuntimeException을 상속받습니다.

이후 시리얼 번호를 넣어주는데, 이건 객체를 구분할 때 쓰는겁니다. (중요하지는 않고 JVM할 때 중요합니다.)

최종적으로 이렇게 입력합니다.

CustomValidationExcxeption이라는 함수는 파라미터로 메세지와 errorMap을 받을 것입니다.

그리고 getter를 이용해서 getErrorMap()을 get합니다.

그런데 웃긴게 메세지는 get을 안붙혀도 됩니다.

왜냐하면

RuntimeException이 메세지를 받으면 super한테(부모한테) 메세지를 넘기기 때문이에요.

그런데 부모인 Exception 클래스도 보면

이렇게 super한테 넘기고 있고 이 Exception의 부모는

Throwable인데 여기서 메세지를 받아서 detailMessage로 들어오고 

Throwable의

getMessage()함수는 return할 때 detailMessage를 return하는 것으로 보아 그대로 메세지를 반환하는 것을 알 수 있습니다.

이해하셨나요?

그래서 우리는 단순히 메세지를 따로 getter를 이용해서 안만들어도 되고 부모한테 던져주면 되는 것입니다.

그러므로 이렇게 super(message)만 추가함으로써 자연스래 기존의 message는 굳이 받아올 필요가 없어집니다.

그러므로 이렇게 message 생성을 모두 지우고 super로만 받아오게 설정함으로써 CustomValidationException 만들기가 끝이 났습니다.

그럼 이제 우리가 만든 CustomValidationException을 직접 써먹어봐야겠죠?

ControllerExceptionHandler의 return타입과 갖고오는 Exception을 다음과 같이 바꿉니다.

그런 다음

AuthController에서 단순히 RuntimeException이 아니라 우리가 만든 커스텀엑셉션을 내보내고 메세지와 errorMap을 담아서 예외 발생 시킵니다.

그래서 실제로 예외를 발생시키기 위해 서버를 실행하고 글자 이름을 매우 길게 입력했습니다.

그 결과

이런 오류가 뜨는 것을 알 수 있습니다.

어떤가요?

일부러 에러를 도출해낼 때 Handler를 이용해서 직접 error를 담고 메세지를 출력하게 하니 훨씬 더 깔끔해진 것을 알 수 있습니다.

 

728x90
반응형
Comments