๐ ์ค๋ ๋ฐฐ์ด ๋ด์ฉ!
- @ExceptionHandler
- @RestControllerAdvice
- ์์ธ Throw / Catch
- Custom Exception
โ๏ธ @ExceptionHandler ์์ธ ์ฒ๋ฆฌ
์ ํ๋ฆฌ์ผ์ด์ ์์ ์์ธ(Exception)๊ฐ ๋ฐ์ํ์ ๋, ๋ด๋ถ์ ์ผ๋ก Spring์์ ์์ธ๋ฅผ ์ฒ๋ฆฌํ์ฌ ํด๋ผ์ด์ธํธ์ ์๋ต์ผ๋ก ์๋ฌ ๋ฉ์ธ์ง๋ฅผ ๋ณด๋ด์ฃผ๋๋ฐ,
์ด ๋ ํด๋ผ์ด์ธํธ๋ ์ด๋์์ ์์ธ๊ฐ ๋ฐ์ํ๋์ง ์ฝ๊ฒ ์ ์ ์์
โ @ExceptionHandler ์ฌ์ฉํ์ฌ ์๋ฌ ์๋ต ๋ฉ์ธ์ง๋ฅผ ์ง์ ์์ฑํ์ฌ ์๋ต์ผ๋ก ๋ณด๋ด์ค ์ ์์ !
- Controller ๋ ๋ฒจ์์๋ง ์ฌ์ฉ
- ์์ธ์ฒ๋ฆฌ๋ฅผ ํ ํธ๋ค๋ฌ ๋ฉ์๋๋ฅผ ์์ฑํ๊ณ , ๊ทธ ์์
@Exception
์ ๋ํ ์ด์ ์ ๋ถ์ฌ ์๋ฌ ๋ฉ์ธ์ง๋ฅผ ๊ตฌ์ฒด์ ์ผ๋ก ์ ์ก ๊ฐ๋ฅ
( But, ์์ ๊ฒฝ์ฐ ์๋ฌ ์ ๋ณด ๋ฟ๋ง ์๋๋ผ Response Body ์ ์ฒด ์ ๋ณด๊น์ง ์ ๋ฌ๋จ ! )
โ ๊ณตํต๋๋ ์๋ฌ๋ ErrorResponse ํด๋์ค
๋ฅผ ๋ฐ๋ก ๋ง๋ค์ด DTO ํด๋์ค์ ์ ํจ์ฑ ๊ฒ์ฆ ์คํจ ์, ์คํจํ ํ๋(๋ฉค๋ฒ ๋ณ์)์ ๋ํ Error ์ ๋ณด๋ง ๋ด์์ ๊ทธ ํด๋์ค ๋ด์ FieldError
ํด๋์ค๋ก ์๋ต์ผ๋ก ์ ์ก ๊ฐ๋ฅ
โ ์ด ๊ฒฝ์ฐ, ์๋ฌ๊ฐ ์ฌ๋ฌ๊ฐ๊ฐ ๋ ์ ์๊ธฐ ๋๋ฌธ์, ํธ๋ค๋ฌ ๋ฉ์๋ ๋ด์์ FieldError
ํด๋์ค๋ List ๊ฐ์ฒด
๋ฅผ ์ด์ฉํ์ฌ ์๋ฌ ์ ๋ณด๋ฅผ ๋ด๊ณ ๋๊ฒจ์ค ์ ์์
โ๏ธ ErrorResponse ํด๋์ค
โ ์๋ฌ ๊ฒ์ฌํ ํญ๋ชฉ ์ ๋ฆฌํ๋ ํด๋์ค
โ๏ธ @ExceptionHandler์ ๋จ์
- ๊ฐ ํด๋์ค๋ง๋ค @Exception ์ ๋ํ
์ด์
์ ์ฌ์ฉํ์ฌ ์๋ฌ ์ฒ๋ฆฌ๋ฅผ ํด์ผํ๋ฏ๋ก
๊ฐ Controller ํด๋์ค๋ง๋ค ์ฝ๋์ ์ค๋ณต์ด ๋ฐ์
- ํ๋์ Controller ํด๋์ค ๋ด์ ์ฒ๋ฆฌํด์ผํ ์์ธ๊ฐ ์ ํจ์ฑ ๊ฒ์ฆ ์คํจ์ ๋ํ ์์ธ(MethodArgumentNotValidException)๋ง ์๋๊ฒ์ด ์๋๊ธฐ ๋๋ฌธ์,
ํ๋์ Controller ํด๋์ค ๋ด์@ExceptionHandler
๋ฅผ ์ถ๊ฐํ ์๋ฌ ์ฒ๋ฆฌ ํธ๋ค๋ฌ ๋ฉ์๋๊ฐ ๋์ด๋จ
Ex. patchMember() ํธ๋ค๋ฌ ๋ฉ์๋์ URI ๋ณ์์ธ “/{member-id}”์ 0์ด ๋์ด์ฌ ๊ฒฝ์ฐ,
ConstraintViolationException์ด ๋ฐ์
โ ๊ทธ Controller ํด๋์ค ์์๋ ์ ํจ์ฑ ๊ฒ์ฌ ํธ๋ค๋ฌ ๋ฉ์๋ + ์ด ์์ธ๋ฅผ ์ฒ๋ฆฌํ ํธ๋ค๋ฌ ๋ฉ์๋ ์ด๋ ๊ฒ ๋๊ฐ๊ฐ ์๊น
โ๏ธ @RestControllerAdvice๋ฅผ ์ฌ์ฉํ ์์ธ ์ฒ๋ฆฌ ๊ณตํตํ
- Controller ํด๋์ค ๋ด์์ ์์ธ ์ฒ๋ฆฌ๋ฅผ ํ๋ ๋์ @RestControllerAdvice ์ ๋ํ
์ด์
์ฌ์ฉํ์ฌ ์๋ก ํด๋์ค ๋ง๋ค๋ฉด,
๊ทธ ํด๋์ค์์ ์์ธ ์ฒ๋ฆฌ๋ฅผ ๊ณตํตํํ์ฌ ์ฌ๋ฌ Controller ํด๋์ค์์@ExceptionHandler/@InitBinder/@ModelAttribute๊ฐ ๋ถ์ ๋ฉ์๋ ๊ณต์ ํ์ฌ ์ฌ์ฉ ๊ฐ๋ฅ
๐ก @InitBinder / @ModelAttribute ์ ๋ํ ์ด์
โ ์ฃผ๋ก ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง(SSR, Server Side Rendering) ๋ฐฉ์์์ ์ฌ์ฉ๋๋ ๋ฐฉ์
Ex. JSP, Thymeleaf
@RestControllerAdvice
๊ฐ ๋ถ์ ํด๋์ค์๋ @ExceptionHandler ์ ๋ํ ์ด์ ์ด ๋ถ์๋ ์๋ฌ ์ฒ๋ฆฌ ํธ๋ค๋ฌ ๋ฉ์๋๋ค์ ๋ฃ์ผ๋ฉด ๋จ- ๊ฐ ์ปจํธ๋กค๋ฌ๋ง๋ค ๋ฐ๊ฒฌ๋๋ ์๋ฌ๋ฅผ
@RestControllerAdvice
๊ฐ ์ฒ๋ฆฌ
โ๏ธ @RestControllerAdvice ์ ๋ํ ์ด์ ์ด ๋ถ์ ํด๋์ค
โ ๊ฐ ํธ๋ค๋ฌ ๋ฉ์ธ์ง์ ์๋ฌ ์๋ต ์ ๋ฌํ๋ ํด๋์ค
- ์ด ํด๋์ค์๋ @ResponseStatus ์ ๋ํ
์ด์
์ด ๋ถ์ ์ ์์
( ResponseEntity๋ก ๋ฐ์ดํฐ ๋ํํ๋ ๊ฒฝ์ฐ์๋ ์ฌ์ฉ X / ErrorResponse๋ก ๋ํํ๋ ๊ฒฝ์ฐ์๋ง ์ฌ์ฉ )
โ๏ธ @ResponseStatus ์ ๋ํ ์ด์
โ HTTP Status๋ฅผ ๋์ ํํ
Ex. @ResponseStatus(HttpStatus.BAD_REQUEST)
๐ก @RestControllerAdvice vs @ControllerAdvice
- @RestControllerAdvice = @ControllerAdvice + @ResponseBody
โ
โ @RestControllerAdvice ์ ๋ํ ์ด์ ์ JSON ํ์์ ๋ฐ์ดํฐ๋ฅผ Response Body๋ก ์ ์กํ๊ธฐ ์ํด์ ResponseEntity๋ก ๋ฐ์ดํฐ๋ฅผ ๋ํํ ํ์๊ฐ ์์
โ๏ธ of() ๋ฉ์๋
- ๋ค์ด๋ฐ ์ปจ๋ฒค์ (Naming Convention)
- ๊ฐ์ฒด ์์ฑ์ ์ด๋ค ๊ฐ๋ค์(of~) ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค๋ ์๋ฏธ
- ์์ฑ์์ private ์ ๊ทผ ์ ์ด์๊ฐ ๋ถ์์ ๊ฒฝ์ฐ, ๊ฐ ์ญํ ๊ตฌ๋ถ์ ์ํด
์์ฑ์์ ๊ฐ์ ์ญํ ์ ํ๋ ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋ ์ฌ์ฉ
โ - Ex.
ErrorResponse of(BindingResult bindingResult)
โ An ErrorResponse instance is made of BindingResult object
โ๏ธ ์์ธ ๋์ง๊ธฐ(throw) ๋ฐ ์์ธ ์ฒ๋ฆฌ
โ๏ธ ์ฒดํฌ ์์ธ (Checked Exception)
- ๋ฐ์ํ ์์ธ๋ฅผ ์ก์์(catch) ์ฒดํฌํ ํ์ ํด๋น ์์ธ๋ฅผ ๋ณต๊ตฌ ํ๋ ๊ฐ ์๋๋ฉด ํํผ ํ๋ ๊ฐ ๋ฑ์ ์ด๋ค ๊ตฌ์ฒด์ ์ธ ์ฒ๋ฆฌ๋ฅผ ํด์ผ ํ๋ ์์ธ
โ๏ธ ์ธ์ฒดํฌ ์์ธ (Unchecked Exception)
- ์์ธ๋ฅผ ์ก์์(catch) ํด๋น ์์ธ์ ๋ํ ์ด๋ค ์ฒ๋ฆฌ๋ฅผ ํ ํ์๊ฐ ์๋ ์์ธ
- RuntimeException์ด ์ด์ ํด๋น ( ์ด๋ฅผ ์์๋ฐ์ ํ์ ํด๋์ค๋ ๋ชจ๋ )
โ Java๋ Spring์์ ์๋ง์ RuntimeException์ ์ง์ํด์ฃผ์ง๋ง, ๊ฐ๋ฐ์๊ฐ ์ง์ ์์ธ(Exception)๋ฅผ ๋ง๋ค์ด์ผ ํ ๊ฒฝ์ฐ๋ ์์ !
โ ์์ธ๋ฅผ ๋์ง๋ค๊ณ ํจ
โ ์๋์ ์ผ๋ก ์์ธ๋ฅผ ๋์ง ์(throw) ์๋ ์ํฉ
- ๋ฐฑ์๋ ์๋ฒ์ ์ธ๋ถ ์์คํ
๊ณผ์ ์ฐ๋์์ ๋ฐ์ํ๋ ์๋ฌ ์ฒ๋ฆฌ
โ ๋ฐฑ์๋ ์๋ฒ ์ชฝ์์ ์์ธ๋ฅผ ์๋์ ์ผ๋ก ๋์ ธ์ ํด๋ผ์ด์ธํธ ์ชฝ์ ์๋ฌ๊ฐ ๋ฐ์ํ ์ ๋ณด๋ฅผ ์๋ ค์ค ์ ์์ - ์์คํ
๋ด๋ถ์์ ์กฐํํ๋ ค๋ ๋ฆฌ์์ค(์์, Resource)๊ฐ ์๋ ๊ฒฝ์ฐ
โ ์๋น์ค ๊ณ์ธต์์ ํด๋น ํ์ ์ ๋ณด๊ฐ ์๋ค๋ ์์ธ๋ฅผ ์๋์ ์ผ๋ก ์ ์กํด์ ํด๋ผ์ด์ธํธ ์ชฝ์ ์๋ ค์ค ์ ์์
โ ์์ธ ๋์ง๊ธฐ & ์ฒ๋ฆฌ ๊ณผ์
1. ํด๋ผ์ด์ธํธ๊ฐ Controller์ ํด๋น ํธ๋ค๋ฌ ๋ฉ์๋๋ก ์์ฒญ ๋ณด๋
2. ์์ธ๊ฐ ๋ฐ์ํ๋ค๋ฉด, Service ํด๋์ค์์ RuntimeException์ ๋์ง
Service ํด๋์ค ๋ด์ ํด๋น ํธ๋ค๋ฌ ๋ฉ์๋์๋
throwํค์๋ ์ฌ์ฉํ์ฌ RuntimeException ๊ฐ์ฒด์ ์ ์ ํ ์์ธ ๋ฉ์์ง๋ฅผ ํฌํจ
โ
Ex. throw new RuntimeException("Not found member");
throw new BusinessLogicException(ExceptionCode.MEMBER_NOT_FOUND);
3. @RestControllerAdvice
์ ๋ํ
์ด์
์ด ๋ถ์ ํด๋์ค์ ํด๋น ์์ธ์ ์๋ต์ ๊ตฌํํ๊ณ ์๋ ๋ฉ์๋์์ ๊ทธ throwํ ์์ธ๋ฅผ catchํ์ฌ ๊ฐ์ด ๋ ๋ผ์จ ์์ธ ๋ฉ์ธ์ง๋ฅผ ์ถ๋ ฅํด์ค
โ๏ธ ์ฌ์ฉ์ ์ ์ ์์ธ(Custom Exception)
- ์์ ํด๋์ค์ธ RuntimeException์ ๋ฐํํ๋ ๊ฒ์ด ์๋ ๊ทธ์ ํ์ ํด๋์ค๋ค์ธ ๋์ฑ ๊ตฌ์ฒด์ ์ธ ์์ธ๋ฅผ ํํํ๊ธฐ ์ํด ์ฌ์ฉ
โ ์ ์ฉ ๋ฐฉ๋ฒ
- class๊ฐ ์๋ enum์ผ๋ก ์๋น์ค ๊ณ์ธต์์ ๋์ง Custom Exception์ ์ฌ์ฉํ
ExceptionCode
๋ฅผ ์ ์
โ ๋น์ฆ๋์ค ๋ก์ง์์ ๋ฐ์ํ๋ ๋ค์ํ ์ ํ์ ์์ธ๋ฅผ enum์ ์ถ๊ฐํด์ ์ฌ์ฉํ ์ ์์ - ์์ธ๋ค์ ์ ๋ฆฌํ
ExceptionCode
๋ฅผ ๋ฉค๋ฒ ๋ณ์๋ก ๋ฐ๊ณRuntimeException
์ ์์๋ฐ๋BusinessLogicException
ํด๋์ค๋ฅผ ์ ์
( ์ด ๋, ์์ฑ์์์ exceptionCode.getMessage()
์ ๊ฒฝ์ฐ์๋ ์์ ํด๋์ค์ ์์ฑ์๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ supuer()
ํค์๋ ์ฌ์ฉ )
โ @RestControllerAdvice
์ ๋ํ
์ด์
์ ๊ฐ์ง๊ณ ์๋ ํด๋์ค์๋ ResponseEntity
์ ์ฐ๋ฆฌ๊ฐ ์ ์ํ ErrorResponse
์ฌ์ฉ ๊ฐ๋ฅ
โ๏ธ ResponseEntity
โ ๋ฆฌํด๊ฐ์ผ๋ก HttpStatus๋ฅผ ๋์ ์ผ๋ก ์ง์ ๊ฐ๋ฅ
โ
โ๏ธ ErrorResponse
โ ๊ณ ์ ๋ HttpStatus๋ฅผ ์ง์ ํ๊ธฐ ๋๋ฌธ์ @ResponseStatus ์ ๋ํ ์ด์ ์ผ๋ก HttpStatus๋ฅผ ์ง์ ํด์ค์ผํจ
๐ ์ค์ต
- projects ๋ด์ be-template-exception-handle ํ์ผ
- git ๋ด์ be-homework-exception ํ์ผ
๐ ๋๋์
์ ๋ฒ ํ์ต๊น์ง๋ ๋ฐ๋ผ๊ฐ๊ธฐ ๊ด์ฐฎ์๋๋ฐ ์ค๋์ ๊ฐ์๊ธฐ ์ฝ๋ ์๋ ๋ง์์ง๋ฉด์ ์ดํด๊ฐ ์ด๋ ค์ด ๋ถ๋ถ์ด ๊ฝค ์์๋ค !!
๊ทธ๋๋ ํ์ด ํ์ต ํ๋ฉด์ ํ์ด๋์ด ๋ง์ด ์๋ ค์ฃผ์
์ ์ดํด๊ฐ ๋ง์ด ๋์๋ค! ๐
๊ทผ๋ฐ ํ๋ฃจํ๋ฃจ ์ค์ตํด๋ณด๋ ์ฝ๋์ ์์ด ๋ง๋ค๋ณด๋ ๋ณต์ต์ ์์ฃผ ํด์ค์ผ ์์ง ์์ ๊ฒ ๊ฐ๋ค ใ
( ๋ณธ ๊ฒ์๋ฌผ์ 2022/10/27์ ์์ฑํ ๊ธ์ ์ฎ๊ธด ๊ธ์ ๋๋ค. ์๋ฌธ์ ์๊ธฐ์ ์์! )
'โข CodeStates BootCamp > Section 3' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๐ [Section3] 6. [ Spring MVC ] Spring Data JDBC 2 (1) | 2023.04.10 |
---|---|
๐ [Section3] 5. [ Spring MVC ] Spring Data JDBC 1 (0) | 2023.04.10 |
๐ [Section3] 3. [ Spring MVC ] ์๋น์ค ๊ณ์ธต (0) | 2023.04.10 |
๐ [Section3] 2. [ Spring MVC ] API ๊ณ์ธต 2 (0) | 2023.04.10 |
๐ [Section3] 1. [ Spring MVC ] API ๊ณ์ธต 1 (0) | 2023.04.09 |