[#26] feat: 불필요한 Exception 제거 및 통합

- CafeMenu, MenuOption, OptionDetail 관련 Exception 통합(BusinessException)
- 시스템 관련 에러 핸들러 추가(BasicControllerAdvice)
- 불필요한 클래스 제거
- 패키지 이동(account-api security package)
This commit is contained in:
beaniejoy
2022-12-04 03:04:29 +09:00
parent 8463fcf932
commit b6acd3578a
14 changed files with 56 additions and 36 deletions

View File

@@ -1,4 +1,4 @@
package io.beaniejoy.dongnecafe.common.security
package io.beaniejoy.dongnecafe.security
import io.beaniejoy.dongnecafe.common.error.constant.ErrorCode
import io.beaniejoy.dongnecafe.common.error.exception.BusinessException

View File

@@ -1,4 +1,4 @@
package io.beaniejoy.dongnecafe.common.security
package io.beaniejoy.dongnecafe.security
import io.beaniejoy.dongnecafe.common.error.constant.ErrorCode
import io.beaniejoy.dongnecafe.common.error.exception.BusinessException

View File

@@ -1,5 +1,6 @@
package io.beaniejoy.dongnecafe.common.error.advice
import io.beaniejoy.dongnecafe.common.error.constant.ErrorCode
import io.beaniejoy.dongnecafe.common.error.exception.BusinessException
import io.beaniejoy.dongnecafe.common.response.ApplicationResponse
import mu.KLogging
@@ -13,11 +14,25 @@ class BasicControllerAdvice {
companion object : KLogging()
// 비즈니스 로직 상 에러 처리
/**
* 예외 상황 (500 시스템 오류 처리)
* @param e Exception
*/
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception::class)
fun handleException(e: Exception): ApplicationResponse {
logger.error { "[COMMON][${e.javaClass.simpleName}] $e" }
return ApplicationResponse.fail(errorCode = ErrorCode.COMMON_SERVER_ERROR)
}
/**
* 비즈니스 로직 상 에러 처리(예상 가능한 예외 처리)
* @param e BusinessException
*/
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(BusinessException::class)
fun handleBusinessException(e: BusinessException): ApplicationResponse {
logger.error { "[${BusinessException::class.simpleName}], <ErrorCode>: ${e.errorCode.name}, <ErrorMessage>: ${e.message}" }
logger.error { "[${BusinessException::class.simpleName}] <ErrorCode>: ${e.errorCode.name}, <ErrorMessage>: ${e.message}" }
return ApplicationResponse.fail(errorCode = e.errorCode)
}
}

View File

@@ -1,8 +1,13 @@
package io.beaniejoy.dongnecafe.common.error.constant
enum class Domain {
COMMON,
AUTH,
MEMBER,
CAFE,
CAFE_MENU
CAFE_MENU,
MENU_OPTION,
OPTION_DETAIL
}

View File

@@ -7,8 +7,10 @@ enum class ErrorCode(
val domain: Domain,
val subCategory: SubCategory
) {
// COMMON
COMMON_SERVER_ERROR(COMMON, SERVER_ERROR),
// AUTH(security 관련)
AUTH_COMMON_EXCEPTION(AUTH, COMMON),
AUTH_MEMBER_NOT_FOUND(AUTH, INVALID_AUTHENTICATE_REQUEST),
AUTH_PASSWORD_NOT_VALID(AUTH, INVALID_AUTHENTICATE_REQUEST),
AUTH_MEMBER_DEACTIVATED(AUTH, DEACTIVATED),
@@ -18,11 +20,16 @@ enum class ErrorCode(
// CAFE
CAFE_NOT_FOUND(CAFE, NOT_FOUND),
CAFE_EXISTED(CAFE, EXISTED);
CAFE_EXISTED(CAFE, EXISTED),
companion object {
fun convertOrNull(value: String?): ErrorCode? {
return values().find { it.name === value }
}
}
// CAFE_MENU
CAFE_MENU_NOT_FOUND(CAFE_MENU, NOT_FOUND),
// MENU_OPTION
MENU_OPTION_NOT_FOUND(MENU_OPTION, NOT_FOUND),
// OPTION_DETAIL
OPTION_DETAIL_NOT_FOUND(OPTION_DETAIL, NOT_FOUND)
;
}

View File

@@ -1,7 +1,7 @@
package io.beaniejoy.dongnecafe.common.error.constant
enum class SubCategory {
COMMON,
SERVER_ERROR,
INVALID_AUTHENTICATE_REQUEST,
NOT_FOUND,
EXISTED,

View File

@@ -76,6 +76,5 @@ class CafeController(
)
return ApplicationResponse.success("Successfully Cafe[$id] Info Updated")
}
}

View File

