๐ ๊ฐ์
์ด์ ํ๋ก์ ํธ์์ ๋ฐฑ์๋ ๋๋ฉ์ธ ๋ณ๋ก ๊ฐ๋ฐ ํํธ๋ฅผ ๋๋๊ณ ์์ธ์ฒ๋ฆฌ๋ฅผ ๊ฐ์ ์์์ ํ๋ค.
์ฌ์ง์ด ๋ฌธ์ํ๋ ์ ๋๋ก ํด๋์ง ์์ ํด๋น ์์ธ๊ฐ ์ ๋ฐ์ํ๋์ง ์ ์ ๋ฌ์ด ๋์ง ์์๊ณ
์, ์ด๋์ ๋ฐ์ํ ์์ธ์ธ์ง ์ฐพ๋ ๊ฒ์ด ๊ต์ฅํ ํ๋ค์๋ค.
๊ทธ๋์ ์์ธ ์ฒ๋ฆฌ์์ ๋ฌธ์ ๊ฐ ์๊ธฐ๋ฉด ๋ด๊ฐ ๊ฐ๋ฐํ ํํธ์์ ๋ฐ์ํ ์์ธ๊ฐ ์๋์๋
์๋ฑํ ๊ณณ์์ ๋ฌธ์ ๋ฅผ ์ฐพ๊ธฐ ์ํด ์๊ฐ์ ํ๋นํ ๊ฒฝํ์ด ์์๋ค.
์ด๋ฐ ๊ฒฝํ์ ํตํด, ๋ค์ ํ๋ก์ ํธ์์๋ ๊ธฐํ์ฝ ์์ธ ์ฒ๋ฆฌ๋ฅผ ์ ์ญ์์ ๊ด๋ฆฌํ๊ณ ๋ฌธ์ํ๋ ์ ๋๋ก ํด๋๊ธฐ๋ก ๋ค์งํ๋ค.
๊ทธ๋์ ์ด๋ฒ ํ๋ก์ ํธ์์๋ Custom Exception์ ํตํด ์์ธ ์ฒ๋ฆฌ๋ฅผ ํด๋ณด๋ ค ํ๋ค.
๐ ์ฐ๋ฆฌ์ ํ๋ก์ ํธ ์ํฉ
API ๋ช ์ธ๋ฅผ ํ๋ฉฐ ๋ฐ์ํ ์ ์๋ ์์ธ ์ํฉ๋ค์ ์ ๋ฆฌํ์๊ณ ,
์์ธ๋ค์ ๋ช ๊ฐ์ง ์นดํ ๊ณ ๋ฆฌ๋ก ๋๋ด๋ค.
AUTH
, PAYMENT
, SETTLEMENT
, TRAVEL
, VALIDATION
์ด๋ผ๋ ์นดํ
๊ณ ๋ฆฌ๋ก ๋๋ด๊ณ
PAYMENT
, SETTLEMENT
, TRAVEL
๊ด๋ จ ์์ธ๋ ์๋น์ค ์ ์ฑ
์ ๋ฐ์ํ ์ ์๋ ์์ธ์ด๋ค.
๐ Custom Exception
Custom Exception ๊ตฌํ ๋ฐฉ๋ฒ์ ๋ํด ์ฐพ์๋ณด๋
๋์ฒด๋ก CutomErrorCode
, CustomException
, CustomExceptionHandler
, CustomExceptionResponse
์ด ๋ค ๊ฐ์ง๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌํํ๋ค.
์๋์ ๋ธ๋ก๊ทธ์ ์ด์ ๋ํ ๊ฐ๋ ์ด ์์ธํ ๋์์๊ณ , ํด๋น ์ฝ๋๋ฅผ ์ฐธ๊ณ ํ๋ค.
https://velog.io/@rungoat/SpringBoot-Custom-Exception-%EC%B2%98%EB%A6%AC
๐ก CustomErrorCode
Errorcode ์ ๋ณด๋ฅผ ๋ด์ ๊ด๋ฆฌํ๋ enum
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;
@Getter
@AllArgsConstructor
public enum ErrorCode {
USER_NOT_FOUND(HttpStatus.NOT_FOUND, "ACCOUNT-001", "์ฌ์ฉ์๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค."),
HAS_EMAIL(HttpStatus.BAD_REQUEST, "ACCOUNT-002", "์กด์ฌํ๋ ์ด๋ฉ์ผ์
๋๋ค."),
INVALID_PASSWORD(HttpStatus.BAD_REQUEST, "ACCOUNT-003", "๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค."),
// ...
private final HttpStatus httpStatus; // HttpStatus
private final String code; // ACCOUNT-001
private final String message; // ์ค๋ช
}
๐ก CustomException
Exception์ด๋ RuntimeException์ ์์๋ฐ๊ณ CustomErrorCode๋ฅผ ํ๋๋ก ๊ฐ์ง๊ณ ์๋ class
@Getter
@AllArgsConstructor
public class CustomException extends RuntimeException {
ErrorCode errorCode;
}
๐ก CustomExceptionHandler
CustomException์ด ๋ฐ์ํ์ ๋ ์ ์ญ์์ ์ด ์์ธ๋ฅผ ์ก์ ํธ๋ค๋งํด ์ฃผ๋ class
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class CustomExceptionHandler {
@ExceptionHandler(CustomException.class)
protected ResponseEntity<ErrorResponseEntity> handleCustomException(CustomException e){
return ErrorResponseEntity.toResponseEntity(e.getErrorCode());
}
}
๐ก CustomExceptionResponse
CustomException์ด ๋ฐ์ํด์ CustomExceptionHandler๊ฐ ์ด๋ฅผ ๊ฐ์งํ์ ๋,
์๋ต์ผ๋ก ๋ด๋ ค์ค Response Dto
@Data
@Builder
public class ErrorResponseEntity {
private int status;
private String name;
private String code;
private String message;
public static ResponseEntity<ErrorResponseEntity> toResponseEntity(ErrorCode e){
return ResponseEntity
.status(e.getHttpStatus())
.body(ErrorResponseEntity.builder()
.status(e.getHttpStatus().value())
.name(e.name())
.code(e.getCode())
.message(e.getMessage())
.build());
}
}
๐ ์นดํ ๊ณ ๋ฆฌ๋ณ๋ก ErrorCode ๊ด๋ฆฌํ๊ธฐ
๋ณดํต ErrorCode๋ค์ CustomErrorCode
๋ผ๋ ํ๋์ enum ์์์ ๋ชจ๋ ๊ด๋ฆฌํ๋ ๊ฒ ๊ฐ์๋ค.
ํ์ง๋ง ์ฐ๋ฆฌ ํ๋ก์ ํธ์์๋ ์นดํ ๊ณ ๋ฆฌ ๋ณ๋ก ErrorCode๋ฅผ ๋ถ๋ฅํ์ฌ ๊ด๋ฆฌํ๊ณ ์ถ์๋ค.
์ฐ์ ErrorCode๋ฅผ ์นดํ ๊ณ ๋ฆฌ ๋ณ๋ก ๋ถ๋ฅํด์ ๊ด๋ฆฌํ๊ธฐ ์ํด์ ํ ๊ฐ์ง ์กฐ๊ฑด์ด ํ์ํ๋ค.
ErrorCode๋ ๋ชจ๋ ํ ๊ฐ์ง ํ์ ์ด์ด์ผ ํ๋ค.
๊ทธ ์ด์ ๋ CustomExceptionResponse์์ ErrorResponseEntity
class์ toResponseEntity
๋ฉ์๋๋ฅผ ํ์ธํด ๋ณด๋ฉด
ErrorCode๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ๊ณ ์๋ค.
๋ง์ฝ ErrorCode์ ํ์
์ด ๋ชจ๋ ์ ๊ฐ๊ฐ์ด๋ฉด, ErrorCode ๋ณ๋ก toResponseEntity
๋ฉ์๋๋ฅผ ์ค๋ฒ๋ก๋ฉํด์ ๋ง๋ค์ด์ค์ผ ํ๋ค.
์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ErrorCode
๋ฅผ ์์ํ๋ AuthErrorCode
, PaymentErrorCode
... ๋ฅผ ๋ง๋ค์ด ํ๋์ toResponseEntity
๋ฉ์๋๋ก๋ ํด๊ฒฐ ๊ฐ๋ฅํ๋๋ก ํ ๊ฒ์ด๋ค.
๊ทธ๋ผ ์ฐ์ ErrorCode๋ฅผ ๋ง๋ค์ด ๋ณด์.
์์ CustomErrorCode๋ enum์ผ๋ก ๋ง๋ค์ด์ ธ ์๋๋ฐ
enum์ ์ด๋ฏธ java.lang.Enum
ํด๋์ค๋ฅผ ์๋ฌต์ ์ผ๋ก ์์ํ๊ณ ์๊ธฐ ๋๋ฌธ์,
์นดํ ๊ณ ๋ฆฌ๋ณ ErrorCode๋ค๋ enum์ผ๋ก ๋ง๋ค๋ฉด, ErrorCode๋ฅผ ์์ํ๊ฒ ํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํ๋ค.
๋ฐ๋ผ์ ErrorCode๋ฅผ ์ถ์ ํด๋์ค๋ก ์ ์ธํ๊ณ ,
์นดํ ๊ณ ๋ฆฌ๋ณ ErrorCode๋ฅผ enum์ด ์๋ ํด๋์ค๋ก ๋ง๋ค์ด ErrorCode๋ฅผ ์์๋ฐ๊ฒ ํ๋ค.
๊ทธ๋ฆฌ๊ณ ์นดํ ๊ณ ๋ฆฌ๋ณ ErrorCode๋ค์์ ์ ์ ์์ ๊ฐ์ฒด ์ ์๋ฅผ ํตํด enum์ ์๋์ง๋ง enum ์์์ฒ๋ผ ์ฌ์ฉํ ๊ฒ์ด๋ค.
๐ก ErrorCode
package withbeetravel.exception.error;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;
@Getter
@AllArgsConstructor
public abstract class ErrorCode {
private final HttpStatus status;
private final String name;
private final String code;
private final String message;
}
๐ก AuthErrorCode
package withbeetravel.exception.error;
import lombok.Getter;
import org.springframework.http.HttpStatus;
@Getter
public class AuthErrorCode extends ErrorCode{
// ์ ์ ์์ ๊ฐ์ฒด ์ ์
public static final AuthErrorCode AUTHENTICATION_FAILED = new AuthErrorCode(HttpStatus.UNAUTHORIZED, "AUTHENTICATION_FAILED", "AUTH-001", "์ฌ์ฉ์ ์ธ์ฆ ์คํจ");
public static final AuthErrorCode ADMIN_PRIVILEGES_REQUIRED = new AuthErrorCode(HttpStatus.FORBIDDEN, "ADMIN_PRIVILEGES_REQUIRED", "AUTH-002", "๊ด๋ฆฌ์ ๊ถํ ์์");
public static final AuthErrorCode INVALID_CREDENTIALS = new AuthErrorCode(HttpStatus.UNAUTHORIZED, "INVALID_CREDENTIALS", "AUTH-003", "์๋ชป๋ ์ด๋ฉ์ผ ๋๋ ๋น๋ฐ๋ฒํธ");
public static final AuthErrorCode EMAIL_NOT_FOUND = new AuthErrorCode(HttpStatus.NOT_FOUND, "EMAIL_NOT_FOUND", "AUTH-004", "์กด์ฌํ์ง ์๋ ์ด๋ฉ์ผ");
public static final AuthErrorCode TERMS_NOT_ACCEPTED = new AuthErrorCode(HttpStatus.FORBIDDEN, "TERMS_NOT_ACCEPTED", "AUTH-005", "์๋น์ค ์ด์ฉ ์ฝ๊ด์ ๋์ํ์ง ์์");
public static final AuthErrorCode EMAIL_ALREADY_EXISTS = new AuthErrorCode(HttpStatus.CONFLICT, "EMAIL_ALREADY_EXISTS", "AUTH-006", "์ด๋ฏธ ์กด์ฌํ๋ ์ด๋ฉ์ผ");
public static final AuthErrorCode PASSWORD_POLICY_VIOLATION = new AuthErrorCode(HttpStatus.BAD_REQUEST, "AUTH-007", "PASSWORD_POLICY_VIOLATION", "๋น๋ฐ๋ฒํธ ์ ์ฑ
๋ถ์ถฉ์กฑ");
public static final AuthErrorCode INVALID_EMAIL_FORMAT = new AuthErrorCode(HttpStatus.BAD_REQUEST, "AUTH-008", "INVALID_EMAIL_FORMAT", "์๋ชป๋ ์ด๋ฉ์ผ ํ์");
public static final AuthErrorCode PIN_POLICY_VIOLATION = new AuthErrorCode(HttpStatus.BAD_REQUEST, "PIN_POLICY_VIOLATION", "AUTH-009", "ํ๋ฒํธ ์ ์ฑ
๋ถ์ถฉ์กฑ");
private AuthErrorCode(HttpStatus status, String name, String code, String message) {
super(status, name, code, message);
}
}
๐ก PaymentErrorCode
package withbeetravel.exception.error;
import lombok.Getter;
import org.springframework.http.HttpStatus;
@Getter
public class PaymentErrorCode extends ErrorCode{
// ์ ์ ์์ ๊ฐ์ฒด ์ ์
public static final PaymentErrorCode SHARED_PAYMENT_NOT_FOUND = new PaymentErrorCode(HttpStatus.NOT_FOUND, "SHARED_PAYMENT_NOT_FOUND", "PAYMENT-001", "SHARED PAYMENT ID์ ํด๋นํ๋ ๊ณต๋ ๊ฒฐ์ ๋ด์ญ์ด ์์");
public static final PaymentErrorCode NO_PERMISSION_TO_MODIFY_SHARED_PAYMENT = new PaymentErrorCode(HttpStatus.FORBIDDEN, "NO_PERMISSION_TO_MODIFY_SHARED_PAYMENT", "PAYMENT-002", "ํด๋น ๊ณต๋ ๊ฒฐ์ ๋ด์ญ ์์ ๊ถํ ์์");
private PaymentErrorCode(HttpStatus status, String name, String code, String message) {
super(status, name, code, message);
}
}
์ด๋ ๊ฒ ๊ตฌํํจ์ผ๋ก์จ ErrorCode๋ฅผ ์นดํ ๊ณ ๋ฆฌ๋ณ๋ก ๊ตฌ๋ถํ๋,
ํ ๊ฐ์ง ํ์ ์ผ๋ก ๋ง๋ค์๋ค.
๐ ์นดํ ๊ณ ๋ฆฌ๋ณ๋ก Exception ๊ด๋ฆฌํ๊ธฐ → CustomException์ผ๋ก ๋ชจ๋ ๊ด๋ฆฌ
์๋๋ CustomException๋ ํ๋๋ก ๋ญ๋ฑ๊ทธ๋ฆฌ์ง ์๊ณ ,
์นดํ ๊ณ ๋ฆฌ๋ณ๋ก ๊ด๋ฆฌํ์ฌ ์ด๋ ์์ธ๊ฐ ๋ฐ์ํ ๊ฒ์ธ์ง ์ง๊ด์ ์ผ๋ก ํ์ธ์ด ๊ฐ๋ฅํ๊ฒ ํ๊ณ ์ถ์๋ค.
์ด๋ฌํ ์๊ฐ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ด ์นดํ ๊ณ ๋ฆฌ๋ณ๋ก ๋ชจ๋ Exception์ ๋ง๋ค์๋ค.
๋ํ, ์ด๋ ๊ฒ ์๊ฒจ๋ Exception๋ค์ ํธ๋ค๋งํ handler ๋ฉ์๋๋ ์ถ๊ฐํด ์ฃผ์๋ค.
๐ก AuthException
package withbeetravel.exception;
import lombok.AllArgsConstructor;
import lombok.Getter;
import withbeetravel.exception.error.AuthErrorCode;
@Getter
@AllArgsConstructor
public class AuthException extends RuntimeException {
AuthErrorCode errorCode;
}
๐ก PaymentException
package withbeetravel.exception;
import lombok.AllArgsConstructor;
import lombok.Getter;
import withbeetravel.exception.error.PaymentErrorCode;
@Getter
@AllArgsConstructor
public class PaymentException extends RuntimeException {
PaymentErrorCode errorCode;
}
๐ก CustomExceptionHandler
package withbeetravel.exception.handler;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import withbeetravel.exception.*;
import withbeetravel.exception.dto.ErrorResponseDto;
@ControllerAdvice
public class CustomExceptionHandler {
@ExceptionHandler(AuthException.class)
protected ResponseEntity<ErrorResponseDto> handleAuthException(AuthException e) {
return ErrorResponseDto.toResponseEntity(e.getErrorCode());
}
@ExceptionHandler(PaymentException.class)
protected ResponseEntity<ErrorResponseDto> handlePaymentException(PaymentException e) {
return ErrorResponseDto.toResponseEntity(e.getErrorCode());
}
@ExceptionHandler(SettlementException.class)
protected ResponseEntity<ErrorResponseDto> handleSettlementException(SettlementException e) {
return ErrorResponseDto.toResponseEntity(e.getErrorCode());
}
@ExceptionHandler(TravelException.class)
protected ResponseEntity<ErrorResponseDto> handleTravelException(TravelException e) {
return ErrorResponseDto.toResponseEntity(e.getErrorCode());
}
@ExceptionHandler(ValidationException.class)
protected ResponseEntity<ErrorResponseDto> handleValidationException(ValidationException e) {
return ErrorResponseDto.toResponseEntity(e.getErrorCode());
}
}
ํ์ง๋ง ์ด๋ ๊ฒ ๊ตฌํํ์ ๋,
์ฝ๋ ์ค๋ณต๋ง ์ฌํด์ง๊ณ
ํ๋ก์ ํธ๋ฅผ ๋๋ฒจ๋กญ์ํค๊ฑฐ๋ ์ ์ง๋ณด์ ๊ณผ์ ์์ ์๋ก์ด ์นดํ ๊ณ ๋ฆฌ์ ์์ธ๊ฐ ์๊ฒผ์ ๋
๋งค๋ฒ ์๋ก์ด Exception๊ณผ handler ๋ฉ์๋๋ฅผ ์ถ๊ฐํด์ฃผ์ด์ผ ํ๋ค.
์ด๋ฅผ ๊ฐ์ํ ๋งํผ์ ์ฅ์ ์ด ์๋ค๊ณ ๋๊ผ๋ค.
๋ํ ์ด๋ฏธ ์นดํ ๊ณ ๋ฆฌ ๋ณ๋ก ErrorCode๋ฅผ ๋๋ ๋์๊ธฐ ๋๋ฌธ์,
์ด๋ฏธ ์ด๋ ๋ถ๋ถ์์ ๋ฐ์ํ ์์ธ์ธ์ง ํ์ธ์ด ๊ฐ๋ฅํ๋ค.
๊ทธ๋์ ๊ทธ๋ฅ ํ๋์ CustomException์ผ๋ก ์์ธ๋ฅผ ๊ด๋ฆฌํ๊ธฐ๋ก ํ๋ค.
๐ก CustomException
package withbeetravel.exception;
import lombok.AllArgsConstructor;
import lombok.Getter;
import withbeetravel.exception.error.ErrorCode;
@Getter
@AllArgsConstructor
public class CustomException extends RuntimeException{
ErrorCode errorCode;
}
๐ก CustomExceptionHandler
package withbeetravel.exception.handler;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import withbeetravel.exception.CustomException;
import withbeetravel.exception.dto.ErrorResponseDto;
@ControllerAdvice
public class CustomExceptionHandler {
@ExceptionHandler(CustomException.class)
protected ResponseEntity<ErrorResponseDto> handleAuthException(CustomException e) {
return ErrorResponseDto.toResponseEntity(e.getErrorCode());
}
}
์ด๋ ๊ฒ ํจ์ผ๋ก์จ ๋์ค์ ์๋ก์ด ์นดํ ๊ณ ๋ฆฌ์ Error๊ฐ ์๊ฒจ๋
ErrorCode๋ฅผ ์์๋ฐ์ error code ๊ด๋ฆฌ ํด๋์ค๋ง ์์ฑํด ์ฃผ๋ฉด ๋๋ค.
๐ CustomeException ์ฌ์ฉํ๊ธฐ
CustomException์ ์ฌ์ฉํ ๋๋ ๋ค์๊ณผ ๊ฐ์ด ์ด๋ค Error์ธ์ง๋ง CustomException์ ์์ฑ์์ ๋ฃ์ด์ฃผ๋ฉด ๋๋ค.
new CustomException(AuthErrorCode.AUTHENTICATION_FAILED);
'Back-end > Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring] AOP๋ก ๊ถํ ์ฒ๋ฆฌํ๊ธฐ (0) | 2024.11.14 |
---|---|
[Spring] Swagger ์ค์ ๋ฐ ์ฌ์ฉ ๋ฐฉ๋ฒ (4) | 2024.11.11 |