From cab20de7b196c52292746e3916ab40459e8d6e11 Mon Sep 17 00:00:00 2001 From: beaniejoy Date: Sat, 3 Dec 2022 20:43:15 +0900 Subject: [PATCH 1/4] =?UTF-8?q?[#26]=20feat:=20application=20=EC=A0=84?= =?UTF-8?q?=EC=B2=B4=20=EA=B3=B5=ED=86=B5=20response=20=EA=B7=9C=EA=B2=A9?= =?UTF-8?q?=ED=99=94=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ApplicationResponse 통한 공통 response 규격화 - BusinessException 적용(로직 상 예측 가능한 예외) - Exception handler 적용(ControllerAdvice) --- .../error/handler/CommonControllerAdvice.kt | 6 +-- .../error/advice/BasicControllerAdvice.kt | 23 ++++++++++ .../common/error/constant/Domain.kt | 7 +++ .../common/error/constant/ErrorCode.kt | 13 ++++++ .../common/error/constant/SubCategory.kt | 6 +++ .../error/exception/BusinessException.kt | 30 ++++++++++++ .../common/response/ApplicationResponse.kt | 46 +++++++++++++++++++ .../dongnecafe/common/response/ResultCode.kt | 6 +++ .../dongnecafe/error/ErrorResponse.kt | 6 --- .../common/config/SecurityConfig.kt | 3 +- .../domain/cafe/controller/CafeController.kt | 11 +++-- .../domain/cafe/service/CafeService.kt | 14 +++--- .../dongnecafe/error/CafeExceptionHandler.kt | 15 ------ .../error/exception/CafeExistedException.kt | 3 -- .../error/exception/CafeNotFoundException.kt | 3 -- .../domain/cafe/service/CafeServiceTest.kt | 12 +++-- 16 files changed, 157 insertions(+), 47 deletions(-) create mode 100644 dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/advice/BasicControllerAdvice.kt create mode 100644 dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/Domain.kt create mode 100644 dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/ErrorCode.kt create mode 100644 dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/SubCategory.kt create mode 100644 dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/exception/BusinessException.kt create mode 100644 dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/response/ApplicationResponse.kt create mode 100644 dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/response/ResultCode.kt delete mode 100644 dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/error/ErrorResponse.kt delete mode 100644 dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/CafeExceptionHandler.kt delete mode 100644 dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeExistedException.kt delete mode 100644 dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeNotFoundException.kt diff --git a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/handler/CommonControllerAdvice.kt b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/handler/CommonControllerAdvice.kt index 83d901c..98574dc 100644 --- a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/handler/CommonControllerAdvice.kt +++ b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/handler/CommonControllerAdvice.kt @@ -1,6 +1,6 @@ package io.beaniejoy.dongnecafe.error.handler -import io.beaniejoy.dongnecafe.error.ErrorResponse +import io.beaniejoy.dongnecafe.common.response.ApplicationResponse import mu.KLogging import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity @@ -15,10 +15,10 @@ class CommonControllerAdvice { companion object : KLogging() @ExceptionHandler(AuthenticationException::class) - fun handleAuthenticationException(e: AuthenticationException): ResponseEntity { + fun handleAuthenticationException(e: AuthenticationException): ResponseEntity> { logger.error { "AuthenticationException: ${e.message}" } return ResponseEntity.ok().body( - ErrorResponse( + ApplicationResponse( code = HttpStatus.BAD_REQUEST.value(), message = "계정 혹은 비밀번호가 일치하지 않습니다." ) diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/advice/BasicControllerAdvice.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/advice/BasicControllerAdvice.kt new file mode 100644 index 0000000..7c5a8b8 --- /dev/null +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/advice/BasicControllerAdvice.kt @@ -0,0 +1,23 @@ +package io.beaniejoy.dongnecafe.common.error.advice + +import io.beaniejoy.dongnecafe.common.error.exception.BusinessException +import io.beaniejoy.dongnecafe.common.response.ApplicationResponse +import mu.KLogging +import org.springframework.http.HttpStatus +import org.springframework.web.bind.annotation.ExceptionHandler +import org.springframework.web.bind.annotation.ResponseStatus +import org.springframework.web.bind.annotation.RestControllerAdvice + +@RestControllerAdvice +class BasicControllerAdvice { + + companion object: KLogging() + + @ResponseStatus(HttpStatus.OK) + @ExceptionHandler(BusinessException::class) + fun handleBusinessException(e: BusinessException): ApplicationResponse { + logger.error { "[BusinessException] ${e.errorCode.name}" } + + return ApplicationResponse.fail(e.errorCode, "error") + } +} \ No newline at end of file diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/Domain.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/Domain.kt new file mode 100644 index 0000000..2e37a56 --- /dev/null +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/Domain.kt @@ -0,0 +1,7 @@ +package io.beaniejoy.dongnecafe.common.error.constant + +enum class Domain { + AUTH, + CAFE, + CAFE_MENU +} \ No newline at end of file diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/ErrorCode.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/ErrorCode.kt new file mode 100644 index 0000000..1f6594f --- /dev/null +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/ErrorCode.kt @@ -0,0 +1,13 @@ +package io.beaniejoy.dongnecafe.common.error.constant + +import io.beaniejoy.dongnecafe.common.error.constant.Domain.CAFE +import io.beaniejoy.dongnecafe.common.error.constant.SubCategory.* + +enum class ErrorCode( + val domain: Domain, + val subCategory: SubCategory +) { + // CAFE + CAFE_NOT_FOUND(CAFE, NOT_FOUND), + CAFE_EXISTED(CAFE, EXISTED); +} \ No newline at end of file diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/SubCategory.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/SubCategory.kt new file mode 100644 index 0000000..b1b6717 --- /dev/null +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/SubCategory.kt @@ -0,0 +1,6 @@ +package io.beaniejoy.dongnecafe.common.error.constant + +enum class SubCategory { + NOT_FOUND, + EXISTED +} \ No newline at end of file diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/exception/BusinessException.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/exception/BusinessException.kt new file mode 100644 index 0000000..c945882 --- /dev/null +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/exception/BusinessException.kt @@ -0,0 +1,30 @@ +package io.beaniejoy.dongnecafe.common.error.exception + +import io.beaniejoy.dongnecafe.common.error.constant.ErrorCode + +/* +* Business Logic 상 발생 가능한 Exception +* - 로직상 개발자가 예측 가능한 예외 +* - front 측면에서 해당 에러에 대해서 error code(4xx, 5xx)보다 success code(2xx)를 응답받게 설계 +* - front에서 해당 예외 응답에 대해서 ErrorResponse의 Result field로 따로 구분해서 처리가능 +*/ +class BusinessException : RuntimeException { + var errorCode: ErrorCode + private set + + constructor(errorCode: ErrorCode) : super(errorCode.name){ + this.errorCode = errorCode + } + + constructor(errorCode: ErrorCode, message: String): super(message) { + this.errorCode = errorCode + } + + constructor(errorCode: ErrorCode, cause: Throwable) : super(cause) { + this.errorCode = errorCode + } + + constructor(errorCode: ErrorCode, message: String, cause: Throwable) : super(message, cause) { + this.errorCode = errorCode + } +} \ No newline at end of file diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/response/ApplicationResponse.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/response/ApplicationResponse.kt new file mode 100644 index 0000000..593e789 --- /dev/null +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/response/ApplicationResponse.kt @@ -0,0 +1,46 @@ +package io.beaniejoy.dongnecafe.common.response + +import com.fasterxml.jackson.annotation.JsonInclude +import io.beaniejoy.dongnecafe.common.error.constant.ErrorCode + +@JsonInclude(JsonInclude.Include.NON_NULL) +class ApplicationResponse { + var result: ResultCode + private set + + var data: Any? = null + private set + + var message: String? + private set + + var errorCode: String? = null + private set + + constructor(resultCode: ResultCode, message: String?) { + this.result = resultCode + this.message = message + } + + constructor(resultCode: ResultCode, errorCode: ErrorCode, message: String?) { + this.result = resultCode + this.errorCode = errorCode.name + this.message = message + } + + companion object { + fun success(message: String? = null): ApplicationResponse { + return ApplicationResponse(ResultCode.SUCCESS, message) + } + + fun fail(errorCode: ErrorCode, message: String?): ApplicationResponse { + return ApplicationResponse(ResultCode.FAIL, errorCode, message) + } + } + + fun data(data: Any): ApplicationResponse { + this.data = data + + return this + } +} \ No newline at end of file diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/response/ResultCode.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/response/ResultCode.kt new file mode 100644 index 0000000..df7f271 --- /dev/null +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/response/ResultCode.kt @@ -0,0 +1,6 @@ +package io.beaniejoy.dongnecafe.common.response + +enum class ResultCode { + SUCCESS, + FAIL; +} \ No newline at end of file diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/error/ErrorResponse.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/error/ErrorResponse.kt deleted file mode 100644 index a6e8abd..0000000 --- a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/error/ErrorResponse.kt +++ /dev/null @@ -1,6 +0,0 @@ -package io.beaniejoy.dongnecafe.error - -data class ErrorResponse( - val code: Int, - val message: String? -) \ No newline at end of file diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt index 7bf46f1..8cc4cb7 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt @@ -22,9 +22,10 @@ class SecurityConfig { fun filterChain(http: HttpSecurity): SecurityFilterChain { return http .csrf().disable() + .formLogin().disable() .authorizeRequests() - .anyRequest().authenticated() + .anyRequest().permitAll() .and() .also { jwtAuthenticationConfigurer(it) } diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeController.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeController.kt index f9b9bc1..e8c4833 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeController.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeController.kt @@ -1,5 +1,6 @@ package io.beaniejoy.dongnecafe.domain.cafe.controller +import io.beaniejoy.dongnecafe.common.response.ApplicationResponse import io.beaniejoy.dongnecafe.domain.cafe.model.request.CafeRegisterRequest import io.beaniejoy.dongnecafe.domain.cafe.model.request.CafeUpdateRequest import io.beaniejoy.dongnecafe.domain.cafe.model.response.CafeDetailedInfo @@ -20,14 +21,16 @@ class CafeController( * 신규 카페 생성 */ @PostMapping - fun createNewCafe(@RequestBody resource: CafeRegisterRequest): Long { - return cafeService.createNew( + fun createNewCafe(@RequestBody resource: CafeRegisterRequest): ApplicationResponse { + val newCafeId = cafeService.createNew( name = resource.name!!, address = resource.address!!, phoneNumber = resource.phoneNumber!!, description = resource.description!!, cafeMenuRequestList = resource.cafeMenuList ) + + return ApplicationResponse.success("OK").data(newCafeId) } /** @@ -36,8 +39,8 @@ class CafeController( @GetMapping fun searchCafeList( @PageableDefault(sort = ["name"], direction = Sort.Direction.ASC, page = 0, size = 10) pageable: Pageable - ): Page { - return cafeService.searchCafeList(pageable) + ): ApplicationResponse { + return ApplicationResponse.success().data(cafeService.searchCafeList(pageable)) } /** diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeService.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeService.kt index e311c5d..cc8092c 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeService.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeService.kt @@ -1,12 +1,12 @@ package io.beaniejoy.dongnecafe.domain.cafe.service +import io.beaniejoy.dongnecafe.domain.cafe.entity.Cafe +import io.beaniejoy.dongnecafe.domain.cafe.model.request.CafeMenuRegisterRequest import io.beaniejoy.dongnecafe.domain.cafe.model.response.CafeDetailedInfo import io.beaniejoy.dongnecafe.domain.cafe.model.response.CafeSearchInfo -import io.beaniejoy.dongnecafe.domain.cafe.model.request.CafeMenuRegisterRequest -import io.beaniejoy.dongnecafe.domain.cafe.entity.Cafe -import io.beaniejoy.dongnecafe.error.exception.CafeExistedException -import io.beaniejoy.dongnecafe.error.exception.CafeNotFoundException import io.beaniejoy.dongnecafe.domain.cafe.repository.CafeRepository +import io.beaniejoy.dongnecafe.common.error.constant.ErrorCode +import io.beaniejoy.dongnecafe.common.error.exception.BusinessException import mu.KLogging import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable @@ -55,7 +55,7 @@ class CafeService( private fun checkCafeExistedByName(name: String) { val findCafe = cafeRepository.findByName(name) if (findCafe != null) { - throw CafeExistedException(name) + throw BusinessException(ErrorCode.CAFE_EXISTED) } } @@ -67,7 +67,7 @@ class CafeService( fun getDetailedInfoByCafeId(id: Long): CafeDetailedInfo { val cafe = cafeRepository.findByIdOrNull(id) - ?: throw CafeNotFoundException(id) + ?: throw BusinessException(ErrorCode.CAFE_NOT_FOUND) return CafeDetailedInfo.of(cafe) } @@ -85,7 +85,7 @@ class CafeService( description: String, ) { val cafe = cafeRepository.findByIdOrNull(id) - ?: throw CafeNotFoundException(id) + ?: throw BusinessException(ErrorCode.CAFE_NOT_FOUND) cafe.updateInfo( name = name, diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/CafeExceptionHandler.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/CafeExceptionHandler.kt deleted file mode 100644 index 1d869ea..0000000 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/CafeExceptionHandler.kt +++ /dev/null @@ -1,15 +0,0 @@ -package io.beaniejoy.dongnecafe.error - -import io.beaniejoy.dongnecafe.error.exception.CafeNotFoundException -import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.ExceptionHandler -import org.springframework.web.bind.annotation.RestControllerAdvice - -@RestControllerAdvice -class CafeExceptionHandler { - // TODO: error 규격화 - @ExceptionHandler(CafeNotFoundException::class) - fun handleNotFound(exception: CafeNotFoundException): ResponseEntity { - return ResponseEntity.badRequest().body(exception.message) - } -} \ No newline at end of file diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeExistedException.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeExistedException.kt deleted file mode 100644 index e88e84c..0000000 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeExistedException.kt +++ /dev/null @@ -1,3 +0,0 @@ -package io.beaniejoy.dongnecafe.error.exception - -class CafeExistedException(name: String) : RuntimeException("Cafe[$name] is already existed") \ No newline at end of file diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeNotFoundException.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeNotFoundException.kt deleted file mode 100644 index e8a0c09..0000000 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeNotFoundException.kt +++ /dev/null @@ -1,3 +0,0 @@ -package io.beaniejoy.dongnecafe.error.exception - -class CafeNotFoundException(cafeId: Long) : RuntimeException("Cafe[$cafeId] is not found") \ No newline at end of file diff --git a/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeServiceTest.kt b/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeServiceTest.kt index 7914fe0..42d3315 100644 --- a/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeServiceTest.kt +++ b/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeServiceTest.kt @@ -1,10 +1,10 @@ package io.beaniejoy.dongnecafe.domain.cafe.service import io.beaniejoy.dongnecafe.domain.cafe.entity.Cafe -import io.beaniejoy.dongnecafe.error.exception.CafeExistedException -import io.beaniejoy.dongnecafe.error.exception.CafeNotFoundException import io.beaniejoy.dongnecafe.domain.cafe.repository.CafeRepository import io.beaniejoy.dongnecafe.domain.cafe.utils.CafeTestUtils +import io.beaniejoy.dongnecafe.common.error.constant.ErrorCode +import io.beaniejoy.dongnecafe.common.error.exception.BusinessException import org.junit.jupiter.api.* import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.extension.ExtendWith @@ -68,7 +68,7 @@ internal class CafeServiceTest { `when`(mockCafeRepository.findByName(name)).thenReturn(cafe) // then - assertThrows { + val exception = assertThrows { // when mockCafeService.createNew( name = name, @@ -78,8 +78,8 @@ internal class CafeServiceTest { cafeMenuRequestList = cafeMenuList ) } - verify(mockCafeRepository).findByName(name) + assertEquals(ErrorCode.CAFE_EXISTED, exception.errorCode) } @Test @@ -134,7 +134,7 @@ internal class CafeServiceTest { `when`(mockCafeRepository.findById(cafeId)).thenReturn(Optional.empty()) - assertThrows { + val exception = assertThrows { mockCafeService.updateInfo( id = cafeId, name = "", @@ -143,5 +143,7 @@ internal class CafeServiceTest { description = "", ) } + + assertEquals(ErrorCode.CAFE_NOT_FOUND, exception.errorCode) } } \ No newline at end of file From 8463fcf93202b76abc893f0e8bd73a5dae97e1c9 Mon Sep 17 00:00:00 2001 From: beaniejoy Date: Sun, 4 Dec 2022 01:52:49 +0900 Subject: [PATCH 2/4] =?UTF-8?q?[#26]=20feat:=20controller=20=EA=B7=9C?= =?UTF-8?q?=EA=B2=A9=ED=99=94=EB=90=9C=20response=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 모든 controller에 ApplicationResponse 적용 - 인증 프로세스 내 발생 가능한 예외 BusinessException 처리 - 불필요한 클래스 정리 --- .../security/ApiAuthenticationProvider.kt | 5 ++-- .../common/security/UserDetailsServiceImpl.kt | 8 ++--- .../security/model/AuthenticationResult.kt | 11 ------- .../dongnecafe/controller/AuthController.kt | 7 +++-- .../dongnecafe/controller/MemberController.kt | 9 ++++-- .../error/MemberExistedException.kt | 3 -- .../error/MemberNotActivatedException.kt | 3 -- .../error/handler/CommonControllerAdvice.kt | 27 ----------------- .../dongnecafe/service/MemberService.kt | 5 ++-- .../error/advice/BasicControllerAdvice.kt | 8 ++--- .../common/error/constant/Domain.kt | 1 + .../common/error/constant/ErrorCode.kt | 17 ++++++++++- .../common/error/constant/SubCategory.kt | 5 +++- .../common/response/ApplicationResponse.kt | 10 +++++-- .../common/config/SecurityConfig.kt | 6 +++- .../domain/cafe/controller/CafeController.kt | 26 ++++++++++------ .../cafe/controller/CafeMenuController.kt | 30 +++++++++---------- 17 files changed, 90 insertions(+), 91 deletions(-) delete mode 100644 dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/model/AuthenticationResult.kt delete mode 100644 dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/MemberExistedException.kt delete mode 100644 dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/MemberNotActivatedException.kt delete mode 100644 dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/handler/CommonControllerAdvice.kt diff --git a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/ApiAuthenticationProvider.kt b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/ApiAuthenticationProvider.kt index 6990e3d..b322867 100644 --- a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/ApiAuthenticationProvider.kt +++ b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/ApiAuthenticationProvider.kt @@ -1,9 +1,10 @@ package io.beaniejoy.dongnecafe.common.security +import io.beaniejoy.dongnecafe.common.error.constant.ErrorCode +import io.beaniejoy.dongnecafe.common.error.exception.BusinessException import io.beaniejoy.dongnecafe.security.SecurityUser import mu.KLogging import org.springframework.security.authentication.AuthenticationProvider -import org.springframework.security.authentication.BadCredentialsException import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.core.Authentication import org.springframework.security.core.userdetails.UserDetailsService @@ -29,7 +30,7 @@ class ApiAuthenticationProvider( val user = userDetailsService.loadUserByUsername(email) as SecurityUser if (!passwordEncoder.matches(password, user.password)) { - throw BadCredentialsException("Input password does not match stored password") + throw BusinessException(ErrorCode.AUTH_PASSWORD_NOT_VALID) } logger.info { "User password ${user.password}" } diff --git a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/UserDetailsServiceImpl.kt b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/UserDetailsServiceImpl.kt index b0259bb..e432913 100644 --- a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/UserDetailsServiceImpl.kt +++ b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/UserDetailsServiceImpl.kt @@ -1,13 +1,13 @@ package io.beaniejoy.dongnecafe.common.security +import io.beaniejoy.dongnecafe.common.error.constant.ErrorCode +import io.beaniejoy.dongnecafe.common.error.exception.BusinessException import io.beaniejoy.dongnecafe.domain.member.entity.Member import io.beaniejoy.dongnecafe.domain.member.repository.MemberRepository -import io.beaniejoy.dongnecafe.error.MemberDeactivatedException import io.beaniejoy.dongnecafe.security.SecurityUser import mu.KLogging import org.springframework.security.core.authority.SimpleGrantedAuthority import org.springframework.security.core.userdetails.UserDetailsService -import org.springframework.security.core.userdetails.UsernameNotFoundException import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional @@ -22,12 +22,12 @@ class UserDetailsServiceImpl( return memberRepository.findByEmail(email)?.let { logger.info { "[LOAD MEMBER] email: ${it.email}, role: ${it.roleType}, activated: ${it.activated}" } createSecurityUser(it) - } ?: throw UsernameNotFoundException("${email} is not found") + } ?: throw BusinessException(ErrorCode.AUTH_MEMBER_NOT_FOUND) } private fun createSecurityUser(member: Member): SecurityUser { if (member.activated.not()) { - throw MemberDeactivatedException(member.email) + throw BusinessException(ErrorCode.AUTH_MEMBER_DEACTIVATED) } return SecurityUser( diff --git a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/model/AuthenticationResult.kt b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/model/AuthenticationResult.kt deleted file mode 100644 index b5498f1..0000000 --- a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/model/AuthenticationResult.kt +++ /dev/null @@ -1,11 +0,0 @@ -package io.beaniejoy.dongnecafe.common.security.model - -import com.fasterxml.jackson.annotation.JsonInclude -import org.springframework.security.core.GrantedAuthority - -data class AuthenticationResult( - val email: String, - @JsonInclude(JsonInclude.Include.NON_EMPTY) - val authorities: Collection = listOf(), - val msg: String -) \ No newline at end of file diff --git a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/controller/AuthController.kt b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/controller/AuthController.kt index 37dcfce..4ee6fc1 100644 --- a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/controller/AuthController.kt +++ b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/controller/AuthController.kt @@ -1,5 +1,6 @@ package io.beaniejoy.dongnecafe.controller +import io.beaniejoy.dongnecafe.common.response.ApplicationResponse import io.beaniejoy.dongnecafe.security.JwtTokenUtils import io.beaniejoy.dongnecafe.domain.member.model.request.SignInRequest import io.beaniejoy.dongnecafe.model.TokenResponse @@ -16,7 +17,7 @@ class AuthController( private val jwtTokenUtils: JwtTokenUtils ) { @PostMapping("/authenticate") - fun signIn(@RequestBody signInRequest: SignInRequest): TokenResponse { + fun signIn(@RequestBody signInRequest: SignInRequest): ApplicationResponse { val authentication = authService.signIn( email = signInRequest.email, password = signInRequest.password @@ -24,6 +25,8 @@ class AuthController( val accessToken = jwtTokenUtils.createToken(authentication) - return TokenResponse(accessToken) + return ApplicationResponse + .success("success authenticate") + .data(TokenResponse(accessToken)) } } \ No newline at end of file diff --git a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/controller/MemberController.kt b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/controller/MemberController.kt index c367131..2782d3d 100644 --- a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/controller/MemberController.kt +++ b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/controller/MemberController.kt @@ -1,5 +1,6 @@ package io.beaniejoy.dongnecafe.controller +import io.beaniejoy.dongnecafe.common.response.ApplicationResponse import io.beaniejoy.dongnecafe.domain.member.model.request.MemberRegisterRequest import io.beaniejoy.dongnecafe.service.MemberService import org.springframework.web.bind.annotation.PostMapping @@ -13,7 +14,11 @@ class MemberController( private val memberService: MemberService ) { @PostMapping("/sign-up") - fun signUp(@RequestBody resource: MemberRegisterRequest): Long { - return memberService.registerMember(resource) + fun signUp(@RequestBody resource: MemberRegisterRequest): ApplicationResponse { + val registerMemberId = memberService.registerMember(resource) + + return ApplicationResponse + .success("success sign up") + .data(registerMemberId) } } \ No newline at end of file diff --git a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/MemberExistedException.kt b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/MemberExistedException.kt deleted file mode 100644 index 31d58e1..0000000 --- a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/MemberExistedException.kt +++ /dev/null @@ -1,3 +0,0 @@ -package io.beaniejoy.dongnecafe.error - -class MemberExistedException(email: String): RuntimeException("Member[$email] is already existed") \ No newline at end of file diff --git a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/MemberNotActivatedException.kt b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/MemberNotActivatedException.kt deleted file mode 100644 index 97bedd5..0000000 --- a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/MemberNotActivatedException.kt +++ /dev/null @@ -1,3 +0,0 @@ -package io.beaniejoy.dongnecafe.error - -class MemberDeactivatedException(email: String): RuntimeException("Member[$email] is deactivated") \ No newline at end of file diff --git a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/handler/CommonControllerAdvice.kt b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/handler/CommonControllerAdvice.kt deleted file mode 100644 index 98574dc..0000000 --- a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/handler/CommonControllerAdvice.kt +++ /dev/null @@ -1,27 +0,0 @@ -package io.beaniejoy.dongnecafe.error.handler - -import io.beaniejoy.dongnecafe.common.response.ApplicationResponse -import mu.KLogging -import org.springframework.http.HttpStatus -import org.springframework.http.ResponseEntity -import org.springframework.security.core.AuthenticationException -import org.springframework.web.bind.annotation.ExceptionHandler -import org.springframework.web.bind.annotation.RestControllerAdvice - -// TODO 통합된 에러 핸들링 필요(ErrorResponse 규격화) -@RestControllerAdvice -class CommonControllerAdvice { - - companion object : KLogging() - - @ExceptionHandler(AuthenticationException::class) - fun handleAuthenticationException(e: AuthenticationException): ResponseEntity> { - logger.error { "AuthenticationException: ${e.message}" } - return ResponseEntity.ok().body( - ApplicationResponse( - code = HttpStatus.BAD_REQUEST.value(), - message = "계정 혹은 비밀번호가 일치하지 않습니다." - ) - ) - } -} \ No newline at end of file diff --git a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/service/MemberService.kt b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/service/MemberService.kt index f4e11d7..3882b99 100644 --- a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/service/MemberService.kt +++ b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/service/MemberService.kt @@ -1,9 +1,10 @@ package io.beaniejoy.dongnecafe.service +import io.beaniejoy.dongnecafe.common.error.constant.ErrorCode +import io.beaniejoy.dongnecafe.common.error.exception.BusinessException import io.beaniejoy.dongnecafe.domain.member.entity.Member import io.beaniejoy.dongnecafe.domain.member.model.request.MemberRegisterRequest import io.beaniejoy.dongnecafe.domain.member.repository.MemberRepository -import io.beaniejoy.dongnecafe.error.MemberExistedException import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -16,7 +17,7 @@ class MemberService( ) { fun registerMember(resource: MemberRegisterRequest): Long { memberRepository.findByEmail(resource.email!!)?.also { - throw MemberExistedException(resource.email!!) + throw BusinessException(ErrorCode.MEMBER_EXISTED) } val registeredMember = memberRepository.save( diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/advice/BasicControllerAdvice.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/advice/BasicControllerAdvice.kt index 7c5a8b8..889b079 100644 --- a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/advice/BasicControllerAdvice.kt +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/advice/BasicControllerAdvice.kt @@ -11,13 +11,13 @@ import org.springframework.web.bind.annotation.RestControllerAdvice @RestControllerAdvice class BasicControllerAdvice { - companion object: KLogging() + companion object : KLogging() + // 비즈니스 로직 상 에러 처리 @ResponseStatus(HttpStatus.OK) @ExceptionHandler(BusinessException::class) fun handleBusinessException(e: BusinessException): ApplicationResponse { - logger.error { "[BusinessException] ${e.errorCode.name}" } - - return ApplicationResponse.fail(e.errorCode, "error") + logger.error { "[${BusinessException::class.simpleName}], : ${e.errorCode.name}, : ${e.message}" } + return ApplicationResponse.fail(errorCode = e.errorCode) } } \ No newline at end of file diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/Domain.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/Domain.kt index 2e37a56..17ae0b2 100644 --- a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/Domain.kt +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/Domain.kt @@ -2,6 +2,7 @@ package io.beaniejoy.dongnecafe.common.error.constant enum class Domain { AUTH, + MEMBER, CAFE, CAFE_MENU } \ No newline at end of file diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/ErrorCode.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/ErrorCode.kt index 1f6594f..097a98d 100644 --- a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/ErrorCode.kt +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/ErrorCode.kt @@ -1,13 +1,28 @@ package io.beaniejoy.dongnecafe.common.error.constant -import io.beaniejoy.dongnecafe.common.error.constant.Domain.CAFE +import io.beaniejoy.dongnecafe.common.error.constant.Domain.* import io.beaniejoy.dongnecafe.common.error.constant.SubCategory.* enum class ErrorCode( val domain: Domain, val subCategory: SubCategory ) { + // 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), + + // MEMBER + MEMBER_EXISTED(MEMBER, EXISTED), + // CAFE CAFE_NOT_FOUND(CAFE, NOT_FOUND), CAFE_EXISTED(CAFE, EXISTED); + + companion object { + fun convertOrNull(value: String?): ErrorCode? { + return values().find { it.name === value } + } + } } \ No newline at end of file diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/SubCategory.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/SubCategory.kt index b1b6717..8a0087a 100644 --- a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/SubCategory.kt +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/SubCategory.kt @@ -1,6 +1,9 @@ package io.beaniejoy.dongnecafe.common.error.constant enum class SubCategory { + COMMON, + INVALID_AUTHENTICATE_REQUEST, NOT_FOUND, - EXISTED + EXISTED, + DEACTIVATED } \ No newline at end of file diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/response/ApplicationResponse.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/response/ApplicationResponse.kt index 593e789..054efa3 100644 --- a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/response/ApplicationResponse.kt +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/response/ApplicationResponse.kt @@ -30,11 +30,15 @@ class ApplicationResponse { companion object { fun success(message: String? = null): ApplicationResponse { - return ApplicationResponse(ResultCode.SUCCESS, message) + return ApplicationResponse(resultCode = ResultCode.SUCCESS, message = message) } - fun fail(errorCode: ErrorCode, message: String?): ApplicationResponse { - return ApplicationResponse(ResultCode.FAIL, errorCode, message) + fun fail(errorCode: ErrorCode, message: String? = null): ApplicationResponse { + return ApplicationResponse( + resultCode = ResultCode.FAIL, + errorCode = errorCode, + message = message + ) } } diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt index 8cc4cb7..9a89442 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt @@ -6,10 +6,10 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.security.servlet.PathRequest import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration -import org.springframework.http.HttpMethod import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer +import org.springframework.security.config.http.SessionCreationPolicy import org.springframework.security.web.SecurityFilterChain @Configuration @@ -27,6 +27,10 @@ class SecurityConfig { .authorizeRequests() .anyRequest().permitAll() + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 토큰 방식(세션 불필요) + .and() .also { jwtAuthenticationConfigurer(it) } .build() diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeController.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeController.kt index e8c4833..63faa0a 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeController.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeController.kt @@ -3,10 +3,7 @@ package io.beaniejoy.dongnecafe.domain.cafe.controller import io.beaniejoy.dongnecafe.common.response.ApplicationResponse import io.beaniejoy.dongnecafe.domain.cafe.model.request.CafeRegisterRequest import io.beaniejoy.dongnecafe.domain.cafe.model.request.CafeUpdateRequest -import io.beaniejoy.dongnecafe.domain.cafe.model.response.CafeDetailedInfo -import io.beaniejoy.dongnecafe.domain.cafe.model.response.CafeSearchInfo import io.beaniejoy.dongnecafe.domain.cafe.service.CafeService -import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable import org.springframework.data.domain.Sort import org.springframework.data.web.PageableDefault @@ -30,7 +27,9 @@ class CafeController( cafeMenuRequestList = resource.cafeMenuList ) - return ApplicationResponse.success("OK").data(newCafeId) + return ApplicationResponse + .success("OK") + .data(newCafeId) } /** @@ -40,15 +39,23 @@ class CafeController( fun searchCafeList( @PageableDefault(sort = ["name"], direction = Sort.Direction.ASC, page = 0, size = 10) pageable: Pageable ): ApplicationResponse { - return ApplicationResponse.success().data(cafeService.searchCafeList(pageable)) + val searchCafes = cafeService.searchCafeList(pageable) + + return ApplicationResponse + .success() + .data(searchCafes) } /** * 단일 카페 상세 조회 */ @GetMapping("/{id}") - fun getDetailedInfo(@PathVariable("id") id: Long): CafeDetailedInfo { - return cafeService.getDetailedInfoByCafeId(id) + fun getDetailedInfo(@PathVariable("id") id: Long): ApplicationResponse { + val cafeDetailedInfo = cafeService.getDetailedInfoByCafeId(id) + + return ApplicationResponse + .success() + .data(cafeDetailedInfo) } /** @@ -59,7 +66,7 @@ class CafeController( fun updateInfo( @PathVariable("id") id: Long, @RequestBody resource: CafeUpdateRequest - ): String { + ): ApplicationResponse { cafeService.updateInfo( id = id, name = resource.name!!, @@ -68,6 +75,7 @@ class CafeController( description = resource.description!! ) - return "Successfully Cafe[$id] Info Updated" + return ApplicationResponse.success("Successfully Cafe[$id] Info Updated") + } } \ No newline at end of file diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeMenuController.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeMenuController.kt index 4e41697..7695069 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeMenuController.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeMenuController.kt @@ -1,16 +1,10 @@ package io.beaniejoy.dongnecafe.domain.cafe.controller +import io.beaniejoy.dongnecafe.common.response.ApplicationResponse import io.beaniejoy.dongnecafe.domain.cafe.model.request.CafeMenuBulkDeleteRequest import io.beaniejoy.dongnecafe.domain.cafe.model.request.CafeMenuUpdateRequest -import io.beaniejoy.dongnecafe.domain.cafe.model.response.CafeMenuDetailedInfo import io.beaniejoy.dongnecafe.domain.cafe.service.CafeMenuService -import org.springframework.web.bind.annotation.DeleteMapping -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.PatchMapping -import org.springframework.web.bind.annotation.PathVariable -import org.springframework.web.bind.annotation.RequestBody -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RestController +import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/api/cafes/{cafeId}/menus") @@ -24,11 +18,15 @@ class CafeMenuController( fun getDetailedInfo( @PathVariable("cafeId") cafeId: Long, @PathVariable("menuId") menuId: Long - ): CafeMenuDetailedInfo { - return cafeMenuService.getDetailedInfoByMenuId( + ): ApplicationResponse { + val cafeMenuDetailedInfo = cafeMenuService.getDetailedInfoByMenuId( menuId = menuId, cafeId = cafeId ) + + return ApplicationResponse + .success() + .data(cafeMenuDetailedInfo) } /** @@ -42,14 +40,14 @@ class CafeMenuController( @PathVariable("cafeId") cafeId: Long, @PathVariable("menuId") menuId: Long, @RequestBody cafeMenuUpdateRequest: CafeMenuUpdateRequest - ): String { + ): ApplicationResponse { cafeMenuService.updateInfoAndBulkUpdate( menuId = menuId, cafeId = cafeId, resource = cafeMenuUpdateRequest ) - return "Success Update Cafe[$cafeId]'s CafeMenu[$menuId]" + return ApplicationResponse.success("Success Update Cafe[$cafeId]'s CafeMenu[$menuId]") } /** @@ -59,13 +57,13 @@ class CafeMenuController( fun delete( @PathVariable("cafeId") cafeId: Long, @PathVariable("menuId") menuId: Long - ): String { + ): ApplicationResponse { cafeMenuService.deleteByCafeMenuId( menuId = menuId, cafeId = cafeId ) - return "Success Delete Cafe[$cafeId]'s CafeMenu[$menuId]" + return ApplicationResponse.success("Success Delete Cafe[$cafeId]'s CafeMenu[$menuId]") } /** @@ -75,9 +73,9 @@ class CafeMenuController( fun bulkDelete( @PathVariable("cafeId") cafeId: Long, @RequestBody resource: CafeMenuBulkDeleteRequest - ): String { + ): ApplicationResponse { cafeMenuService.bulkDelete(cafeId, resource.cafeMenuIdList) - return "Success Delete Cafe[$cafeId]'s CafeMenu List" + return ApplicationResponse.success("Success Delete Cafe[$cafeId]'s CafeMenu List") } } \ No newline at end of file From b6acd3578ace123ce6aaa9497308806a592924cb Mon Sep 17 00:00:00 2001 From: beaniejoy Date: Sun, 4 Dec 2022 03:04:29 +0900 Subject: [PATCH 3/4] =?UTF-8?q?[#26]=20feat:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20Exception=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20?= =?UTF-8?q?=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CafeMenu, MenuOption, OptionDetail 관련 Exception 통합(BusinessException) - 시스템 관련 에러 핸들러 추가(BasicControllerAdvice) - 불필요한 클래스 제거 - 패키지 이동(account-api security package) --- .../security/ApiAuthenticationProvider.kt | 2 +- .../security/UserDetailsServiceImpl.kt | 2 +- .../error/advice/BasicControllerAdvice.kt | 19 +++++++++++++++-- .../common/error/constant/Domain.kt | 7 ++++++- .../common/error/constant/ErrorCode.kt | 21 ++++++++++++------- .../common/error/constant/SubCategory.kt | 2 +- .../domain/cafe/controller/CafeController.kt | 1 - .../domain/cafe/service/CafeMenuService.kt | 11 +++++----- .../domain/cafe/service/MenuOptionService.kt | 5 +++-- .../cafe/service/OptionDetailService.kt | 5 +++-- .../exception/CafeMenuNotFoundException.kt | 4 ---- .../exception/MenuOptionNotFoundException.kt | 3 --- .../OptionDetailNotFoundException.kt | 3 --- .../cafe/service/CafeMenuServiceTest.kt | 7 ++++--- 14 files changed, 56 insertions(+), 36 deletions(-) rename dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/{common => }/security/ApiAuthenticationProvider.kt (97%) rename dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/{common => }/security/UserDetailsServiceImpl.kt (96%) delete mode 100644 dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeMenuNotFoundException.kt delete mode 100644 dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/MenuOptionNotFoundException.kt delete mode 100644 dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/OptionDetailNotFoundException.kt diff --git a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/ApiAuthenticationProvider.kt b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/security/ApiAuthenticationProvider.kt similarity index 97% rename from dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/ApiAuthenticationProvider.kt rename to dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/security/ApiAuthenticationProvider.kt index b322867..18df2f0 100644 --- a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/ApiAuthenticationProvider.kt +++ b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/security/ApiAuthenticationProvider.kt @@ -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 diff --git a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/UserDetailsServiceImpl.kt b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/security/UserDetailsServiceImpl.kt similarity index 96% rename from dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/UserDetailsServiceImpl.kt rename to dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/security/UserDetailsServiceImpl.kt index e432913..d1ef467 100644 --- a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/security/UserDetailsServiceImpl.kt +++ b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/security/UserDetailsServiceImpl.kt @@ -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 diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/advice/BasicControllerAdvice.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/advice/BasicControllerAdvice.kt index 889b079..ed9b7de 100644 --- a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/advice/BasicControllerAdvice.kt +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/advice/BasicControllerAdvice.kt @@ -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}], : ${e.errorCode.name}, : ${e.message}" } + logger.error { "[${BusinessException::class.simpleName}] : ${e.errorCode.name}, : ${e.message}" } return ApplicationResponse.fail(errorCode = e.errorCode) } } \ No newline at end of file diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/Domain.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/Domain.kt index 17ae0b2..8aef3f6 100644 --- a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/Domain.kt +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/Domain.kt @@ -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 } \ No newline at end of file diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/ErrorCode.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/ErrorCode.kt index 097a98d..b2422ad 100644 --- a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/ErrorCode.kt +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/ErrorCode.kt @@ -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) + + ; } \ No newline at end of file diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/SubCategory.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/SubCategory.kt index 8a0087a..c70d169 100644 --- a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/SubCategory.kt +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/constant/SubCategory.kt @@ -1,7 +1,7 @@ package io.beaniejoy.dongnecafe.common.error.constant enum class SubCategory { - COMMON, + SERVER_ERROR, INVALID_AUTHENTICATE_REQUEST, NOT_FOUND, EXISTED, diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeController.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeController.kt index 63faa0a..5b59c65 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeController.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeController.kt @@ -76,6 +76,5 @@ class CafeController( ) return ApplicationResponse.success("Successfully Cafe[$id] Info Updated") - } } \ No newline at end of file diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeMenuService.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeMenuService.kt index 72733c6..f00f628 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeMenuService.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeMenuService.kt @@ -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) } diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/MenuOptionService.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/MenuOptionService.kt index a34440e..6954744 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/MenuOptionService.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/MenuOptionService.kt @@ -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) { 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) diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/OptionDetailService.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/OptionDetailService.kt index 94e5753..43cde2f 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/OptionDetailService.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/OptionDetailService.kt @@ -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) { 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) diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeMenuNotFoundException.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeMenuNotFoundException.kt deleted file mode 100644 index bb60691..0000000 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/CafeMenuNotFoundException.kt +++ /dev/null @@ -1,4 +0,0 @@ -package io.beaniejoy.dongnecafe.error.exception - -class CafeMenuNotFoundException(menuId: Long, cafeId: Long) : - RuntimeException("Cafe[${cafeId}]의 Menu[${menuId}]는 존재하지 않는 메뉴입니다.") \ No newline at end of file diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/MenuOptionNotFoundException.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/MenuOptionNotFoundException.kt deleted file mode 100644 index cb42fe7..0000000 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/MenuOptionNotFoundException.kt +++ /dev/null @@ -1,3 +0,0 @@ -package io.beaniejoy.dongnecafe.error.exception - -class MenuOptionNotFoundException(menuOptionId: Long) : RuntimeException("MenuOption[$menuOptionId] is not found") \ No newline at end of file diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/OptionDetailNotFoundException.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/OptionDetailNotFoundException.kt deleted file mode 100644 index 69df3ac..0000000 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/error/exception/OptionDetailNotFoundException.kt +++ /dev/null @@ -1,3 +0,0 @@ -package io.beaniejoy.dongnecafe.error.exception - -class OptionDetailNotFoundException(optionDetailId: Long) : RuntimeException("OptionDetail[$optionDetailId] is not found") \ No newline at end of file diff --git a/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeMenuServiceTest.kt b/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeMenuServiceTest.kt index f9789a2..aae2eb1 100644 --- a/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeMenuServiceTest.kt +++ b/dongne-service-api/src/test/kotlin/io/beaniejoy/dongnecafe/domain/cafe/service/CafeMenuServiceTest.kt @@ -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 { + val exception = assertThrows { // when mockCafeMenuService.getDetailedInfoByMenuId(findCafeMenuId, findCafeId) } - assertEquals("Cafe[${findCafeId}]의 Menu[${findCafeMenuId}]는 존재하지 않는 메뉴입니다.", exception.message) + assertEquals(ErrorCode.CAFE_MENU_NOT_FOUND, exception.errorCode) verify(mockCafeMenuRepository).findById(findCafeMenuId) } From 4caac765142744ffa89f2565928ba6af850d681c Mon Sep 17 00:00:00 2001 From: Hanbin Lee Date: Sat, 31 Dec 2022 19:43:42 +0900 Subject: [PATCH 4/4] =?UTF-8?q?[#26]=20feat:=20ApplicationResponse=20Build?= =?UTF-8?q?er=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ApplicationResponse Generic type 지정하기 위해 중간 팩토리 클래스 적용 (ApplicationResponseBuilder) --- .../dongnecafe/controller/AuthController.kt | 2 +- .../dongnecafe/controller/MemberController.kt | 2 +- .../error/advice/BasicControllerAdvice.kt | 8 +-- .../common/response/ApplicationResponse.kt | 71 +++++++++---------- .../common/config/SecurityConfig.kt | 1 + .../domain/cafe/controller/CafeController.kt | 15 ++-- .../cafe/controller/CafeMenuController.kt | 21 ++++-- 7 files changed, 66 insertions(+), 54 deletions(-) diff --git a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/controller/AuthController.kt b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/controller/AuthController.kt index 4ee6fc1..92ab5d8 100644 --- a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/controller/AuthController.kt +++ b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/controller/AuthController.kt @@ -17,7 +17,7 @@ class AuthController( private val jwtTokenUtils: JwtTokenUtils ) { @PostMapping("/authenticate") - fun signIn(@RequestBody signInRequest: SignInRequest): ApplicationResponse { + fun signIn(@RequestBody signInRequest: SignInRequest): ApplicationResponse { val authentication = authService.signIn( email = signInRequest.email, password = signInRequest.password diff --git a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/controller/MemberController.kt b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/controller/MemberController.kt index 2782d3d..a61b158 100644 --- a/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/controller/MemberController.kt +++ b/dongne-account-api/src/main/kotlin/io/beaniejoy/dongnecafe/controller/MemberController.kt @@ -14,7 +14,7 @@ class MemberController( private val memberService: MemberService ) { @PostMapping("/sign-up") - fun signUp(@RequestBody resource: MemberRegisterRequest): ApplicationResponse { + fun signUp(@RequestBody resource: MemberRegisterRequest): ApplicationResponse { val registerMemberId = memberService.registerMember(resource) return ApplicationResponse diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/advice/BasicControllerAdvice.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/advice/BasicControllerAdvice.kt index ed9b7de..e5748fb 100644 --- a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/advice/BasicControllerAdvice.kt +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/error/advice/BasicControllerAdvice.kt @@ -20,9 +20,9 @@ class BasicControllerAdvice { */ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ExceptionHandler(Exception::class) - fun handleException(e: Exception): ApplicationResponse { + fun handleException(e: Exception): ApplicationResponse { logger.error { "[COMMON][${e.javaClass.simpleName}] $e" } - return ApplicationResponse.fail(errorCode = ErrorCode.COMMON_SERVER_ERROR) + return ApplicationResponse.fail(errorCode = ErrorCode.COMMON_SERVER_ERROR).build() } /** @@ -31,8 +31,8 @@ class BasicControllerAdvice { */ @ResponseStatus(HttpStatus.OK) @ExceptionHandler(BusinessException::class) - fun handleBusinessException(e: BusinessException): ApplicationResponse { + fun handleBusinessException(e: BusinessException): ApplicationResponse { logger.error { "[${BusinessException::class.simpleName}] : ${e.errorCode.name}, : ${e.message}" } - return ApplicationResponse.fail(errorCode = e.errorCode) + return ApplicationResponse.fail(errorCode = e.errorCode).build() } } \ No newline at end of file diff --git a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/response/ApplicationResponse.kt b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/response/ApplicationResponse.kt index 054efa3..5f4bae9 100644 --- a/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/response/ApplicationResponse.kt +++ b/dongne-common/src/main/kotlin/io/beaniejoy/dongnecafe/common/response/ApplicationResponse.kt @@ -4,47 +4,46 @@ import com.fasterxml.jackson.annotation.JsonInclude import io.beaniejoy.dongnecafe.common.error.constant.ErrorCode @JsonInclude(JsonInclude.Include.NON_NULL) -class ApplicationResponse { - var result: ResultCode - private set - - var data: Any? = null - private set - - var message: String? - private set - - var errorCode: String? = null - private set - - constructor(resultCode: ResultCode, message: String?) { - this.result = resultCode - this.message = message - } - - constructor(resultCode: ResultCode, errorCode: ErrorCode, message: String?) { - this.result = resultCode - this.errorCode = errorCode.name - this.message = message - } - +class ApplicationResponse( + val result: ResultCode, + val message: String? = null, + val errorCode: String? = null, + val data: T? = null +) { companion object { - fun success(message: String? = null): ApplicationResponse { - return ApplicationResponse(resultCode = ResultCode.SUCCESS, message = message) - } - - fun fail(errorCode: ErrorCode, message: String? = null): ApplicationResponse { - return ApplicationResponse( - resultCode = ResultCode.FAIL, - errorCode = errorCode, + fun success(message: String? = null): ApplicationResponseBuilder { + return ApplicationResponseBuilder( + result = ResultCode.SUCCESS, message = message ) } + + fun fail(errorCode: ErrorCode, message: String? = null): ApplicationResponseBuilder { + return ApplicationResponseBuilder( + result = ResultCode.FAIL, + message = message, + errorCode = errorCode.name + ) + } + } +} + +class ApplicationResponseBuilder( + var result: ResultCode, + var message: String? = null, + var errorCode: String? = null +) { + fun build(): ApplicationResponse { + return data(null) } - fun data(data: Any): ApplicationResponse { - this.data = data - - return this + fun data(data: T?): ApplicationResponse { + return ApplicationResponse( + result = this.result, + message = this.message, + data = data, + errorCode = errorCode + ) } + } \ No newline at end of file diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt index 9a89442..50252a0 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/common/config/SecurityConfig.kt @@ -24,6 +24,7 @@ class SecurityConfig { .csrf().disable() .formLogin().disable() + // FIXME 임시 permitAll 설정 .authorizeRequests() .anyRequest().permitAll() diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeController.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeController.kt index 5b59c65..39341e1 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeController.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeController.kt @@ -3,7 +3,10 @@ package io.beaniejoy.dongnecafe.domain.cafe.controller import io.beaniejoy.dongnecafe.common.response.ApplicationResponse import io.beaniejoy.dongnecafe.domain.cafe.model.request.CafeRegisterRequest import io.beaniejoy.dongnecafe.domain.cafe.model.request.CafeUpdateRequest +import io.beaniejoy.dongnecafe.domain.cafe.model.response.CafeDetailedInfo +import io.beaniejoy.dongnecafe.domain.cafe.model.response.CafeSearchInfo import io.beaniejoy.dongnecafe.domain.cafe.service.CafeService +import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable import org.springframework.data.domain.Sort import org.springframework.data.web.PageableDefault @@ -18,7 +21,7 @@ class CafeController( * 신규 카페 생성 */ @PostMapping - fun createNewCafe(@RequestBody resource: CafeRegisterRequest): ApplicationResponse { + fun createNewCafe(@RequestBody resource: CafeRegisterRequest): ApplicationResponse { val newCafeId = cafeService.createNew( name = resource.name!!, address = resource.address!!, @@ -38,7 +41,7 @@ class CafeController( @GetMapping fun searchCafeList( @PageableDefault(sort = ["name"], direction = Sort.Direction.ASC, page = 0, size = 10) pageable: Pageable - ): ApplicationResponse { + ): ApplicationResponse> { val searchCafes = cafeService.searchCafeList(pageable) return ApplicationResponse @@ -50,7 +53,7 @@ class CafeController( * 단일 카페 상세 조회 */ @GetMapping("/{id}") - fun getDetailedInfo(@PathVariable("id") id: Long): ApplicationResponse { + fun getDetailedInfo(@PathVariable("id") id: Long): ApplicationResponse { val cafeDetailedInfo = cafeService.getDetailedInfoByCafeId(id) return ApplicationResponse @@ -66,7 +69,7 @@ class CafeController( fun updateInfo( @PathVariable("id") id: Long, @RequestBody resource: CafeUpdateRequest - ): ApplicationResponse { + ): ApplicationResponse { cafeService.updateInfo( id = id, name = resource.name!!, @@ -75,6 +78,8 @@ class CafeController( description = resource.description!! ) - return ApplicationResponse.success("Successfully Cafe[$id] Info Updated") + return ApplicationResponse + .success("Successfully Cafe[$id] Info Updated") + .build() } } \ No newline at end of file diff --git a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeMenuController.kt b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeMenuController.kt index 7695069..3219804 100644 --- a/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeMenuController.kt +++ b/dongne-service-api/src/main/kotlin/io/beaniejoy/dongnecafe/domain/cafe/controller/CafeMenuController.kt @@ -3,6 +3,7 @@ package io.beaniejoy.dongnecafe.domain.cafe.controller import io.beaniejoy.dongnecafe.common.response.ApplicationResponse import io.beaniejoy.dongnecafe.domain.cafe.model.request.CafeMenuBulkDeleteRequest import io.beaniejoy.dongnecafe.domain.cafe.model.request.CafeMenuUpdateRequest +import io.beaniejoy.dongnecafe.domain.cafe.model.response.CafeMenuDetailedInfo import io.beaniejoy.dongnecafe.domain.cafe.service.CafeMenuService import org.springframework.web.bind.annotation.* @@ -18,7 +19,7 @@ class CafeMenuController( fun getDetailedInfo( @PathVariable("cafeId") cafeId: Long, @PathVariable("menuId") menuId: Long - ): ApplicationResponse { + ): ApplicationResponse { val cafeMenuDetailedInfo = cafeMenuService.getDetailedInfoByMenuId( menuId = menuId, cafeId = cafeId @@ -40,14 +41,16 @@ class CafeMenuController( @PathVariable("cafeId") cafeId: Long, @PathVariable("menuId") menuId: Long, @RequestBody cafeMenuUpdateRequest: CafeMenuUpdateRequest - ): ApplicationResponse { + ): ApplicationResponse { cafeMenuService.updateInfoAndBulkUpdate( menuId = menuId, cafeId = cafeId, resource = cafeMenuUpdateRequest ) - return ApplicationResponse.success("Success Update Cafe[$cafeId]'s CafeMenu[$menuId]") + return ApplicationResponse + .success("Success Update Cafe[$cafeId]'s CafeMenu[$menuId]") + .build() } /** @@ -57,13 +60,15 @@ class CafeMenuController( fun delete( @PathVariable("cafeId") cafeId: Long, @PathVariable("menuId") menuId: Long - ): ApplicationResponse { + ): ApplicationResponse { cafeMenuService.deleteByCafeMenuId( menuId = menuId, cafeId = cafeId ) - return ApplicationResponse.success("Success Delete Cafe[$cafeId]'s CafeMenu[$menuId]") + return ApplicationResponse + .success("Success Delete Cafe[$cafeId]'s CafeMenu[$menuId]") + .build() } /** @@ -73,9 +78,11 @@ class CafeMenuController( fun bulkDelete( @PathVariable("cafeId") cafeId: Long, @RequestBody resource: CafeMenuBulkDeleteRequest - ): ApplicationResponse { + ): ApplicationResponse { cafeMenuService.bulkDelete(cafeId, resource.cafeMenuIdList) - return ApplicationResponse.success("Success Delete Cafe[$cafeId]'s CafeMenu List") + return ApplicationResponse + .success("Success Delete Cafe[$cafeId]'s CafeMenu List") + .build() } } \ No newline at end of file