👩💻 Exception Handling
📌컨트롤러 예외처리
✏️ 왜 예외처리를 해야할까?
예외란 프로그램 실행 중에 발생하는 예상치 못한 상황을 말한다. 이를 적절하게 처리하지 않으면 프로그램이 비정상적으로 종료될 수 있다.
예를들어 파일 업로드 기능을 가진 스프링 웹 애플리케이션에서 발생할 수 있는 예외 상황을 생각해보자.
사용자가 허용 된 최대 파일 크기를 초과하는 파일을 업로드하려고 할 때, 스프링은 "파일 크기가 너무 큽니다. 더 작은 파일을 업로드해주세요."와 같은 메시지를 사용자에게 제공하여 즉시 오류를 이해하고 수정할 수 있도록 돕는다.
✏️ 예외 복구 범위
| 영역 | 예외 처리 | 예시 |
| 메소드 영역 | try / catch | 메소드 영역은 종속된 복구 기능으로 단순히 try/catch를 사용하면 된다 |
| 클래스 영역 | @ExceptionHandler | 클래스 내 공통 예외 복구는 @ExceptionHandler를 사용하면 된다. |
| 전역 영역 | @ControllerAdvice | 여러 클래스의 공통 예외 복구는 @ControllerAdvice를 사용하면 된다. |
📌 @ExceptionController
✏️ @ExceptionHandler
: 클래스 내 공통 예외 처리해주는 annotation

- @ExceptionHandler({RuntimeException.class}):RuntimeException 예외를 처리하는 메서드임을 나타냄.
즉, 이 메서드는 RuntimeException 또는 이를 상속받은 예외가 발생했을 때 실행 - public ResponseEntity<?> NotFoundBoard(RuntimeException runtimeException):
RuntimeException을 매개변수로 받으며, 이 예외 객체를 사용하여 처리 로직을 수행 - return ResponseEntity.badRequest().body(runtimeException);: 예외가 발생했을 때 HTTP 응답 상태 코드를 400(Bad Request)로 설정하고, 예외 객체 자체를 응답 본문으로 반환
컨트롤러 내에서 @ExceptionHandler 어노테이션을 사용하여 특정 예외를 처리하는 메서드를 정의하는 부분.
이 어노테이션을 통해 해당 컨트롤러 내에서 발생할 수 있는 예외를 특정 상황에 맞게 처리할 수 있다.
📌 ControllerAdvice
✏️ ControllerAdvice
:전역에서 발생할 수 있는 예외를 잡아 처리해주는 annotation

- @ExceptionHandler: 특정 예외 타입을 처리하는 메서드를 지정할 때 사용
- {NullPointerException.class}: NullPointerException 예외를 처리하는 것을 의미
- public ResponseEntity<?> NotFoundMember(final NullPointerException ex):
NullPointerException이 발생했을 때 실행 - ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex):
HTTP 상태 코드를 404(Not Found)로 설정하고, 예외 객체(ex)를 응답 본문으로 반환
이 ControllerException 클래스는 다음과 같은 역할을 한다.
여러 컨트롤러에서 발생할 수 있는 예외들을 중앙에서 처리하여 일관된 방식으로 응답을 생성한다.
@ExceptionHandler 어노테이션을 사용하여 각 예외 타입별로 별도의 처리 로직을 구현할 수 있으며, ResponseEntity를 사용하여 HTTP 상태 코드와 예외 객체를 클라이언트에게 반환한다.
📌 Custom Exception 만들기
✏️ Custom Exception이란 무엇이고, 왜 사용해야 할까?
: 만약 사용자가 잘못된 방식, 접근을 하였을 경우 Exception을 어떻게 처리해주면 좋을까?
만약 사용자가 아이디 또는 비밀번호를 잘못 입력하여 Exception을 마주했다고 했을 때 표준 명시된 Exception이 나가버린다면, 사용자는 자기가 무엇을 잘 못 했는지 알 방법이 없다. 그렇다면 당연히 로그인도 안하고.....서비스를 이용하지 않을 것 이다...🥹
이뿐만 아니라 회원가입을 한다고 하였을 때, 필수 항목을 입력하지 않고 회원가입을 눌렀는데 표준 명시된 Exception으로 에러 메시지를 전송한다면 프론트는 정확히 어떤 필드가 문제인지 파악하기 어려울 수 있다.
이러한 문제를 해결하기 위해선 우리가 직접 예외처리를 생성해주어야한다~!
✏️ 실습