@@ -1,8 +1,9 @@
package io.beaniejoy.dongnecafe.domain.cafe.service
import io.beaniejoy.dongnecafe.domain.cafe.model.response.CafeMenuDetailedInfo
import io.beaniejoy.dongnecafe.error.exception.CafeMenuNotFoundException
import io.beaniejoy.dongnecafe.common.error.constant.ErrorCode
import io.beaniejoy.dongnecafe.common.error.exception.BusinessException
import io.beaniejoy.dongnecafe.domain.cafe.model.request.CafeMenuUpdateRequest
import io.beaniejoy.dongnecafe.domain.cafe.model.response.CafeMenuDetailedInfo
import io.beaniejoy.dongnecafe.domain.cafe.repository.CafeMenuRepository
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
@@ -20,14 +21,14 @@ class CafeMenuService(
@Transactional(readOnly = true)
fun getDetailedInfoByMenuId(menuId: Long, cafeId: Long): CafeMenuDetailedInfo {
val cafeMenu = cafeMenuRepository.findByIdOrNull(menuId)
?: throw CafeMenuNotFoundException(menuId = menuId, cafeId = cafeId)
?: throw BusinessException(ErrorCode.CAFE_MENU_NOT_FOUND)
return CafeMenuDetailedInfo.of(cafeMenu)
}
fun updateInfoAndBulkUpdate(menuId: Long, cafeId: Long, resource: CafeMenuUpdateRequest) {
val cafeMenu = cafeMenuRepository.findByIdOrNull(menuId)
?: throw CafeMenuNotFoundException(menuId = menuId, cafeId = cafeId)
?: throw BusinessException(ErrorCode.CAFE_MENU_NOT_FOUND)
cafeMenu.updateInfo(name = resource.name!!, price = resource.price)
@@ -36,7 +37,7 @@ class CafeMenuService(
fun deleteByCafeMenuId(menuId: Long, cafeId: Long) {
val cafeMenu = cafeMenuRepository.findByIdOrNull(menuId)
?: throw CafeMenuNotFoundException(menuId = menuId, cafeId = cafeId)
?: throw BusinessException(ErrorCode.CAFE_MENU_NOT_FOUND)
cafeMenuRepository.delete(cafeMenu)
}

View File

@@ -1,6 +1,7 @@
package io.beaniejoy.dongnecafe.domain.cafe.service
import io.beaniejoy.dongnecafe.error.exception.MenuOptionNotFoundException
import io.beaniejoy.dongnecafe.common.error.constant.ErrorCode
import io.beaniejoy.dongnecafe.common.error.exception.BusinessException
import io.beaniejoy.dongnecafe.domain.cafe.model.request.MenuOptionUpdateRequest
import io.beaniejoy.dongnecafe.domain.cafe.repository.MenuOptionRepository
import org.springframework.data.repository.findByIdOrNull
@@ -16,7 +17,7 @@ class MenuOptionService(
fun bulkUpdate(resources: List<MenuOptionUpdateRequest>) {
resources.forEach {
val menuOption = menuOptionRepository.findByIdOrNull(it.menuOptionId)
?: throw MenuOptionNotFoundException(it.menuOptionId)
?: throw BusinessException(ErrorCode.MENU_OPTION_NOT_FOUND)
if (it.isDelete) {
menuOptionRepository.delete(menuOption)

View File

@@ -1,6 +1,7 @@
package io.beaniejoy.dongnecafe.domain.cafe.service
import io.beaniejoy.dongnecafe.error.exception.OptionDetailNotFoundException
import io.beaniejoy.dongnecafe.common.error.constant.ErrorCode
import io.beaniejoy.dongnecafe.common.error.exception.BusinessException
import io.beaniejoy.dongnecafe.domain.cafe.model.request.OptionDetailUpdateRequest
import io.beaniejoy.dongnecafe.domain.cafe.repository.OptionDetailRepository
import org.springframework.data.repository.findByIdOrNull
@@ -15,7 +16,7 @@ class OptionDetailService(
fun bulkUpdate(resources: List<OptionDetailUpdateRequest>) {
resources.forEach {
val optionDetail = optionDetailRepository.findByIdOrNull(it.optionDetailId)
?: throw OptionDetailNotFoundException(it.optionDetailId)
?: throw BusinessException(ErrorCode.OPTION_DETAIL_NOT_FOUND)
if (it.isDelete) {
optionDetailRepository.delete(optionDetail)

View File

@@ -1,4 +0,0 @@
package io.beaniejoy.dongnecafe.error.exception
class CafeMenuNotFoundException(menuId: Long, cafeId: Long) :
RuntimeException("Cafe[${cafeId}]의 Menu[${menuId}]는 존재하지 않는 메뉴입니다.")

View File

@@ -1,3 +0,0 @@
package io.beaniejoy.dongnecafe.error.exception
class MenuOptionNotFoundException(menuOptionId: Long) : RuntimeException("MenuOption[$menuOptionId] is not found")

View File

@@ -1,3 +0,0 @@
package io.beaniejoy.dongnecafe.error.exception
class OptionDetailNotFoundException(optionDetailId: Long) : RuntimeException("OptionDetail[$optionDetailId] is not found")

View File

@@ -1,7 +1,8 @@
package io.beaniejoy.dongnecafe.domain.cafe.service
import io.beaniejoy.dongnecafe.common.error.constant.ErrorCode
import io.beaniejoy.dongnecafe.common.error.exception.BusinessException
import io.beaniejoy.dongnecafe.domain.cafe.entity.CafeMenu
import io.beaniejoy.dongnecafe.error.exception.CafeMenuNotFoundException
import io.beaniejoy.dongnecafe.domain.cafe.repository.CafeMenuRepository
import io.beaniejoy.dongnecafe.domain.cafe.repository.MenuOptionRepository
import io.beaniejoy.dongnecafe.domain.cafe.repository.OptionDetailRepository
@@ -81,12 +82,12 @@ internal class CafeMenuServiceTest {
`when`(mockCafeMenuRepository.findById(findCafeMenuId)).thenReturn(Optional.empty())
// then
val exception = assertThrows<CafeMenuNotFoundException> {
val exception = assertThrows<BusinessException> {
// when
mockCafeMenuService.getDetailedInfoByMenuId(findCafeMenuId, findCafeId)
}
assertEquals("Cafe[${findCafeId}]의 Menu[${findCafeMenuId}]는 존재하지 않는 메뉴입니다.", exception.message)
assertEquals(ErrorCode.CAFE_MENU_NOT_FOUND, exception.errorCode)
verify(mockCafeMenuRepository).findById(findCafeMenuId)
}