[#20] 도메인별 예외 분리 #21

Merged
pricelees merged 37 commits from refactor/#20 into main 2025-07-24 02:48:53 +00:00
10 changed files with 22 additions and 101 deletions
Showing only changes of commit 74f87e4a2a - Show all commits

View File

@ -1,8 +1,8 @@
package roomescape.auth.exception package roomescape.auth.exception
import roomescape.common.exception.RoomescapeExceptionV2 import roomescape.common.exception.RoomescapeException
class AuthException( class AuthException(
override val errorCode: AuthErrorCode, override val errorCode: AuthErrorCode,
override val message: String = errorCode.message override val message: String = errorCode.message
) : RoomescapeExceptionV2(errorCode, message) ) : RoomescapeException(errorCode, message)

View File

@ -2,7 +2,6 @@ package roomescape.common.dto.response
import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.annotation.JsonInclude
import roomescape.common.exception.ErrorCode import roomescape.common.exception.ErrorCode
import roomescape.common.exception.ErrorType
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
data class CommonApiResponse<T>( data class CommonApiResponse<T>(
@ -10,11 +9,6 @@ data class CommonApiResponse<T>(
) )
data class CommonErrorResponse( data class CommonErrorResponse(
val errorType: ErrorType,
val message: String? = errorType.description
)
data class CommonErrorResponseV2(
val code: String, val code: String,
val message: String val message: String
) { ) {

View File

@ -1,53 +0,0 @@
package roomescape.common.exception
enum class ErrorType(
val description: String
) {
// 400 Bad Request
REQUEST_DATA_BLANK("요청 데이터에 유효하지 않은 값(null OR 공백)이 포함되어있습니다."),
INVALID_REQUEST_DATA_TYPE("요청 데이터 형식이 올바르지 않습니다."),
INVALID_REQUEST_DATA("요청 데이터 값이 올바르지 않습니다."),
INVALID_DATE_RANGE("종료 날짜는 시작 날짜 이전일 수 없습니다."),
HAS_RESERVATION_OR_WAITING("같은 테마에 대한 예약(대기)는 한 번만 가능합니다."),
// 401 Unauthorized
EXPIRED_TOKEN("토큰이 만료되었습니다. 다시 로그인 해주세요."),
UNSUPPORTED_TOKEN("지원하지 않는 JWT 토큰입니다."),
MALFORMED_TOKEN("형식이 맞지 않는 JWT 토큰입니다."),
INVALID_SIGNATURE_TOKEN("잘못된 JWT 토큰 Signature 입니다."),
ILLEGAL_TOKEN("JWT 토큰의 Claim 이 비어있습니다."),
INVALID_TOKEN("JWT 토큰이 존재하지 않거나 유효하지 않습니다."),
NOT_EXIST_COOKIE("쿠키가 존재하지 않습니다. 로그인이 필요한 서비스입니다."),
// 403 Forbidden
LOGIN_REQUIRED("로그인이 필요한 서비스입니다."),
PERMISSION_DOES_NOT_EXIST("접근 권한이 존재하지 않습니다."),
// 404 Not Found
MEMBER_NOT_FOUND("회원(Member) 정보가 존재하지 않습니다."),
RESERVATION_NOT_FOUND("예약(Reservation) 정보가 존재하지 않습니다."),
TIME_NOT_FOUND("예약 시간(Time) 정보가 존재하지 않습니다."),
THEME_NOT_FOUND("테마(Theme) 정보가 존재하지 않습니다."),
PAYMENT_NOT_FOUND("결제(Payment) 정보가 존재하지 않습니다."),
// 405 Method Not Allowed
METHOD_NOT_ALLOWED("지원하지 않는 HTTP Method 입니다."),
// 409 Conflict
TIME_IS_USED_CONFLICT("삭제할 수 없는 시간대입니다. 예약이 존재하는지 확인해주세요."),
THEME_IS_USED_CONFLICT("삭제할 수 없는 테마입니다. 예약이 존재하는지 확인해주세요."),
TIME_DUPLICATED("이미 해당 시간이 존재합니다."),
THEME_DUPLICATED("같은 이름의 테마가 존재합니다."),
RESERVATION_DUPLICATED("해당 시간에 이미 예약이 존재합니다."),
RESERVATION_PERIOD_IN_PAST("이미 지난 시간대는 예약할 수 없습니다."),
CANCELED_BEFORE_PAYMENT("취소 시간이 결제 시간 이전일 수 없습니다."),
// 500 Internal Server Error,
INTERNAL_SERVER_ERROR("서버 내부에서 에러가 발생하였습니다."),
UNEXPECTED_ERROR("예상치 못한 에러가 발생하였습니다. 잠시 후 다시 시도해주세요."),
// Payment Error
PAYMENT_ERROR("결제(취소)에 실패했습니다. 결제(취소) 정보를 확인해주세요."),
PAYMENT_SERVER_ERROR("결제 서버에서 에러가 발생하였습니다. 잠시 후 다시 시도해주세요.")
;
}

View File

@ -8,43 +8,33 @@ import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.RestControllerAdvice import org.springframework.web.bind.annotation.RestControllerAdvice
import roomescape.common.dto.response.CommonErrorResponse import roomescape.common.dto.response.CommonErrorResponse
import roomescape.common.dto.response.CommonErrorResponseV2
@RestControllerAdvice @RestControllerAdvice
class ExceptionControllerAdvice( class ExceptionControllerAdvice(
private val logger: KLogger = KotlinLogging.logger {} private val logger: KLogger = KotlinLogging.logger {}
) { ) {
@ExceptionHandler(value = [RoomescapeExceptionV2::class]) @ExceptionHandler(value = [RoomescapeException::class])
fun handleRoomException(e: RoomescapeExceptionV2): ResponseEntity<CommonErrorResponseV2> { fun handleRoomException(e: RoomescapeException): ResponseEntity<CommonErrorResponse> {
logger.error(e) { "message: ${e.message}" } logger.error(e) { "message: ${e.message}" }
val errorCode: ErrorCode = e.errorCode val errorCode: ErrorCode = e.errorCode
return ResponseEntity return ResponseEntity
.status(errorCode.httpStatus) .status(errorCode.httpStatus)
.body(CommonErrorResponseV2(errorCode, e.message)) .body(CommonErrorResponse(errorCode, e.message))
}
@ExceptionHandler(value = [RoomescapeException::class])
fun handleRoomEscapeException(e: RoomescapeException): ResponseEntity<CommonErrorResponse> {
logger.error(e) { "message: ${e.message}, invalidValue: ${e.invalidValue}" }
return ResponseEntity
.status(e.httpStatus)
.body(CommonErrorResponse(e.errorType))
} }
@ExceptionHandler(value = [HttpMessageNotReadableException::class]) @ExceptionHandler(value = [HttpMessageNotReadableException::class])
fun handleHttpMessageNotReadableException(e: HttpMessageNotReadableException): ResponseEntity<CommonErrorResponseV2> { fun handleHttpMessageNotReadableException(e: HttpMessageNotReadableException): ResponseEntity<CommonErrorResponse> {
logger.error(e) { "message: ${e.message}" } logger.error(e) { "message: ${e.message}" }
val errorCode: ErrorCode = CommonErrorCode.INVALID_INPUT_VALUE val errorCode: ErrorCode = CommonErrorCode.INVALID_INPUT_VALUE
return ResponseEntity return ResponseEntity
.status(errorCode.httpStatus) .status(errorCode.httpStatus)
.body(CommonErrorResponseV2(errorCode, e.message ?: errorCode.message)) .body(CommonErrorResponse(errorCode))
} }
@ExceptionHandler(value = [MethodArgumentNotValidException::class]) @ExceptionHandler(value = [MethodArgumentNotValidException::class])
fun handleMethodArgumentNotValidException(e: MethodArgumentNotValidException): ResponseEntity<CommonErrorResponseV2> { fun handleMethodArgumentNotValidException(e: MethodArgumentNotValidException): ResponseEntity<CommonErrorResponse> {
val message: String = e.bindingResult.allErrors val message: String = e.bindingResult.allErrors
.mapNotNull { it.defaultMessage } .mapNotNull { it.defaultMessage }
.joinToString(", ") .joinToString(", ")
@ -53,16 +43,16 @@ class ExceptionControllerAdvice(
val errorCode: ErrorCode = CommonErrorCode.INVALID_INPUT_VALUE val errorCode: ErrorCode = CommonErrorCode.INVALID_INPUT_VALUE
return ResponseEntity return ResponseEntity
.status(errorCode.httpStatus) .status(errorCode.httpStatus)
.body(CommonErrorResponseV2(errorCode, message)) .body(CommonErrorResponse(errorCode))
} }
@ExceptionHandler(value = [Exception::class]) @ExceptionHandler(value = [Exception::class])
fun handleException(e: Exception): ResponseEntity<CommonErrorResponseV2> { fun handleException(e: Exception): ResponseEntity<CommonErrorResponse> {
logger.error(e) { "message: ${e.message}" } logger.error(e) { "message: ${e.message}" }
val errorCode: ErrorCode = CommonErrorCode.UNEXPECTED_SERVER_ERROR val errorCode: ErrorCode = CommonErrorCode.UNEXPECTED_SERVER_ERROR
return ResponseEntity return ResponseEntity
.status(errorCode.httpStatus) .status(errorCode.httpStatus)
.body(CommonErrorResponseV2(errorCode)) .body(CommonErrorResponse(errorCode))
} }
} }

View File

@ -1,16 +1,6 @@
package roomescape.common.exception package roomescape.common.exception
import org.springframework.http.HttpStatusCode open class RoomescapeException(
class RoomescapeException(
val errorType: ErrorType,
val invalidValue: String? = "",
val httpStatus: HttpStatusCode,
) : RuntimeException(errorType.description) {
constructor(errorType: ErrorType, httpStatus: HttpStatusCode) : this(errorType, null, httpStatus)
}
open class RoomescapeExceptionV2(
open val errorCode: ErrorCode, open val errorCode: ErrorCode,
override val message: String = errorCode.message override val message: String = errorCode.message
) : RuntimeException(message) ) : RuntimeException(message)

View File

@ -1,8 +1,8 @@
package roomescape.member.exception package roomescape.member.exception
import roomescape.common.exception.RoomescapeExceptionV2 import roomescape.common.exception.RoomescapeException
class MemberException( class MemberException(
override val errorCode: MemberErrorCode, override val errorCode: MemberErrorCode,
override val message: String = errorCode.message override val message: String = errorCode.message
) : RoomescapeExceptionV2(errorCode, message) ) : RoomescapeException(errorCode, message)

View File

@ -1,8 +1,8 @@
package roomescape.payment.exception package roomescape.payment.exception
import roomescape.common.exception.RoomescapeExceptionV2 import roomescape.common.exception.RoomescapeException
class PaymentException( class PaymentException(
override val errorCode: PaymentErrorCode, override val errorCode: PaymentErrorCode,
override val message: String = errorCode.message override val message: String = errorCode.message
) : RoomescapeExceptionV2(errorCode, message) ) : RoomescapeException(errorCode, message)

View File

@ -1,9 +1,9 @@
package roomescape.reservation.exception package roomescape.reservation.exception
import roomescape.common.exception.ErrorCode import roomescape.common.exception.ErrorCode
import roomescape.common.exception.RoomescapeExceptionV2 import roomescape.common.exception.RoomescapeException
class ReservationException( class ReservationException(
override val errorCode: ErrorCode, override val errorCode: ErrorCode,
override val message: String = errorCode.message override val message: String = errorCode.message
) : RoomescapeExceptionV2(errorCode, message) ) : RoomescapeException(errorCode, message)

View File

@ -1,8 +1,8 @@
package roomescape.theme.exception package roomescape.theme.exception
import roomescape.common.exception.RoomescapeExceptionV2 import roomescape.common.exception.RoomescapeException
class ThemeException( class ThemeException(
override val errorCode: ThemeErrorCode, override val errorCode: ThemeErrorCode,
override val message: String = errorCode.message override val message: String = errorCode.message
) : RoomescapeExceptionV2(errorCode, message) ) : RoomescapeException(errorCode, message)

View File

@ -1,9 +1,9 @@
package roomescape.time.exception package roomescape.time.exception
import roomescape.common.exception.ErrorCode import roomescape.common.exception.ErrorCode
import roomescape.common.exception.RoomescapeExceptionV2 import roomescape.common.exception.RoomescapeException
class TimeException( class TimeException(
override val errorCode: ErrorCode, override val errorCode: ErrorCode,
override val message: String = errorCode.message override val message: String = errorCode.message
) : RoomescapeExceptionV2(errorCode, message) ) : RoomescapeException(errorCode, message)