[spring MVC] CustomError-throw
Categories: Spring
Tags: MVC, Spring, ๊ฐ๋ ์ ๋ฆฌ, ์ค์ต
๐ ๊ฐ์ธ์ ์ธ ๊ณต๊ฐ์ผ๋ก ๊ณต๋ถ๋ฅผ ๊ธฐ๋กํ๊ณ ๋ณต์ตํ๊ธฐ ์ํด ์ฌ์ฉํ๋ ๋ธ๋ก๊ทธ์
๋๋ค.
์ ํํ์ง ์์ ์ ๋ณด๊ฐ ์์ ์ ์์ผ๋ ์ฐธ๊ณ ๋ฐ๋๋๋ค :๐ธ
[ํ๋ฆฐ ๋ด์ฉ์ ๋๊ธ๋ก ๋จ๊ฒจ์ฃผ์๋ฉด ๋ณต๋ฐ์ผ์ค๊ฑฐ์์]
์์ธ์ฒ๋ฆฌ
์์ธ๋ ํฌ๊ฒ Checked Exception , Unchecked Exception
[์ถ์ฒ]https://rollbar.com/blog/how-to-handle-checked-unchecked-exceptions-in-java/
Checked Exception์ ๋ง๊ทธ๋๋ก ์ฒดํฌํด์ผ ํ๋ ์์ธ
- ๋ฐ์ํ ์์ธ๋ฅผ ์ก์์ ์ฒดํฌํ ํ ํด๋น ์์ธ๋ฅผ ๋ณต๊ตฌ ๋๋ ํํผ๋ฅผ ํด์ ๊ตฌ์ฒด์ ์ธ ์ฒ๋ฆฌ๋ฅผ ํด์ผ ํ๋ ์์ธ
- ๋ํ์ ์ผ๋ก
ClassNotFoundException
Unchecked Exception์ ํด๋น ์์ธ์ ๋ํ ์ด๋ ํ ์ฒ๋ฆฌ๋ฅผ ํ ํ์๊ฐ ์๋ ์์ธ
- ๋ํ์ ์ผ๋ก
NullPointerException
,ArrayIndexOutOfBoundsException
๋ฑ - ํํ ๊ฐ๋ฐ์๊ฐ ์ฝ๋๋ฅผ ์๋ชป ์์ฑํด์ ๋ฐ์ํ๋ ์ด๋ฐ ์ค๋ฅ๋ค์ ๋ชจ๋
RuntimeException
์ ์์ํ ์์ธ๋ค
์์ธ ์์ 1.
- ๊ฐ๋ฐ์์ ์ํฉ์์ ์๊ฐํด๋ณด๋ฉด ์ํธํํ ์ง๊ฐ์ ๋ธ๋ก์ฒด์ธ๊ณผ ํต์ ํ๋ ๊ฒฝ์ฐ๊ฐ ์๊ธฐ๋ฉด A์ฌ์ฉ์๊ฐ B์ฌ์ฉ์์๊ฒ ๋ณด๋ด๋ ค๋ฉด ์๊ณ ๋ฅผ ์ฒดํฌํ๊ณ ๋ณด๋ด์ผ ํจ.
- ์คํจํ๋ฉด ๋ค์ ์ฒ์์ํ๋ก ๋๋์๊ฐ์ผ ํด : transaction
- ๊ฐ๋ฐ์๊ฐ ์ง์ ์ ์ผ๋ก accessํ ์ ์์ด์ - ์์ก์ด ๋ถ์กฑํด์๋ผ๊ณ ์๋ ค์ค์ผ ํจ.
์์ธ ์์ 2.
- ํ ์ธ์ ์ฑ ์ ์ ํ๋ค๊ณ ํ ๋
- ์ฐ๋ฆฌ๋ ์์ธ๋ก ์ธ์ง๋ฅผ ๋ชปํ๋๋ผ๋ ์์ธ๋ฅผ ๋์ ธํ๋ ์ํฉ์ด ์์ ์ ์์. 0์ผ๋ก ๊ณฑํ๋ค๋ ์์ธ๋ฅผ ์ฒ๋ฆฌํ ๋ price*discount๋ฉด ์ฌ์ฉ์๊ฐ 0์ ์ ๋ ฅํ๋์ง ์ด์ฐํ๋์ง๋ ๋ ์ ์ ์์
- ๊ทธ๋ ์ง๋ง ์์ธ ์ฒ๋ฆฌ๋ฅผ ํด์ผํ๋ฏ๋ก discount๊ฐ 0์ผ๋ก ์ฒ๋ฆฌ๋๋ฉด ์ปค์คํ ์์ธ๋ก ์ฒ๋ฆฌ๋ฅผ ํด์ผ ๋จ.
์๋น์ค ๊ณ์ธต์์ ์์ธ ๋์ง๊ธฐ (throw)
โ๏ธ์๋น์ค๊ณ์ธต์์ ์์ธ๊ฐ ๋ฐ์ํ๋ฉด throw๋ก ๋์ง๊ฒ.
โ๏ธ controller์ ์์ธ๊ฐ ๋ฐ์ํ๋ฉด @controllerAdvice๊ฐ ์๋ ํด๋์ค๊ฐ ๋ฐ์์ ์ฒ๋ฆฌํ ๊ฒ์. (โ ํด๋น ํด๋์ค์์๋ง ์ฒ๋ฆฌํ๋ค.) โ ์์ ํ ๋๋ ํด๋น ํด๋์ค๋ง ์ถ๊ฐํ๊ณ ์ญ์ ํ๋ฉด ๋์ ํธ๋ฆฌํจ.
๊ทธ๋ ๊ฒ ํ๋ ค๋ฉด ์ ์ญ์์ ๋ฐ์ํ๋ ์์ธ๋ฅผ ๋ค ๋ฐ์์ ํ ๊ฒ.
์ฌ์ฉ์ ์์ธ ์ฌ์ฉ
์๋น์ค ๊ณ์ธต์์ ๋์น ์์ธ ์ฒ๋ฆฌํ๊ธฐ
- ์๋ฒ์ชฝ์์ ๋ฐ์ํ ์์ธ๋ฅผ ์กฐ๊ธ ๋ ๊ตฌ์ฒด์ ์ผ๋ก ํํํ ์ ์๋ Custom Exception์ ๋ง๋ค์ด ์์ธ๋ฅผ ๋์ง ์ ์์
- ExceptionCode์ BuisinessLogicException ์์ฑ
-
ExceptionCode
1 2 3 4 5 6 7 8 9 10 11 12 13 14
package com.springboot.exception; import lombok.AllArgsConstructor; import lombok.Getter; @AllArgsConstructor @Getter public enum ExceptionCode { MEMBER_NOT_FOUND(404,"Member Not Found"), MEMBER_EMAIL_NOT_DUPLICATION(404,"์ค๋ณต๋ ์ด๋ฉ์ผ ์ฃผ์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค."); private int status; private String message; }
ExceptionCode๋ฅผ enum์ผ๋ก ์ ์ํ๋ฉด ๋น์ฆ๋์ค ๋ก์ง์์ ๋ฐ์ํ๋ ๋ค์ํ ์ ํ์ ์์ธ๋ฅผ enum์ ์ถ๊ฐํด์ ์ฌ์ฉ ๊ฐ๋ฅ
-
BuisinessLogicException
1 2 3 4 5 6 7 8 9 10 11 12 13 14
package com.springboot.exception; import lombok.Getter; public class BuisinessLogicExceptiton extends RuntimeException { //Runtime์ค์ exception์ด ๋ฐ์ํ๊ธฐ๋๋ฌธ์ Exception์ด ์๋ RuntimeException์ ์์๋ฐ์ @Getter private ExceptionCode exceptionCode; public BuisinessLogicExceptiton(ExceptionCode exceptionCode){ super(exceptionCode.getMessage()); this.exceptionCode=exceptionCode; } }
BusinessLogicException
์RuntimeException
์ ์์ํ๊ณ ์์ExceptionCode
๋ฅผ ๋ฉค๋ฒ ๋ณ์๋ก ์ง์ ํ์ฌ ์์ฑ์๋ฅผ ํตํด์ ์กฐ๊ธ ๋ ๊ตฌ์ฒด์ ์ธ ์์ธ ์ ๋ณด๋ค์ ์ ๊ณตRuntimeException
์ ์์ฑ์(super)๋ก ์์ธ ๋ฉ์์ง๋ฅผ ์ ๋ฌ
-
globalExceptionAdvice
1 2 3 4 5 6 7 8 9 10 11 12 13 14
@RestControllerAdvice public class GlobalExceptionAdvice { ... @ExceptionHandler public ResponseEntity handleBusinessLogicException(BuisinessLogicExceptiton e){ System.out.println("์์ธ์บ์น!"); System.out.println(e.getMessage()); int currentStatus = e.getExceptionCode().getStatus(); return new ResponseEntity(HttpStatus.valueOf(currentStatus)); } }
@RestControllerAdvice
- API๊ณ์ธต์ ์๋, RestController์ ์๋ exception์ ๋ด๊ฐ ๋ค ์ง์ผ๋ณด๊ณ ์๋ค ํ๋ ๊ฒ.
- ์ฆ controller์์ ๋ฐ์ํ๋ ์์ธ๋ฅผ ์ฒ๋ฆฌํ์ง๋ง ์๋น์ค์์ ๊ด๋ฆฌํ๋ error๋ ์ฒ๋ฆฌ.
- ์๋น์ค ๊ณ์ธต์์ ๋ฐ์ํ๋ ์์ธ๋ controller์์ ๋ฐ๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฅํ ์ผ.
@RestControllerAdvice์์ @ResponseStatus๋ฅผ ์ธ๊น? ResponseEntity๋ฅผ ์ธ๊น?
๐ ํ ๊ฐ์ง ์ ํ์ผ๋ก ๊ณ ์ ๋ ์์ธ๋ฅผ ์ฒ๋ฆฌํ ๊ฒฝ์ฐ @ResponseStatus๋ก HttpStatus๋ฅผ ์ง์ ํด์ ์ฌ์ฉ
๐ BusinessLogicException์ฒ๋ผ ๋ค์ํ ์ ํ์ Custom Exception์ ์ฒ๋ฆฌํ๊ณ ์ ํ ๊ฒฝ์ฐ์๋ ResponseEntity๋ฅผ ์ฌ์ฉํ๊ธฐ
-
MemberService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
lic class MemberService { public Member createMember(Member member) { // TODO should business logic // TODO member ๊ฐ์ฒด๋ ๋์ค์ DB์ ์ ์ฅ ํ, ๋๋๋ ค ๋ฐ๋ ๊ฒ์ผ๋ก ๋ณ๊ฒฝ ํ์. // ์ค๋ณต๋ ์ฃผ์์ผ ๊ฒฝ์ฐ ์์ธ ์์ฑ String duplEmail = "jerry@gmail.com"; if(member.getEmail().equals(duplEmail)){ throw new BuisinessLogicExceptiton(ExceptionCode.MEMBER_EMAIL_NOT_DUPLICATION); } Member createdMember = member; return createdMember; } @Service public class MemberService { ... ... public Member findMember(long memberId) { throw new BuisinessLogicExceptiton(ExceptionCode.MEMBER_NOT_FOUND); } }
์ค์ต
- ์ค์ต์ฉ ํ๋ก์ ํธ ํจํค์ง ๊ตฌ์ฑ
- advice
- ์์ธ ๊ณตํต ์ฒ๋ฆฌ๋ฅผ ์ํ GlobalExceptionAdvice
- coffee
- exception
- BusinessLogicException ํด๋์ค
- ExceptionCode ํด๋์ค
- member
- order
- response
- ErrorResponse
- validator
- advice
- ๋๋จธ์ง ํด๋์ค๋ ๊ฑด๋ค์ง ์๊ณ GlobalExceptionAdvice์ ErrorResponse๋ง ์์ ํ๊ธฐ
ํค๋งธ๋ ๋ถ๋ถ
-
ErrorResponseํด๋์ค์์ ์์์๋ ๋ฉ์๋ ๋ง๋๋ ๋ถ๋ถ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
@Getter public class ErrorResponse { Integer status; String message; private List<FieldError> fieldErrors; private List<ConstraintViolationError> violationErrors; private ErrorResponse(Integer status,String message,final List<FieldError>fieldErrors,final List<ConstraintViolationError> violationErrors) { this.status=status; this.message=message; this.fieldErrors = fieldErrors; this.violationErrors = violationErrors; // public static ErrorResponse of(BusinessLogicException businessLogicException) { // return new ErrorResponse(businessLogicException.getExceptionCode().getStatus(), // businessLogicException.getMessage(), // null, // null); // } // public static ErrorResponse of(HttpRequestMethodNotSupportedException httpRequestMethodNotSupportedException) { // return new ErrorResponse(HttpStatus.METHOD_NOT_ALLOWED.value(),HttpStatus.METHOD_NOT_ALLOWED.toString(), // null, // null); // } public static ErrorResponse of(Integer status, String message, Object o, Object object){ return new ErrorResponse(status, message,null,null); }
- 4๊ฐ์ ์ธ์๋ฅผ ๋ค ๋ฐ์์ผ ํด์ Object์ฒ๋ฆฌํ๊ณ null ๋ฃ์ด์คโฆ!
- ๊ทผ๋ฐ ์์ฑ์๋ฅผ ํ๋ ๋ ๋ง๋ค์ด์ status์ message๋ง ๋ฐ์ ์ ์์.
- ๋๋ 4๊ฐ๋ฅผ ๋ค ๋ฐ์์ ํ๋๋ผ ํค๋งธ์โฆ.
-
๊ทผ๋ฐ ์์ฑ์๋ฅผ 2๊ฐ๋ง ๋ฐ์๋ ์๊ด์์
1 2 3 4
public ErrorResponse(Integer status, String message) { this.status = status; this.message = message; }
-
globalException
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
@ExceptionHandler public ResponseEntity handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e){ String message="METHOD_NOT_ALLOWED"; final ErrorResponse response = ErrorResponse.of(HttpStatus.METHOD_NOT_ALLOWED.value(),message,null,null); return new ResponseEntity<>(response,HttpStatus.METHOD_NOT_ALLOWED); } @ExceptionHandler public ResponseEntity handleException(Exception e){ final ErrorResponse response = ErrorResponse.of( ExceptionCode.INTERNAL_SERVER_ERROR.getStatus(), ExceptionCode.INTERNAL_SERVER_ERROR.getMessage(), null, null ); return new ResponseEntity<>(response,HttpStatus.INTERNAL_SERVER_ERROR); }
- status์ message๋ฅผ ์ด๋ป๊ฒ ๊ฐ์ ธ์ฌ๊ฑด์ง
- ๋์ค์ ์ ์ง๋ณด์๊ฐ ํธํ๊ฒ ๋ง๋ค๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผํ๋ ๊ฑด์งโฆ๋ชฐ๋ผ์ ํ์ฐธ ํค๋งธ์
- ๊ทธ๋์ ๊ทธ๋ฅ ๋ชจ๋ฅด๊ฒ ๊ณ ๊ตฌํ์ด ๋จผ์ ๋ค ์ถ์ด์ ์ผ๋จ ์์ฑํ์
ํด๊ฒฐ๋ฐฉ๋ฒ v1
-
HttpsStats๊ฐ ๊ตฌํ๋ ํด๋์ค๋ก ์ด๋ํด๋ณด๋ฉด .value() ๋ก ์ํ์ฝ๋ ๋ฐ์์ฌ ์ ์๊ณ .getReasonPhrase()๋ก ์ํ๋ฉ์ธ์ง ๊ฐ์ ธ์ฌ ์ ์์.
GlobalExceptionAdvice
1 2 3 4 5 6 7 8 9
public static ErrorResponse of (HttpRequestMethodNotSupportedException e){ HttpStatus currentStatus = HttpStatus.METHOD_NOT_ALLOWED; return new ErrorResponse(currentStatus.value(), currentStatus.getReasonPhrase()); } public satic ErrorResponse of(NullPointerException e){ HttpStatus currentStatus = HttpStatus.INTERNAL_SERVER_ERROR; return new ErrorResponse(currengtStatus.value(), currentStatus.getReasonPhrase()); }
ErrorResponse
1 2 3 4
@ExceptionHandler public ErrorResponse handleException(NullPointerException e){ return ErropResponse.of(e); }
Refactoring
GlobalExceptionAdvice
1
2
3
4
5
6
7
8
9
10
11
@ExceptionHandler
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
public ErrorResponse handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e){
return ErrorResponse.of(HttpStatus.Method_NOT_ALLOWED);
}
@ExceptionHandler
@ResponseStatus(HttpStatus.INTERNATIONAL_SERVER_ERROR)
public ErrorResponse handleException(NullpointerException e){
return ErrorResponse.of(HttpStatus.INTERNAL_SERVER_ERROR);
}
๊ด๋ จ ์์ธ๋ค์ ๋ณ์ ์ฌ์ฉ ์์ด ๋ฐ๋ก ErrorResponse๋ก ๋ฐํํ์ฌ ๋ฆฌํฉํ ๋ง ๊ฐ๋ฅ.
๐ ์ฐธ๊ณ ํ๊ธฐ
@Deprecated ์์ผ๋ก ์์ธ๊ฑฐ๋๊น ์ฌ์ฉ์ ์์ ํด๋ฌ๋ผ - ์ง์ํ์ง ์์ ์์ .
Comment
์์ธ์ฒ๋ฆฌ ์ด์ ๊ฒ๋ ์ดํด๋ชปํ๋๋ฐ ์ค์ตํ๋๊น ๋ ์ดํด์๊ฐ์ ๋ ํค๋งธ์
๋์ด์ผ๋ณด๋ฉด ํ์คํ ์ฝ๋๋ฅผ ๋ณด๊ณ ์ดํดํ๋ ๊ฒ๋ ์ค์ํ๋ฐ
๋ฐฑ์ง์์ ์ฝ๋๋ฅผ ์ณ๋ณด๊ณ ํค๋งค๋ ๊ฒฝํ๋
์ค์ํ ๊ฒ ๊ฐ์โฆ!
๊ทธ๋ฌ๊ณ ๋ซ์ ๋ ๋ ์ดํด๊ฐ ๋๋ ๊ฒ ๊ฐ์๋ฐ
๊ทธ ๊ณผ์ ์ด ๊ณ ํต์ค๋ฝ๋ค
๊ฐ์ฌ๋์ด ํ์ดํด์ฃผ์๋ ๊ฒ๋ ๋๋ฌด ์ฝ๊ฒ ํ์ด์ ํํ์ดโฆ
๋ ๋๋์ฒด ๋ญํ๊ฑฐ์ง..?ใ
๊ณต์๋ฌธ์๋ ๊ตฌํ์ฒด๋ฅผ ๋ณด๋๊ฒ ์ค์ํ ๊ฒ ๊ฐ์์
์์ผ๋ก๋ ๊ฒ์ํด์ ๋ธ๋ก๊ทธ๋ณด๋ ๊ฒ ๋ณด๋จ ๊ณต์๋ฌธ์๋ฅผ ์ฐพ์๋ณด๋ ๊ฒ์ดโฆ
์ข์๊ฒ ๊ฐ๋ค!
๐ ๊ณต์ง
Leave a comment