diff --git a/src/main/java/com/diareat/diareat/food/controller/FoodController.java b/src/main/java/com/diareat/diareat/food/controller/FoodController.java index 293eb3e..7f60221 100644 --- a/src/main/java/com/diareat/diareat/food/controller/FoodController.java +++ b/src/main/java/com/diareat/diareat/food/controller/FoodController.java @@ -49,8 +49,8 @@ public ApiResponse updateFood(UpdateFoodDto updateFoodDto){ //음식 삭제 @Operation(summary = "[음식] 음식 정보 삭제",description = "음식에 대한 정보를 삭제합니다.") @DeleteMapping("/{foodId}/delete") - public ApiResponse deleteFood(@PathVariable Long foodId){ - foodService.deleteFood(foodId); + public ApiResponse deleteFood(@PathVariable Long foodId, @RequestHeader Long userId){ + foodService.deleteFood(foodId, userId); return ApiResponse.success(null, ResponseCode.FOOD_DELETE_SUCCESS.getMessage()); } @@ -79,8 +79,8 @@ public ApiResponse updateFavoriteFood(UpdateFavoriteFoodDto updateFavorite //즐겨찾기 음식 해제 @Operation(summary = "[즐겨찾기] 즐겨찾기 해제",description = "유저의 즐겨찾기에 등록된 음식을 해제합니다.") @DeleteMapping("/favorite/{favoriteFoodId}") - public ApiResponse deleteFavoriteFood(@PathVariable Long favoriteFoodId){ - foodService.deleteFavoriteFood(favoriteFoodId); + public ApiResponse deleteFavoriteFood(@PathVariable Long favoriteFoodId, @RequestHeader Long userId){ + foodService.deleteFavoriteFood(favoriteFoodId, userId); return ApiResponse.success(null, ResponseCode.FOOD_FAVORITE_DELETE_SUCCESS.getMessage()); } diff --git a/src/main/java/com/diareat/diareat/food/dto/CreateFoodDto.java b/src/main/java/com/diareat/diareat/food/dto/CreateFoodDto.java index 1b4a7df..0f07e40 100644 --- a/src/main/java/com/diareat/diareat/food/dto/CreateFoodDto.java +++ b/src/main/java/com/diareat/diareat/food/dto/CreateFoodDto.java @@ -5,6 +5,8 @@ import lombok.Getter; import lombok.NoArgsConstructor; +import java.time.LocalDate; + @Getter @NoArgsConstructor @AllArgsConstructor @@ -13,8 +15,9 @@ public class CreateFoodDto { private Long userId; private String name; private BaseNutrition baseNutrition; + private LocalDate date; - public static CreateFoodDto of(Long userId, String name, BaseNutrition baseNutrition) { - return new CreateFoodDto(userId, name, baseNutrition); + public static CreateFoodDto of(Long userId, String name, BaseNutrition baseNutrition, LocalDate date) { + return new CreateFoodDto(userId, name, baseNutrition, date); } } diff --git a/src/main/java/com/diareat/diareat/food/dto/UpdateFavoriteFoodDto.java b/src/main/java/com/diareat/diareat/food/dto/UpdateFavoriteFoodDto.java index 705591e..df7ecbf 100644 --- a/src/main/java/com/diareat/diareat/food/dto/UpdateFavoriteFoodDto.java +++ b/src/main/java/com/diareat/diareat/food/dto/UpdateFavoriteFoodDto.java @@ -11,10 +11,11 @@ public class UpdateFavoriteFoodDto { private Long favoriteFoodId; + private Long userId; private String name; private BaseNutrition baseNutrition; - public static UpdateFavoriteFoodDto of(Long favoriteFoodId, String name, BaseNutrition baseNutrition) { - return new UpdateFavoriteFoodDto(favoriteFoodId, name, baseNutrition); + public static UpdateFavoriteFoodDto of(Long favoriteFoodId, Long userId, String name, BaseNutrition baseNutrition) { + return new UpdateFavoriteFoodDto(favoriteFoodId, userId, name, baseNutrition); } } diff --git a/src/main/java/com/diareat/diareat/food/dto/UpdateFoodDto.java b/src/main/java/com/diareat/diareat/food/dto/UpdateFoodDto.java index 7471e85..55b2dac 100644 --- a/src/main/java/com/diareat/diareat/food/dto/UpdateFoodDto.java +++ b/src/main/java/com/diareat/diareat/food/dto/UpdateFoodDto.java @@ -11,10 +11,11 @@ public class UpdateFoodDto { private Long foodId; + private Long userId; private String name; private BaseNutrition baseNutrition; - public static UpdateFoodDto of(Long foodId, String name, BaseNutrition baseNutrition) { - return new UpdateFoodDto(foodId, name, baseNutrition); + public static UpdateFoodDto of(Long foodId, Long userId, String name, BaseNutrition baseNutrition) { + return new UpdateFoodDto(foodId, userId, name, baseNutrition); } } diff --git a/src/main/java/com/diareat/diareat/food/repository/FavoriteFoodRepository.java b/src/main/java/com/diareat/diareat/food/repository/FavoriteFoodRepository.java index 1bd1248..fad8f7c 100644 --- a/src/main/java/com/diareat/diareat/food/repository/FavoriteFoodRepository.java +++ b/src/main/java/com/diareat/diareat/food/repository/FavoriteFoodRepository.java @@ -7,5 +7,6 @@ public interface FavoriteFoodRepository extends JpaRepository { List findAllByUserId(Long userId); + boolean existsByIdAndUserId(Long id, Long userId); // 유저가 즐겨찾기에 추가한 음식인지 확인 boolean existsByFoodId(Long foodId); // 이미 즐겨찾기에 추가된 음식인지 확인하기 위함 } diff --git a/src/main/java/com/diareat/diareat/food/repository/FoodRepository.java b/src/main/java/com/diareat/diareat/food/repository/FoodRepository.java index 7625379..b206e45 100644 --- a/src/main/java/com/diareat/diareat/food/repository/FoodRepository.java +++ b/src/main/java/com/diareat/diareat/food/repository/FoodRepository.java @@ -7,6 +7,7 @@ import java.util.List; public interface FoodRepository extends JpaRepository { + boolean existsByIdAndUserId(Long id, Long userId); // 유저가 먹은 음식인지 확인 List findAllByUserIdAndDate(Long userId, LocalDate date); //유저가 특정 날짜에 먹은 음식 반환 List findAllByUserIdAndDateBetween(Long userId, LocalDate startDate, LocalDate endDate); // 유저가 특정 기간 내에 먹은 음식 반환 } diff --git a/src/main/java/com/diareat/diareat/food/service/FoodService.java b/src/main/java/com/diareat/diareat/food/service/FoodService.java index ea55b59..281c627 100644 --- a/src/main/java/com/diareat/diareat/food/service/FoodService.java +++ b/src/main/java/com/diareat/diareat/food/service/FoodService.java @@ -15,8 +15,10 @@ import com.diareat.diareat.util.exception.FoodException; import com.diareat.diareat.util.exception.UserException; import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CacheEvict; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.cache.annotation.Cacheable; import java.time.DayOfWeek; import java.time.LocalDate; @@ -33,6 +35,7 @@ public class FoodService { private final UserRepository userRepository; // 촬영 후, 음식 정보 저장 + @CacheEvict(value = "ResponseFoodDto", key = "#createFoodDto.getUserId()+#createFoodDto.getDate()", cacheManager = "diareatCacheManager") @Transactional public Long saveFood(CreateFoodDto createFoodDto) { User user = getUserById(createFoodDto.getUserId()); @@ -40,7 +43,8 @@ public Long saveFood(CreateFoodDto createFoodDto) { return foodRepository.save(food).getId(); } - // 회원이 특정 날짜에 먹은 음식 반환 + // 회원이 특정 날짜에 먹은 음식 조회 + @Cacheable(value = "ResponseFoodDto", key = "#userId+#date", cacheManager = "diareatCacheManager") @Transactional(readOnly = true) public List getFoodListByDate(Long userId, LocalDate date){ validateUser(userId); @@ -49,22 +53,25 @@ public List getFoodListByDate(Long userId, LocalDate date){ .map(food -> ResponseFoodDto.of(food.getId(), food.getUser().getId(), food.getName(), food.getDate(), food.getTime(), food.getBaseNutrition(), food.isFavorite())).collect(Collectors.toList()); } - // 음식 정보 수정 + @CacheEvict(value = "ResponseFoodDto", key = "#updateFoodDto.getUserId()", cacheManager = "diareatCacheManager") @Transactional public void updateFood(UpdateFoodDto updateFoodDto) { Food food = getFoodById(updateFoodDto.getFoodId()); food.updateFood(updateFoodDto.getName(), updateFoodDto.getBaseNutrition()); + foodRepository.save(food); } // 음식 삭제 + @CacheEvict(value = "ResponseFoodDto", key = "#userId", cacheManager = "diareatCacheManager") @Transactional - public void deleteFood(Long foodId) { - validateFood(foodId); + public void deleteFood(Long foodId, Long userId) { + validateFood(foodId, userId); foodRepository.deleteById(foodId); } // 즐겨찾기에 음식 저장 + @CacheEvict(value = "ResponseFavoriteFoodDto", key = "#createFavoriteFoodDto.getUserId()", cacheManager = "diareatCacheManager") @Transactional public Long saveFavoriteFood(CreateFavoriteFoodDto createFavoriteFoodDto) { User user = getUserById(createFavoriteFoodDto.getUserId()); @@ -75,6 +82,7 @@ public Long saveFavoriteFood(CreateFavoriteFoodDto createFavoriteFoodDto) { } //즐겨찾기 음식 리스트 반환 + @Cacheable(value = "ResponseFavoriteFoodDto", key = "#userId", cacheManager = "diareatCacheManager") @Transactional(readOnly = true) public List getFavoriteFoodList(Long userId){ validateUser(userId); @@ -85,19 +93,23 @@ public List getFavoriteFoodList(Long userId){ } // 즐겨찾기 음식 수정 + @CacheEvict(value = "ResponseFavoriteFoodDto", key = "updateFavoriteFoodDto.getUserId()", cacheManager = "diareatCacheManager") @Transactional public void updateFavoriteFood(UpdateFavoriteFoodDto updateFavoriteFoodDto) { FavoriteFood food = getFavoriteFoodById(updateFavoriteFoodDto.getFavoriteFoodId()); food.updateFavoriteFood(updateFavoriteFoodDto.getName(), updateFavoriteFoodDto.getBaseNutrition()); + favoriteFoodRepository.save(food); } // 즐겨찾기 해제 + @CacheEvict(value = "ResponseFavoriteFoodDto", key = "#userId", cacheManager = "diareatCacheManager") @Transactional - public void deleteFavoriteFood(Long favoriteFoodId) { - validateFavoriteFood(favoriteFoodId); + public void deleteFavoriteFood(Long favoriteFoodId, Long userId) { + validateFavoriteFood(favoriteFoodId, userId); favoriteFoodRepository.deleteById(favoriteFoodId); } + @Cacheable(value = "ResponseNutritionSumByDateDto", key = "#userId+#date", cacheManager = "diareatCacheManager") @Transactional(readOnly = true) // 유저의 특정 날짜에 먹은 음식들의 영양성분별 총합 조회 (섭취영양소/기준영양소 및 비율까지 계산해서 반환, dto 구체적 협의 필요) public ResponseNutritionSumByDateDto getNutritionSumByDate(Long userId, LocalDate date) { @@ -178,6 +190,7 @@ public ResponseFoodRankDto getWorstFoodByWeek(Long userId) { // 유저의 일기 분석 그래프 데이터 및 식습관 totalScore 조회 + @Cacheable(value = "ResponseRankUserDto", key = "#userId", cacheManager = "diareatCacheManager") @Transactional(readOnly = true) // 유저의 식습관 점수를 기반으로 한 주간 랭킹 조회 public List getUserRankByWeek(Long userId) { @@ -268,14 +281,18 @@ private void validateUser(Long userId) { throw new UserException(ResponseCode.USER_NOT_FOUND); } - private void validateFood(Long foodId) { - if (!foodRepository.existsById(foodId)) + private void validateFood(Long foodId, Long userId) { + if(!foodRepository.existsById(foodId)) throw new FoodException(ResponseCode.FOOD_NOT_FOUND); + if (!foodRepository.existsByIdAndUserId(foodId, userId)) // 음식의 주인이 유저인지 아닌지 판정 + throw new FoodException(ResponseCode.NOT_FOOD_OWNER); } - private void validateFavoriteFood(Long favoriteFoodId) { - if (!favoriteFoodRepository.existsById(favoriteFoodId)) + private void validateFavoriteFood(Long favoriteFoodId, Long userId) { + if(!favoriteFoodRepository.existsById(favoriteFoodId)) throw new FavoriteException(ResponseCode.FAVORITE_NOT_FOUND); + if(!favoriteFoodRepository.existsByIdAndUserId(favoriteFoodId, userId)) // 즐겨찾는 음식의 주인이 유저인지 아닌지 판정 + throw new FavoriteException(ResponseCode.NOT_FOOD_OWNER); } // 1주일동안 먹은 음식들의 영양성분 총합을 요일을 Key로 한 Map을 통해 반환 diff --git a/src/main/java/com/diareat/diareat/util/api/ResponseCode.java b/src/main/java/com/diareat/diareat/util/api/ResponseCode.java index 3185dd9..d80d3de 100644 --- a/src/main/java/com/diareat/diareat/util/api/ResponseCode.java +++ b/src/main/java/com/diareat/diareat/util/api/ResponseCode.java @@ -14,6 +14,7 @@ public enum ResponseCode { // 403 Forbidden FORBIDDEN(HttpStatus.FORBIDDEN, false, "권한이 없습니다."), + NOT_FOOD_OWNER(HttpStatus.FORBIDDEN, false, "음식의 주인 유저가 아닙니다."), // 404 Not Found USER_NOT_FOUND(HttpStatus.NOT_FOUND, false, "사용자를 찾을 수 없습니다."), diff --git a/src/test/java/com/diareat/diareat/service/FoodServiceTest.java b/src/test/java/com/diareat/diareat/service/FoodServiceTest.java index cf29add..b2bf4ac 100644 --- a/src/test/java/com/diareat/diareat/service/FoodServiceTest.java +++ b/src/test/java/com/diareat/diareat/service/FoodServiceTest.java @@ -57,7 +57,7 @@ void testSaveAndGetFood() { // 음식 정보 저장 및 해당 날짜 음식 리 User user = User.createUser("testUser", "testImage","testPassword", 1,180, 80,18, testBaseNutrition); user.setId(1L); - CreateFoodDto createFoodDto = CreateFoodDto.of(user.getId(), "testFood", testBaseNutrition); + CreateFoodDto createFoodDto = CreateFoodDto.of(user.getId(), "testFood", testBaseNutrition, LocalDate.now()); Food food = Food.createFood("testFood", user, testBaseNutrition); food.setId(2L); @@ -89,7 +89,7 @@ void testUpdateFood() { //when BaseNutrition testChangedBaseNutrition = BaseNutrition.createNutrition(2,3,4,5); - foodService.updateFood(UpdateFoodDto.of(food.getId(), "testChangedFood", testChangedBaseNutrition)); + foodService.updateFood(UpdateFoodDto.of(food.getId(), 1L,"testChangedFood", testChangedBaseNutrition)); assertEquals("testChangedFood", food.getName()); @@ -98,7 +98,7 @@ void testUpdateFood() { assertEquals(4,food.getBaseNutrition().getProtein()); assertEquals(5,food.getBaseNutrition().getFat()); } -// + // @Test void testDeleteFood() { //given @@ -108,9 +108,10 @@ void testDeleteFood() { food.setId(1L); given(foodRepository.existsById(food.getId())).willReturn(true); + given(foodRepository.existsByIdAndUserId(food.getId(), 1L)).willReturn(true); //when - foodService.deleteFood(food.getId()); + foodService.deleteFood(food.getId(), 1L); verify(foodRepository, times(1)).deleteById(food.getId()); } @@ -152,7 +153,7 @@ void testUpdateFavoriteFood() { //when BaseNutrition testChangedBaseNutrition = BaseNutrition.createNutrition(2,3,4,5); - foodService.updateFavoriteFood(UpdateFavoriteFoodDto.of(favoriteFood.getId(), "testChangedFood", testChangedBaseNutrition)); + foodService.updateFavoriteFood(UpdateFavoriteFoodDto.of(favoriteFood.getId(), 1L,"testChangedFood", testChangedBaseNutrition)); assertEquals("testChangedFood", favoriteFood.getName()); assertEquals(2,favoriteFood.getBaseNutrition().getKcal()); @@ -160,7 +161,7 @@ void testUpdateFavoriteFood() { assertEquals(4,favoriteFood.getBaseNutrition().getProtein()); assertEquals(5,favoriteFood.getBaseNutrition().getFat()); } -// + // @Test void testDeleteFavoriteFood() { //given @@ -170,13 +171,14 @@ void testDeleteFavoriteFood() { favoriteFood.setId(1L); given(favoriteFoodRepository.existsById(favoriteFood.getId())).willReturn(true); + given(favoriteFoodRepository.existsByIdAndUserId(favoriteFood.getId(), 1L)).willReturn(true); //when - foodService.deleteFavoriteFood(favoriteFood.getId()); + foodService.deleteFavoriteFood(favoriteFood.getId(), 1L); verify(favoriteFoodRepository, times(1)).deleteById(favoriteFood.getId()); } -// + // @Test void testNutritionSumByDate(){ //given @@ -203,7 +205,7 @@ void testNutritionSumByDate(){ assertEquals(Math.round((((double)200 / (double)80) * 100.0)*100.0)/100.0, responseNutritionSumByDateDto.getRatioProtein()); assertEquals(Math.round((((double)250 / (double)80) * 100.0)*100.0)/100.0, responseNutritionSumByDateDto.getRatioFat()); } -// + // @Test void testNutritionSumByWeek(){ //given @@ -261,7 +263,7 @@ void testNutritionSumByMonth(){ assertEquals(Math.round((((double)250 / (double)80) * 100.0)*100.0)/100.0, responseNutritionSumByDateDto.getRatioFat()); } -// + // @Test void getBest3FoodTest() { // given @@ -288,7 +290,7 @@ void getBest3FoodTest() { assertEquals("Food2", top3Foods.get(1).getName()); assertEquals("Food3", top3Foods.get(2).getName()); } -// + // @Test void getWorst3FoodsTest() { // given