CustomeException: 커스텀 예외 클래스
CustomExceptionHandler: 예외를 처리해주는 핸들러
Error: 에러 메시지를 정의한 enum
ErrorResponse: Error Dto

"Error" enum은 각 예외 상황에 대한 상태코드와 에러 메시지를 정의 함
"state"와 "errorMessage"필드는 각 상수에 대해 초기화 된다.
💡ENUM 클래스
: Enum은 상수들의 집합
Enum은 상수들의 집합으로, 각 상수는 클래스 내에서 정의된 순서대로 생성된다. 따라서 Enum 클래스 내의 요소들은 보통 다음과 같은 순서로 정의된다.
1. Enum 상수들: 각각의 Enum상수들이 먼저 정의 됨
2.필드들: 각 Enum 상수들이 사용할 필드들이 정의 됨
3. 생성자와 메서드: Enum 상수들이 사용할 생성자 또는 메서드들이 정의 됨
따라서 보통은 Enum 상수들을 먼저 정의하고, 이후에 Enum 상수들이 공유할 필드들을 정의한다.
이는 코드의 가독성을 높이고, Enum 상수들이 정의될 때 필드들이 이미 준비되어 있어서 초기화를 수월하게 할 수 있기 때문이다.

BoardController에서 제목으로 Board를 찾아왔을때 board값이 null이라면 CustomException 예외가 터지도록 하였다.
매개변수값으로는 위에 정의한 Enum중 글이 없다는 errorMessage가 담긴 NOT_FOUND_BOARD를 넣어주었다.

직접 만든 CustomException은 RuntimeException을 상속받으며, CustomExcpetion 예외처리가 생성되었을 때
부모 클래스인 RuntimeException의 생성자를 호출하여 예외 메시지로 Error enum에서 가져온 메시지(
error.getErrorMessage())를 전달한다.
이후 생성자 파라미터로 받은 Error enum을 error 필드에 저장한다.
* 사실 error enum안에 state 필드가 있어 굳이 CustomException클래스에서 state 필드를 받지않고, CustomException에서 ErrorResponse를 만들 때 ex.getError().getState()를 하면 되는데 CustomException 코드가 길어지는 게 싫어서 여기서 필드로 받았다..~~ *


[CustomExceptionHandler]
@RestControllerAdvice와 @ExceptionHandler를 사용한 예외 처리 클래스
CustomException이 발생할 경우, 해당 예외에 맞는 HTTP 상태 코드와 오류 메시지를 포함한 JSON 응답을 클라이언트에게 반환하는 역할을 한다. 이를 통해 예외 상황을 명확히 전달하고, 클라이언트가 적절히 처리할 수 있도록 도와준다.
[ErrorResponse]
예외 상황에 대한 정보를 클라이언트에게 전달하는 DTO
✏️ CustomException 예외가 발생했을 때 반환 값

throw new CustomException(Error.NOT_FOUND_BOARD); 예외가 터졌을 때

예외처리 결과
'Spring' 카테고리의 다른 글
| [SQL]Error: 1406-22001: Data too long for column '?' at row 1 (0) | 2024.10.01 |
|---|---|
| [Spring Security] Security 기본 (0) | 2024.08.29 |
| [Mockito] Mockito란 무엇일까? (0) | 2024.07.04 |
| [Spring] 연관관계 매핑 (0) | 2024.06.30 |
| [Spring] Jsoup를 사용한 html 파싱 (0) | 2024.06.17 |