From 11f2910f9f3aabfc27365f6d8d6fb9f40b093679 Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Wed, 22 Jan 2025 05:30:51 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20store=20exception=20=EA=B5=AC?= =?UTF-8?q?=EC=B2=B4=ED=99=94=20-=20#118?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cakey-api/build.gradle | 3 +- .../cakey/cake/controller/CakeController.java | 5 +- .../cakey/cake/exception/CakeErrorCode.java | 5 -- .../com/cakey/cake/service/CakeService.java | 6 +- .../cakelikes/service/CakeLikesService.java | 40 +++++++--- .../handler/GlobalExceptionHandler.java | 19 ++++- .../com/cakey/store/service/StoreService.java | 80 ++++++++++--------- .../controller/StoreLikesController.java | 5 +- .../storelikes/service/StoreLikesService.java | 27 ++++++- .../com/cakey/cake/facade/CakeFacade.java | 2 +- .../com/cakey/cake/facade/CakeRetriever.java | 2 +- .../cakelike/facade/CakeLikesFacade.java | 4 +- .../cakelike/facade/CakeLikesRetriever.java | 7 +- .../repository/CakeLikesRepository.java | 6 +- .../facade/StoreOperationTimeRetriever.java | 2 +- .../cakey/store/facade/StoreRetriever.java | 3 + 16 files changed, 142 insertions(+), 74 deletions(-) diff --git a/cakey-api/build.gradle b/cakey-api/build.gradle index ffcd62a..996061e 100644 --- a/cakey-api/build.gradle +++ b/cakey-api/build.gradle @@ -12,7 +12,8 @@ dependencies { implementation group: 'org.postgresql', name: 'postgresql', version: '42.7.3' implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-security' -// implementation 'org.springframework.boot:spring-boot-starter-data-redis:3.2.1' //redis + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:4.1.0' //feign implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5' //jwt 의존성 diff --git a/cakey-api/src/main/java/com/cakey/cake/controller/CakeController.java b/cakey-api/src/main/java/com/cakey/cake/controller/CakeController.java index bc1c57c..97d8ff3 100644 --- a/cakey-api/src/main/java/com/cakey/cake/controller/CakeController.java +++ b/cakey-api/src/main/java/com/cakey/cake/controller/CakeController.java @@ -8,13 +8,16 @@ import com.cakey.common.response.BaseResponse; import com.cakey.rescode.SuccessCode; import com.cakey.store.domain.Station; +import jakarta.validation.constraints.Min; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/v1/cake") @RequiredArgsConstructor +@Validated public class CakeController { private final CakeService cakeService; @@ -56,7 +59,7 @@ public ResponseEntity> getRankCakesByStationStore(@UserId final @GetMapping("/select/{cakeId}") public ResponseEntity> getCakeSelect( @UserId final Long userId, - @PathVariable(value = "cakeId") final long cakeId, + @PathVariable(value = "cakeId") @Min(1) final long cakeId, @RequestParam(value = "dayCategory") final DayCategory dayCategory, @RequestParam(value = "themeName") final ThemeName themeName ) { diff --git a/cakey-api/src/main/java/com/cakey/cake/exception/CakeErrorCode.java b/cakey-api/src/main/java/com/cakey/cake/exception/CakeErrorCode.java index 8484fcb..e85fc3c 100644 --- a/cakey-api/src/main/java/com/cakey/cake/exception/CakeErrorCode.java +++ b/cakey-api/src/main/java/com/cakey/cake/exception/CakeErrorCode.java @@ -24,11 +24,6 @@ public enum CakeErrorCode implements ErrorCode { - - - - - ; diff --git a/cakey-api/src/main/java/com/cakey/cake/service/CakeService.java b/cakey-api/src/main/java/com/cakey/cake/service/CakeService.java index 3366769..5e876ca 100644 --- a/cakey-api/src/main/java/com/cakey/cake/service/CakeService.java +++ b/cakey-api/src/main/java/com/cakey/cake/service/CakeService.java @@ -99,12 +99,13 @@ public CakesPopularListRes getPopularCakesByStationStore(final Long userId, } public CakeListByPopularityRes getCakeByRank(final Long userId) { + final List cakeByPopularityDtos; try { - final List cakeByPopularityDtos = cakeFacade.findCakeByRank(userId); - return new CakeListByPopularityRes(cakeByPopularityDtos); + cakeByPopularityDtos = cakeFacade.findCakeByRank(userId); } catch (NotFoundBaseException e) { throw new CakeNotFoundException(CakeErrorCode.CAKE_NOT_FOUND_ENTITY); } + return new CakeListByPopularityRes(cakeByPopularityDtos); } @@ -176,7 +177,6 @@ public CakesLatestListRes findCakesByCategoryAndTheme(final DayCategory dayCateg final boolean isLastData = cakeInfoDtos.get(lastCakeInfoDtosIndex).isLastData(); final Long nextCakeIdCursor = cakeInfoDtos.get(lastCakeInfoDtosIndex).getCakeIdCursor(); - final List cakes = cakeInfoDtos.stream() .map(cakeInfoDto -> CakeInfo.of( cakeInfoDto.getCakeId(), diff --git a/cakey-api/src/main/java/com/cakey/cakelikes/service/CakeLikesService.java b/cakey-api/src/main/java/com/cakey/cakelikes/service/CakeLikesService.java index 522021f..c2db661 100644 --- a/cakey-api/src/main/java/com/cakey/cakelikes/service/CakeLikesService.java +++ b/cakey-api/src/main/java/com/cakey/cakelikes/service/CakeLikesService.java @@ -3,12 +3,15 @@ import com.cakey.cake.domain.Cake; import com.cakey.cake.dto.CakeInfo; import com.cakey.cake.dto.CakeInfoDto; +import com.cakey.cake.exception.CakeErrorCode; +import com.cakey.cake.exception.CakeNotFoundException; import com.cakey.cake.facade.CakeFacade; import com.cakey.cakelike.domain.CakeLikes; import com.cakey.cakelike.facade.CakeLikesFacade; import com.cakey.cakelike.facade.CakeLikesRemover; import com.cakey.cakelikes.dto.CakeLikedLatestRes; import com.cakey.cakelikes.dto.CakeLikedPopularRes; +import com.cakey.common.exception.NotFoundBaseException; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -28,10 +31,13 @@ public class CakeLikesService { public CakeLikedLatestRes getLatestCakeLikedByUser(final long userId, final Long cakeIdCursor, final Integer size) { - + final List cakeInfoDtos; // 페이지네이션 조회 - final List cakeInfoDtos = cakeFacade.findLatestLikedCakesByUser(userId, cakeIdCursor, size); - + try { + cakeInfoDtos = cakeFacade.findLatestLikedCakesByUser(userId, cakeIdCursor, size); + } catch (NotFoundBaseException e) { + throw new CakeNotFoundException(CakeErrorCode.CAKE_NOT_FOUND_ENTITY); + } //마지막 데이터인지 final int lastCakeInfoDtosIndex = cakeInfoDtos.size() - 1; final boolean isLastData = cakeInfoDtos.get(lastCakeInfoDtosIndex).isLastData(); @@ -63,10 +69,14 @@ public CakeLikedPopularRes getPopularLikedCakesByUser(final long userId, final Long cakeIdCursor, final Integer cakeLikesCursor, final int size) { + final List cakeInfoDtos; // 페이지네이션 조회 - final List cakeInfoDtos = cakeFacade.findPopularLikedCakesByUser(userId, cakeIdCursor,cakeLikesCursor, size); - + try { + cakeInfoDtos = cakeFacade.findPopularLikedCakesByUser(userId, cakeIdCursor, cakeLikesCursor, size); + } catch (NotFoundBaseException e) { + throw new CakeNotFoundException(CakeErrorCode.CAKE_NOT_FOUND_ENTITY); + } //마지막 데이터인지 final int lastCakeInfoDtosIndex = cakeInfoDtos.size() - 1; final int nextLikesCursor = cakeInfoDtos.get(lastCakeInfoDtosIndex).getCakeLikeCount(); @@ -96,21 +106,29 @@ public CakeLikedPopularRes getPopularLikedCakesByUser(final long userId, @Transactional public void postCakeLike(final long cakeId, final long userId) { - Cake cake = cakeFacade.findById(cakeId); + try { + final Cake cake = cakeFacade.findById(cakeId); + } catch (NotFoundBaseException e) { + throw new CakeNotFoundException(CakeErrorCode.CAKE_NOT_FOUND_ENTITY); + } + if (!cakeLikesFacade.existsCakeLikesByCakeIdAndUserId(cakeId, userId)) { - CakeLikes cakeLikes = CakeLikes.createCakeLikes(cakeId, userId); + final CakeLikes cakeLikes = CakeLikes.createCakeLikes(cakeId, userId); cakeLikesFacade.saveCakeLikes(cakeLikes); } else { - //todo: 추후 구체적인 예외 처리 - throw new RuntimeException("Cake like already exists"); + throw new CakeNotFoundException(CakeErrorCode.CAKE_LIKES_CONFLICT); } } //케이크 좋아요 취소 @Transactional public void deleteCakeLikes(final long cakeId, final long userId) { - CakeLikes cakeLikes = cakeLikesFacade.getCakeLikesByCakeIdAndUserId(cakeId, userId); + final CakeLikes cakeLikes; + try { + cakeLikes = cakeLikesFacade.getCakeLikesByCakeIdAndUserId(cakeId, userId); + } catch (NotFoundBaseException e) { + throw new CakeNotFoundException(CakeErrorCode.CAKE_LIKES_NOT_FOUND_ENTITY); + } cakeLikesFacade.removeCakeLikes(cakeLikes); } - } diff --git a/cakey-api/src/main/java/com/cakey/exception/handler/GlobalExceptionHandler.java b/cakey-api/src/main/java/com/cakey/exception/handler/GlobalExceptionHandler.java index e8053b2..b26c50a 100644 --- a/cakey-api/src/main/java/com/cakey/exception/handler/GlobalExceptionHandler.java +++ b/cakey-api/src/main/java/com/cakey/exception/handler/GlobalExceptionHandler.java @@ -8,8 +8,8 @@ import com.cakey.user.exception.UserApiBaseException; import com.fasterxml.jackson.databind.JsonMappingException; import jakarta.persistence.EntityNotFoundException; +import jakarta.validation.ConstraintViolationException; import lombok.val; -import org.hibernate.exception.ConstraintViolationException; import org.springframework.context.MessageSourceResolvable; import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.dao.DataIntegrityViolationException; @@ -61,6 +61,21 @@ public ResponseEntity> handleMethodArgumentNotValidException(fin return ApiResponseUtil.failure(ErrorBaseCode.BAD_REQUEST_REQUEST_BODY_VALID, errorMessage); } + /** + * 400 - ConstraintViolationException + * 발생 이유 : @Validated 검증 실패 + */ + @ExceptionHandler(ConstraintViolationException.class) + public ResponseEntity> handleConstraintViolationException(final ConstraintViolationException e) { + String errorMessage = e.getConstraintViolations().stream() + .map(violation -> String.format("Field '%s': %s", + violation.getPropertyPath(), + violation.getMessage() + )) + .collect(Collectors.joining(", ")); + return ApiResponseUtil.failure(ErrorBaseCode.BAD_REQUEST_REQUEST_BODY_VALID, errorMessage); + } + /** * 400 - HandlerMethodValidationException * 발생 이유 : @Valid 검증 실패 (@Request Param, @ModelAttribute) @@ -168,7 +183,7 @@ public ResponseEntity> handleDataIntegrityViolationException(fin if (e.getCause() instanceof ConstraintViolationException constraintViolationException) { // 제약 조건 이름 추출 - String constraintName = constraintViolationException.getConstraintName().toString(); + String constraintName = constraintViolationException.getConstraintViolations().toString(); String errorMessage = String.format("제약 조건 '%s' 위반이 발생했습니다.", constraintName); // log.info(errorMessage); return ApiResponseUtil.failure(ErrorBaseCode.INTEGRITY_CONFLICT, errorMessage); diff --git a/cakey-api/src/main/java/com/cakey/store/service/StoreService.java b/cakey-api/src/main/java/com/cakey/store/service/StoreService.java index ae346f4..6447270 100644 --- a/cakey-api/src/main/java/com/cakey/store/service/StoreService.java +++ b/cakey-api/src/main/java/com/cakey/store/service/StoreService.java @@ -149,17 +149,6 @@ public List getAllStation() { .collect(Collectors.toList()); } - private int calculateNextCursor(final List storeInfoDtos) { - return storeInfoDtos.isEmpty() ? -1 : storeInfoDtos.get(storeInfoDtos.size() - 1).getStoreLikesCount(); - } - - //스토어 id들 조회 - private List getStoreIds(final List storeInfoDtos) { - return storeInfoDtos.stream() - .map(StoreInfoDto::getStoreId) - .toList(); - } - //storeInfo 생성 private List getStoreInfo(final List storeInfoDtos, final Map> imageMap) { return storeInfoDtos.stream() @@ -200,7 +189,7 @@ public StoreDetailAllDesignRes getStoreAllDesign(final long storeId, final Long // 케이크 조회 // 스토어 ID로 케이크 리스트 조회 try { - cakes = cakeFacade.findAllByStoreId(storeId); + cakes = cakeFacade.findAllByStoreId(storeId); } catch (NotFoundBaseException e) { throw new CakeNotFoundException(CakeErrorCode.CAKE_NOT_FOUND_ENTITY); } @@ -227,7 +216,7 @@ public StoreDetailAllDesignRes getStoreAllDesign(final long storeId, final Long public StoreAllSizeAndTasteRes getStoreSizeAndTaste(final long storeId) { final List sizeList; try { - sizeList = sizeFacade.findSizeAllByStoreIdAndOrderByPriceAsc(storeId); + sizeList = sizeFacade.findSizeAllByStoreIdAndOrderByPriceAsc(storeId); } catch (NotFoundBaseException e) { throw new StoreNotfoundException(StoreErrorCode.STORE_NOT_FOUND_ENTITY); } @@ -239,45 +228,64 @@ public StoreDetailInfoRes getStoreDetailInfo(final long storeId) { StoreOperationTimeDto storeOperationTimeDto; try { storeDetailInfoDto = storeFacade.findStoreDetailInfo(storeId); + } catch (NotFoundBaseException e) { + throw new StoreNotfoundException(StoreErrorCode.STORE_NOT_FOUND_ENTITY); + } + + try { storeOperationTimeDto = storeOperationTimeFacade.findStoreOperationTimeByStoreId(storeId); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm"); - return StoreDetailInfoRes.of( - storeOperationTimeDto.monOpen().format(formatter), - storeOperationTimeDto.monClose().format(formatter), - storeOperationTimeDto.tueOpen().format(formatter), - storeOperationTimeDto.tueClose().format(formatter), - storeOperationTimeDto.wedOpen().format(formatter), - storeOperationTimeDto.wedClose().format(formatter), - storeOperationTimeDto.thuOpen().format(formatter), - storeOperationTimeDto.thuClose().format(formatter), - storeOperationTimeDto.friOpen().format(formatter), - storeOperationTimeDto.friClose().format(formatter), - storeOperationTimeDto.satOpen().format(formatter), - storeOperationTimeDto.satClose().format(formatter), - storeOperationTimeDto.sunOpen().format(formatter), - storeOperationTimeDto.sunClose().format(formatter), - storeDetailInfoDto.address(), - storeDetailInfoDto.phone() - ); } catch (NotFoundBaseException e) { throw new StoreNotfoundException(STORE_OPERATION_TIME_NOT_FOUND); } + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm"); + return StoreDetailInfoRes.of( + storeOperationTimeDto.monOpen().format(formatter), + storeOperationTimeDto.monClose().format(formatter), + storeOperationTimeDto.tueOpen().format(formatter), + storeOperationTimeDto.tueClose().format(formatter), + storeOperationTimeDto.wedOpen().format(formatter), + storeOperationTimeDto.wedClose().format(formatter), + storeOperationTimeDto.thuOpen().format(formatter), + storeOperationTimeDto.thuClose().format(formatter), + storeOperationTimeDto.friOpen().format(formatter), + storeOperationTimeDto.friClose().format(formatter), + storeOperationTimeDto.satOpen().format(formatter), + storeOperationTimeDto.satClose().format(formatter), + storeOperationTimeDto.sunOpen().format(formatter), + storeOperationTimeDto.sunClose().format(formatter), + storeDetailInfoDto.address(), + storeDetailInfoDto.phone() + ); } public StoreListByPopularityRes getStoreByRank() { - final List storeByPopularityDtoList = storeFacade.findStoreListByLank(); + final List storeByPopularityDtoList; + try { + storeByPopularityDtoList = storeFacade.findStoreListByLank(); + } catch (NotFoundBaseException e) { + throw new StoreNotfoundException(StoreErrorCode.STORE_NOT_FOUND_ENTITY); + } return new StoreListByPopularityRes(storeByPopularityDtoList); } public StoreSelectedCoordinateRes getStoreSelectedCoordinate(final long storeId) { - Store store = storeFacade.findStoreById(storeId); + final Store store; + try { + store = storeFacade.findStoreById(storeId); + } catch (NotFoundBaseException e) { + throw new StoreNotfoundException(StoreErrorCode.STORE_NOT_FOUND_ENTITY); + } return StoreSelectedCoordinateRes.of(storeId, store.getLatitude(), store.getLongitude()); } //선택된 스토어 조회 public StoreSelectedRes getStoreSelected(final long storeId, final Long userId) { - final StoreSelectedDto storeSelectedDto = storeFacade.findStoreInfoById(storeId, userId); - + final StoreSelectedDto storeSelectedDto; + try { + storeSelectedDto = storeFacade.findStoreInfoById(storeId, userId); + } catch (NotFoundBaseException e) { + throw new StoreNotfoundException(StoreErrorCode.STORE_NOT_FOUND_ENTITY); + } return StoreSelectedRes.of( storeSelectedDto.storeId(), storeSelectedDto.storeName(), diff --git a/cakey-api/src/main/java/com/cakey/storelikes/controller/StoreLikesController.java b/cakey-api/src/main/java/com/cakey/storelikes/controller/StoreLikesController.java index 096dfab..914b5cb 100644 --- a/cakey-api/src/main/java/com/cakey/storelikes/controller/StoreLikesController.java +++ b/cakey-api/src/main/java/com/cakey/storelikes/controller/StoreLikesController.java @@ -6,11 +6,14 @@ import com.cakey.rescode.SuccessCode; import com.cakey.store.dto.StoreLikedCoordinateRes; import com.cakey.storelikes.service.StoreLikesService; +import jakarta.validation.constraints.Min; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @RestController +@Validated @RequestMapping("/api/v1/store/likes") @RequiredArgsConstructor public class StoreLikesController { @@ -44,7 +47,7 @@ public ResponseEntity> getPopularityStoreByUserLikes( //찜한 스토어 좌표 조회 @GetMapping("/coordinate") public ResponseEntity> getStoreLikedCoordinate( - @UserId final long userId + @UserId @Min(1) final long userId ) { return ApiResponseUtil.success( SuccessCode.OK, diff --git a/cakey-api/src/main/java/com/cakey/storelikes/service/StoreLikesService.java b/cakey-api/src/main/java/com/cakey/storelikes/service/StoreLikesService.java index 6f85171..197cb8d 100644 --- a/cakey-api/src/main/java/com/cakey/storelikes/service/StoreLikesService.java +++ b/cakey-api/src/main/java/com/cakey/storelikes/service/StoreLikesService.java @@ -1,6 +1,8 @@ package com.cakey.storelikes.service; import com.cakey.cake.dto.CakeMainImageDto; +import com.cakey.cake.exception.CakeErrorCode; +import com.cakey.cake.exception.CakeNotFoundException; import com.cakey.cake.facade.CakeFacade; import com.cakey.common.exception.NotFoundBaseException; import com.cakey.store.domain.Station; @@ -8,6 +10,8 @@ import com.cakey.store.dto.StoreCoordinatesDto; import com.cakey.store.dto.StoreInfo; import com.cakey.store.dto.StoreInfoDto; +import com.cakey.store.exception.StoreErrorCode; +import com.cakey.store.exception.StoreNotfoundException; import com.cakey.store.facade.StoreFacade; import com.cakey.storelike.facade.StoreLikeFacade; import com.cakey.storelikes.dto.StoreLatestLikedByUserRes; @@ -32,15 +36,24 @@ public StoreLatestLikedByUserRes getLatestStoreLikesByUser(final long userId, final Long storeIdCursor, final int size) { + final List storeInfoDtos ///페이지네이션으로 스토어 조회 - final List storeInfoDtos = storeFacade.findLatestStoresLikedByUser(userId, storeIdCursor, size); + try { + storeInfoDtos = storeFacade.findLatestStoresLikedByUser(userId, storeIdCursor, size); + } catch (NotFoundBaseException e) { + throw new StoreNotfoundException(StoreErrorCode.STORE_NOT_FOUND_ENTITY); + } ///조회한 store들의 id 추출 final List storeIds = getStoreIds(storeInfoDtos); ///메인 이미지 매핑 - final Map> mainImageMap = cakeFacade.getMainImageMap(storeIds); - + final Map> mainImageMap; + try { + mainImageMap = cakeFacade.getMainImageMap(storeIds); + } catch (NotFoundBaseException e) { + throw new StoreNotfoundException(StoreErrorCode.STORE_MAIN_IMAGE_NOT_FOUND); + } ///storeInfo 생성 final List storeInfos = getStoreInfo(storeInfoDtos, mainImageMap); @@ -62,6 +75,7 @@ public StorePopularityLikedByUserRes getPopularityStoreByUserLikes(final long us final Integer likesCursor, final Long storeIdCursor, final int size) { + final List storeInfoOrderByLikesDtos = storeFacade.findPopularityStoresLikedByUser(userId, likesCursor, storeIdCursor, size); ///조회한 store들의 id 추출 @@ -128,7 +142,12 @@ private List getStoreInfo(final List storeInfoDtos, fin //찜한 스토어 좌표 조회 public List getLikedStoreCoordinatesByUserId(final long userId) { - final List storeCoordinatesDtos = storeFacade.findLikedStoreCoordinatesByUserId(userId); + final List storeCoordinatesDtos; + try { + storeCoordinatesDtos = storeFacade.findLikedStoreCoordinatesByUserId(userId); + } catch (NotFoundBaseException e) { + throw new StoreNotfoundException(StoreErrorCode.STORE_NOT_FOUND_ENTITY); + } return storeCoordinatesDtos.stream() .map( storeCoordinatesDto -> StoreCoordinate.of(storeCoordinatesDto.storeId(), storeCoordinatesDto.latitude(), storeCoordinatesDto.longitude()) diff --git a/cakey-domain/src/main/java/com/cakey/cake/facade/CakeFacade.java b/cakey-domain/src/main/java/com/cakey/cake/facade/CakeFacade.java index 8c45606..a79a345 100644 --- a/cakey-domain/src/main/java/com/cakey/cake/facade/CakeFacade.java +++ b/cakey-domain/src/main/java/com/cakey/cake/facade/CakeFacade.java @@ -62,7 +62,7 @@ public List findCakeByRank(final Long userId) { return cakeRetriever.findCakesByRank(userId); } - public Cake findById(final Long cakeId) { + public Cake findById(final long cakeId) { return cakeRetriever.findById(cakeId); } //찜한 디자인(케이크) 조회(최신순) diff --git a/cakey-domain/src/main/java/com/cakey/cake/facade/CakeRetriever.java b/cakey-domain/src/main/java/com/cakey/cake/facade/CakeRetriever.java index 8dc0162..7665518 100644 --- a/cakey-domain/src/main/java/com/cakey/cake/facade/CakeRetriever.java +++ b/cakey-domain/src/main/java/com/cakey/cake/facade/CakeRetriever.java @@ -56,7 +56,7 @@ public List findCakesByRank(final Long userId) { return cakeRepository.findCakesByRank(userId); } - public Cake findById(final Long cakeId) { + public Cake findById(final long cakeId) { return cakeRepository.findById(cakeId) .orElseThrow(NotFoundBaseException::new); } diff --git a/cakey-domain/src/main/java/com/cakey/cakelike/facade/CakeLikesFacade.java b/cakey-domain/src/main/java/com/cakey/cakelike/facade/CakeLikesFacade.java index eec9fbf..3c1182d 100644 --- a/cakey-domain/src/main/java/com/cakey/cakelike/facade/CakeLikesFacade.java +++ b/cakey-domain/src/main/java/com/cakey/cakelike/facade/CakeLikesFacade.java @@ -11,7 +11,7 @@ public class CakeLikesFacade { private final CakeLikesRetriever cakeLikesRetriever; private final CakeLikesRemover cakeLikesRemover; - public boolean existsCakeLikesByCakeIdAndUserId(final Long cakeId, final Long userId) { + public boolean existsCakeLikesByCakeIdAndUserId(final long cakeId, final long userId) { return cakeLikesRetriever.existsCakeLikesByCakeIdAndUserId(cakeId, userId); } @@ -28,7 +28,7 @@ public void removeCakeLikes(CakeLikes cakeLikes) { cakeLikesRemover.removeCakeLikes(cakeLikes); } - public CakeLikes getCakeLikesByCakeIdAndUserId(final Long cakeId, final Long userId) { + public CakeLikes getCakeLikesByCakeIdAndUserId(final long cakeId, final long userId) { return cakeLikesRetriever.findCakeLikesByCakeIdAndUserId(cakeId, userId); } diff --git a/cakey-domain/src/main/java/com/cakey/cakelike/facade/CakeLikesRetriever.java b/cakey-domain/src/main/java/com/cakey/cakelike/facade/CakeLikesRetriever.java index a41cfb6..8e08fd3 100644 --- a/cakey-domain/src/main/java/com/cakey/cakelike/facade/CakeLikesRetriever.java +++ b/cakey-domain/src/main/java/com/cakey/cakelike/facade/CakeLikesRetriever.java @@ -2,6 +2,7 @@ import com.cakey.cakelike.domain.CakeLikes; import com.cakey.cakelike.repository.CakeLikesRepository; +import com.cakey.common.exception.NotFoundBaseException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; @@ -10,7 +11,7 @@ public class CakeLikesRetriever { private final CakeLikesRepository cakeLikesRepository; - public boolean existsCakeLikesByCakeIdAndUserId(Long cakeId, Long userId) { + public boolean existsCakeLikesByCakeIdAndUserId(final long cakeId, final long userId) { return cakeLikesRepository.existsByCakeIdAndUserId(cakeId, userId); } @@ -22,7 +23,7 @@ public int countByUserId(final Long userId) { return cakeLikesRepository.countByUserId(userId); } - public CakeLikes findCakeLikesByCakeIdAndUserId(final Long cakeId, final Long userId) { - return cakeLikesRepository.findByCakeIdAndUserId(cakeId, userId); + public CakeLikes findCakeLikesByCakeIdAndUserId(final long cakeId, final long userId) { + return cakeLikesRepository.findByCakeIdAndUserId(cakeId, userId).orElseThrow(NotFoundBaseException::new); } } diff --git a/cakey-domain/src/main/java/com/cakey/cakelike/repository/CakeLikesRepository.java b/cakey-domain/src/main/java/com/cakey/cakelike/repository/CakeLikesRepository.java index 38326fd..ce53e07 100644 --- a/cakey-domain/src/main/java/com/cakey/cakelike/repository/CakeLikesRepository.java +++ b/cakey-domain/src/main/java/com/cakey/cakelike/repository/CakeLikesRepository.java @@ -3,11 +3,13 @@ import com.cakey.cakelike.domain.CakeLikes; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + public interface CakeLikesRepository extends JpaRepository { - boolean existsByCakeIdAndUserId(final Long cakeId, final Long userId); + boolean existsByCakeIdAndUserId(final long cakeId, final long userId); int countByUserId(final Long userId); - CakeLikes findByCakeIdAndUserId(final Long cakeId, final Long userId); + Optional findByCakeIdAndUserId(final long cakeId, final long userId); } diff --git a/cakey-domain/src/main/java/com/cakey/operationtime/facade/StoreOperationTimeRetriever.java b/cakey-domain/src/main/java/com/cakey/operationtime/facade/StoreOperationTimeRetriever.java index e67a013..da290ef 100644 --- a/cakey-domain/src/main/java/com/cakey/operationtime/facade/StoreOperationTimeRetriever.java +++ b/cakey-domain/src/main/java/com/cakey/operationtime/facade/StoreOperationTimeRetriever.java @@ -14,7 +14,7 @@ public class StoreOperationTimeRetriever { public StoreOperationTime findStoreOperationTimeByStoreId(final Long storeId) { return storeOperationTimeRepository.findByStoreId(storeId) - .orElseThrow(() -> new NotFoundBaseException()); + .orElseThrow(NotFoundBaseException::new); } } diff --git a/cakey-domain/src/main/java/com/cakey/store/facade/StoreRetriever.java b/cakey-domain/src/main/java/com/cakey/store/facade/StoreRetriever.java index 466ddd5..9b3c613 100644 --- a/cakey-domain/src/main/java/com/cakey/store/facade/StoreRetriever.java +++ b/cakey-domain/src/main/java/com/cakey/store/facade/StoreRetriever.java @@ -82,6 +82,9 @@ public Store findById(final Long storeId) { } public List findStoreListByLank(){ + if (storeRepository.findStoresByLikeCount().isEmpty()) { + throw new NotFoundBaseException(); + } return storeRepository.findStoresByLikeCount(); } } From 435dacc1bcd0520c649c336a60167903af8c937f Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Wed, 22 Jan 2025 05:41:05 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20=EB=82=98=EB=A8=B8=EC=A7=80=20excep?= =?UTF-8?q?tion=20=EA=B5=AC=EC=B2=B4=ED=99=94=20-=20#118?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/StoreConflictBaseException.java | 2 +- .../storelikes/service/StoreLikesService.java | 37 +++++++++++++------ .../cakey/user/exception/UserErrorCode.java | 1 + .../com/cakey/user/service/UserService.java | 5 +-- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/cakey-api/src/main/java/com/cakey/store/exception/StoreConflictBaseException.java b/cakey-api/src/main/java/com/cakey/store/exception/StoreConflictBaseException.java index ed00471..69986e9 100644 --- a/cakey-api/src/main/java/com/cakey/store/exception/StoreConflictBaseException.java +++ b/cakey-api/src/main/java/com/cakey/store/exception/StoreConflictBaseException.java @@ -4,7 +4,7 @@ import org.springframework.http.HttpStatus; public class StoreConflictBaseException extends StoreApiBaseException { - protected StoreConflictBaseException(ErrorCode errorCode) { + public StoreConflictBaseException(ErrorCode errorCode) { super(errorCode); } diff --git a/cakey-api/src/main/java/com/cakey/storelikes/service/StoreLikesService.java b/cakey-api/src/main/java/com/cakey/storelikes/service/StoreLikesService.java index 197cb8d..4af8348 100644 --- a/cakey-api/src/main/java/com/cakey/storelikes/service/StoreLikesService.java +++ b/cakey-api/src/main/java/com/cakey/storelikes/service/StoreLikesService.java @@ -10,6 +10,7 @@ import com.cakey.store.dto.StoreCoordinatesDto; import com.cakey.store.dto.StoreInfo; import com.cakey.store.dto.StoreInfoDto; +import com.cakey.store.exception.StoreConflictBaseException; import com.cakey.store.exception.StoreErrorCode; import com.cakey.store.exception.StoreNotfoundException; import com.cakey.store.facade.StoreFacade; @@ -17,6 +18,7 @@ import com.cakey.storelikes.dto.StoreLatestLikedByUserRes; import com.cakey.storelikes.dto.StorePopularityLikedByUserRes; import lombok.RequiredArgsConstructor; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Service; import java.util.List; @@ -36,7 +38,7 @@ public StoreLatestLikedByUserRes getLatestStoreLikesByUser(final long userId, final Long storeIdCursor, final int size) { - final List storeInfoDtos + final List storeInfoDtos; ///페이지네이션으로 스토어 조회 try { storeInfoDtos = storeFacade.findLatestStoresLikedByUser(userId, storeIdCursor, size); @@ -75,26 +77,29 @@ public StorePopularityLikedByUserRes getPopularityStoreByUserLikes(final long us final Integer likesCursor, final Long storeIdCursor, final int size) { - - final List storeInfoOrderByLikesDtos = storeFacade.findPopularityStoresLikedByUser(userId, likesCursor, storeIdCursor, size); + final List storeInfoOrderByLikesDtos; + try { + storeInfoOrderByLikesDtos = storeFacade.findPopularityStoresLikedByUser(userId, likesCursor, storeIdCursor, size); + } catch (NotFoundBaseException e) { + throw new StoreNotfoundException(StoreErrorCode.STORE_NOT_FOUND_ENTITY); + } ///조회한 store들의 id 추출 final List storeIds = getStoreIds(storeInfoOrderByLikesDtos); ///메인 이미지 매핑 - final Map> mainImageMap = cakeFacade.getMainImageMap(storeIds); - + final Map> mainImageMap; + try { + mainImageMap = cakeFacade.getMainImageMap(storeIds); + } catch (NotFoundBaseException e) { + throw new StoreNotfoundException(StoreErrorCode.STORE_MAIN_IMAGE_NOT_FOUND); + } ///storeInfo 생성 final List storeInfos = getStoreInfo(storeInfoOrderByLikesDtos, mainImageMap); ///찜한 스토어 개수 조회 final int storeCount = storeLikeFacade.countAllLikedStoreByUserId(userId); - - if(storeInfoOrderByLikesDtos.isEmpty()) { - throw new NotFoundBaseException(); - } - ///커서 업데이트 final int lastCakeInfoDtosIndex = storeInfoOrderByLikesDtos.size() - 1; final int storeLikesCursor = storeInfoOrderByLikesDtos.get(lastCakeInfoDtosIndex).getStoreLikesCount(); @@ -156,11 +161,19 @@ public List getLikedStoreCoordinatesByUserId(final long userId) //스토어 좋아요 등록 public void postStoreLikes(final long userId, final long storeId) { - storeLikeFacade.saveStoreLikes(userId, storeId); + try { + storeLikeFacade.saveStoreLikes(userId, storeId); + } catch (DataIntegrityViolationException e) { + throw new StoreConflictBaseException(StoreErrorCode.STORE_LIKES_CONFLICT); + } } //스토어 좋아요 취소 public void deleteStoreLikes(final long userId, final long storeId) { - storeLikeFacade.deleteStoreLikes(userId, storeId); + try { + storeLikeFacade.deleteStoreLikes(userId, storeId); + } catch (NotFoundBaseException e) { + throw new StoreNotfoundException(StoreErrorCode.STORE_LIKES_NOT_FOUND_ENTITY); + } } } diff --git a/cakey-api/src/main/java/com/cakey/user/exception/UserErrorCode.java b/cakey-api/src/main/java/com/cakey/user/exception/UserErrorCode.java index d1e545e..44b180f 100644 --- a/cakey-api/src/main/java/com/cakey/user/exception/UserErrorCode.java +++ b/cakey-api/src/main/java/com/cakey/user/exception/UserErrorCode.java @@ -13,6 +13,7 @@ public enum UserErrorCode implements ErrorCode { */ USER_SOCIAL_TYPE_NOT_FOUND(HttpStatus.NOT_FOUND, 40407, "유저의 소셜타입을 찾을 수 없습니다."), USER_NOT_FOUND(HttpStatus.NOT_FOUND, 40408, "유저를 찾을 수 없습니다."), + KAKAO_LOGIN_FAILED(HttpStatus.BAD_REQUEST, 40409, "카카오 로그인에 실패하였습니다"), ; diff --git a/cakey-api/src/main/java/com/cakey/user/service/UserService.java b/cakey-api/src/main/java/com/cakey/user/service/UserService.java index df3a999..db44492 100644 --- a/cakey-api/src/main/java/com/cakey/user/service/UserService.java +++ b/cakey-api/src/main/java/com/cakey/user/service/UserService.java @@ -52,7 +52,7 @@ public LoginSuccessRes login( if (loginReq.socialType().equals(SocialType.KAKAO)) { kakaoUserInfo = kakaoSocialService.getKakaoUserInfo(authorizationCode, loginReq.redirectUri()); } else { - throw new UserBadRequestException(UserErrorCode.USER_SOCIAL_TYPE_NOT_FOUND); //todo: exception 변경 + throw new UserBadRequestException(UserErrorCode.KAKAO_LOGIN_FAILED); } //플랫폼 타입 @@ -167,8 +167,7 @@ public UserInfoRes getUserInfo(final Long userId) { try { userInfoDto = userFacade.findUserInfoById(userId); } catch (NotFoundBaseException e) { - //todo: 추후 구체적인 예외처리 - throw e; + throw new UserNotFoundException(UserErrorCode.USER_NOT_FOUND); } return UserInfoRes.from(userInfoDto); From a73713bffc17808cf937cdb883bb9fab2082d208 Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Wed, 22 Jan 2025 05:45:59 +0900 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20url=20=EB=B3=80=EA=B2=BD=20-=20#118?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/cakey/common/filter/OptionalAuthenticationFilter.java | 4 ++-- cakey-api/src/main/java/com/cakey/config/FilterConfig.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cakey-api/src/main/java/com/cakey/common/filter/OptionalAuthenticationFilter.java b/cakey-api/src/main/java/com/cakey/common/filter/OptionalAuthenticationFilter.java index 20e4924..c9192b9 100644 --- a/cakey-api/src/main/java/com/cakey/common/filter/OptionalAuthenticationFilter.java +++ b/cakey-api/src/main/java/com/cakey/common/filter/OptionalAuthenticationFilter.java @@ -28,8 +28,8 @@ public class OptionalAuthenticationFilter extends OncePerRequestFilter { //로 "/api/v1/store/likes/latest/*", "/api/v1/store/likes/popularity/*", "/api/v1/store/likes/coordinate", - "/api/v1/store/likes/cake/latest/*", - "/api/v1/store/likes/cake/popularity/*", + "/api/v1/cake/store/likes/cake/latest/*", + "/api/v1/cake/store/likes/cake/popularity/*", "/api/v1/store/likes/*", "/api/v1/cake/likes/*", "/api/v1/cake/likes/latest/*", diff --git a/cakey-api/src/main/java/com/cakey/config/FilterConfig.java b/cakey-api/src/main/java/com/cakey/config/FilterConfig.java index 6288111..566032a 100644 --- a/cakey-api/src/main/java/com/cakey/config/FilterConfig.java +++ b/cakey-api/src/main/java/com/cakey/config/FilterConfig.java @@ -48,8 +48,8 @@ public FilterRegistrationBean requiredAuthenticati "/api/v1/store/likes/latest/*", "/api/v1/store/likes/popularity/*", "/api/v1/store/likes/coordinate", - "/api/v1/store/likes/cake/latest/*", - "/api/v1/store/likes/cake/popularity/*", + "/api/v1/cake/store/likes/cake/latest/*", + "/api/v1/cake/store/likes/cake/popularity/*", "/api/v1/store/likes/*", "/api/v1/cake/likes/*", "/api/v1/cake/likes/latest/*",