diff --git a/src/main/java/com/diareat/diareat/food/domain/Food.java b/src/main/java/com/diareat/diareat/food/domain/Food.java index 7b98ef5..851c5e5 100644 --- a/src/main/java/com/diareat/diareat/food/domain/Food.java +++ b/src/main/java/com/diareat/diareat/food/domain/Food.java @@ -30,7 +30,6 @@ public class Food { @JoinColumn(name = "favorite_food_id") private FavoriteFood favoriteFood; - @CreatedDate private LocalDate date; private LocalTime time; @@ -42,6 +41,7 @@ public static Food createFood(String name, User user, BaseNutrition baseNutritio Food food = new Food(); food.name = name; food.user = user; + food.date = LocalDate.now(); food.time = LocalTime.now(); food.baseNutrition = baseNutrition; return food; diff --git a/src/main/java/com/diareat/diareat/food/dto/ResponseFoodRankDto.java b/src/main/java/com/diareat/diareat/food/dto/ResponseFoodRankDto.java new file mode 100644 index 0000000..03d74b8 --- /dev/null +++ b/src/main/java/com/diareat/diareat/food/dto/ResponseFoodRankDto.java @@ -0,0 +1,24 @@ +package com.diareat.diareat.food.dto; + +import com.diareat.diareat.food.domain.Food; +import com.diareat.diareat.user.domain.BaseNutrition; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.List; + +@Getter +@AllArgsConstructor +public class ResponseFoodRankDto { + + private Long userId; + private List rankFoodList; + private LocalDate startDate; //해당 날짜로부터 7일전까지 + private boolean isBest; //isBest = true 이면 Best 3, false 이면 Worst 3 + + public static ResponseFoodRankDto of(Long userId, List rankFoodList, LocalDate startDate, boolean isBest) { + return new ResponseFoodRankDto(userId, rankFoodList, startDate, isBest); + } +} diff --git a/src/main/java/com/diareat/diareat/food/dto/ResponseNutritionSumByDateDto.java b/src/main/java/com/diareat/diareat/food/dto/ResponseNutritionSumByDateDto.java index 5eb8e4c..1520eb4 100644 --- a/src/main/java/com/diareat/diareat/food/dto/ResponseNutritionSumByDateDto.java +++ b/src/main/java/com/diareat/diareat/food/dto/ResponseNutritionSumByDateDto.java @@ -3,9 +3,16 @@ import lombok.AllArgsConstructor; import lombok.Getter; +import java.time.LocalDate; + @Getter @AllArgsConstructor public class ResponseNutritionSumByDateDto { + + Long userId; + LocalDate checkDate; //조회한 날짜 + int nutritionSumType; //조회할 기간을 나타내는 코드. {1: 특정 날짜, 7: 최근 7일간, 30: 최근 한달간} + int totalKcal; int totalCarbohydrate; int totalProtein; @@ -16,7 +23,7 @@ public class ResponseNutritionSumByDateDto { double ratioProtein; double ratioFat; - public static ResponseNutritionSumByDateDto of (int totalKcal, int totalCarbohydrate, int totalProtein, int totalFat, double ratioKcal, double ratioCarbohydrate, double ratioProtein, double ratioFat){ - return new ResponseNutritionSumByDateDto(totalKcal, totalCarbohydrate, totalProtein, totalFat, ratioKcal, ratioCarbohydrate, ratioProtein, ratioFat); + public static ResponseNutritionSumByDateDto of (Long userId, LocalDate checkDate, int nutritionSumType, int totalKcal, int totalCarbohydrate, int totalProtein, int totalFat, double ratioKcal, double ratioCarbohydrate, double ratioProtein, double ratioFat){ + return new ResponseNutritionSumByDateDto(userId, checkDate, nutritionSumType, totalKcal, totalCarbohydrate, totalProtein, totalFat, ratioKcal, ratioCarbohydrate, ratioProtein, ratioFat); } } 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 4c4ef98..5cd6d90 100644 --- a/src/main/java/com/diareat/diareat/food/repository/FoodRepository.java +++ b/src/main/java/com/diareat/diareat/food/repository/FoodRepository.java @@ -8,4 +8,5 @@ public interface FoodRepository extends JpaRepository { 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 f2db24e..2d7c637 100644 --- a/src/main/java/com/diareat/diareat/food/service/FoodService.java +++ b/src/main/java/com/diareat/diareat/food/service/FoodService.java @@ -15,7 +15,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.rmi.registry.LocateRegistry; import java.time.LocalDate; +import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; @@ -94,50 +96,67 @@ public void deleteFavoriteFood(Long favoriteFoodId) { // 유저의 특정 날짜에 먹은 음식들의 영양성분별 총합 조회 (섭취영양소/기준영양소 및 비율까지 계산해서 반환, dto 구체적 협의 필요) public ResponseNutritionSumByDateDto getNutritionSumByDate(Long userId, LocalDate date) { List foodList = foodRepository.findAllByUserIdAndDate(userId, date); - User targetUser = getUserById(userId); - int totalKcal = 0; - int totalCarbohydrate = 0; - int totalProtein = 0; - int totalFat = 0; - - for (Food food : foodList) { - BaseNutrition targetFoodNutrition = food.getBaseNutrition(); - totalKcal += targetFoodNutrition.getKcal(); - totalCarbohydrate += targetFoodNutrition.getCarbohydrate(); - totalProtein += targetFoodNutrition.getProtein(); - totalFat += targetFoodNutrition.getFat(); - } - - double ratioKcal = Math.round((totalKcal*1.0)/(targetUser.getBaseNutrition().getKcal()*1.0))*10.0; - double ratioCarbohydrate = Math.round((totalCarbohydrate*1.0)/(targetUser.getBaseNutrition().getCarbohydrate()*1.0))*10.0; - double ratioProtein = Math.round((totalProtein*1.0)/(targetUser.getBaseNutrition().getProtein()*1.0))*10.0; - double ratioFat = Math.round((totalFat*1.0)/(targetUser.getBaseNutrition().getFat()*1.0))*10.0; - - return ResponseNutritionSumByDateDto.of(totalKcal,totalCarbohydrate, totalProtein, totalFat, ratioKcal, ratioCarbohydrate, ratioProtein, ratioFat); + return calculateNutritionSumAndRatio(userId, foodList, date, 1); } - @Transactional + @Transactional(readOnly = true) // 유저의 최근 7일간의 영양성분별 총합 조회 (섭취영양소/기준영양소 및 비율까지 계산해서 반환, dto 구체적 협의 필요) - public void getNutritionSumByWeek(Long userId) { + public ResponseNutritionSumByDateDto getNutritionSumByWeek(Long userId) { + LocalDate endDate = LocalDate.now(); + List foodList = foodRepository.findAllByUserIdAndDateBetween(userId, endDate.minusWeeks(1), endDate); + return calculateNutritionSumAndRatio(userId, foodList, endDate, 7); } - @Transactional + @Transactional(readOnly = true) // 유저의 최근 1개월간의 영양성분별 총합 조회 (섭취영양소/기준영양소 및 비율까지 계산해서 반환, dto 구체적 협의 필요) - public void getNutritionSumByMonth(Long userId) { + public ResponseNutritionSumByDateDto getNutritionSumByMonth(Long userId) { + LocalDate endDate = LocalDate.now(); + List foodList = foodRepository.findAllByUserIdAndDateBetween(userId, endDate.minusWeeks(1), endDate); + return calculateNutritionSumAndRatio(userId, foodList, endDate, 30); } - @Transactional + @Transactional(readOnly = true) // 유저의 최근 7일간의 Best 3 음식 조회 (dto 구체적 협의 필요) - public void getBestFoodByWeek(Long userId) { + public ResponseFoodRankDto getBestFoodByWeek(Long userId, LocalDate endDate) { + List foodList = foodRepository.findAllByUserIdAndDateBetween(userId, endDate.minusWeeks(1), endDate); + + List top3Foods = foodList.stream() + .sorted(Comparator.comparingDouble((Food food) -> + 0.7 * food.getBaseNutrition().getProtein()- 0.3 * food.getBaseNutrition().getFat()).reversed()) + .limit(3) + .collect(Collectors.toList()); //고단백 저지방일수록 점수를 높게 측정되도록 기준을 잡은 후, 그 기준을 기반으로 정렬 + //사용한 기준은, 고단백과 저지방의 점수 반영 비율을 7:3으로 측정하고, 단백질량이 높을 수록, 지방량이 낮을 수록 점수가 높음. 이후, 내림차순 정렬 + // ** Best 3 기준 논의 필요 ** + + List top3FoodsDtoList = top3Foods.stream() + .map(food -> ResponseFoodDto.of(food.getId(), food.getUser().getId(), food.getName(), food.getDate(), food.getTime(), food.getBaseNutrition(), food.isFavorite())).collect(Collectors.toList()); + return ResponseFoodRankDto.of(userId, top3FoodsDtoList, endDate, true); } - @Transactional + @Transactional(readOnly = true) // 유저의 최근 7일간의 Worst 3 음식 조회 (dto 구체적 협의 필요) - public void getWorstFoodByWeek(Long userId) { + public ResponseFoodRankDto getWorstFoodByWeek(Long userId, LocalDate endDate) { + + List foodList = foodRepository.findAllByUserIdAndDateBetween(userId, endDate.minusWeeks(1), endDate); + + List worst3Foods = foodList.stream() + .sorted(Comparator.comparingDouble((Food food) -> + 0.7 * food.getBaseNutrition().getFat() + 0.3 * food.getBaseNutrition().getCarbohydrate()).reversed()) + .limit(3) + .collect(Collectors.toList()); + //반대로 고지방 고탄수의 경우를 7:3으로 측정하고, 지방이 높을 수록 점수가 급격히 높아짐. 이 경우는 점수가 높은 것이 안좋음. + //(수정) https://blog.nongshim.com/1961, 탄수화물이 더 영향을 미친다고 하는데...흠... + // ** 이점은 논의가 필요할 듯? ** + // 우선 임시로 지방 비율을 높게 설정 + + List worst3FoodDtoList = worst3Foods.stream() + .map(food -> ResponseFoodDto.of(food.getId(), food.getUser().getId(), food.getName(), food.getDate(), food.getTime(), food.getBaseNutrition(), food.isFavorite())).collect(Collectors.toList()); + + return ResponseFoodRankDto.of(userId, worst3FoodDtoList, endDate, false); } private User getUserById(Long userId){ @@ -155,6 +174,29 @@ private FavoriteFood getFavoriteFoodById(Long foodId){ .orElseThrow(() -> new FoodException(ResponseCode.FOOD_NOT_FOUND)); } + private ResponseNutritionSumByDateDto calculateNutritionSumAndRatio(Long userId, List foodList, LocalDate checkDate, int nutritionSumType){ + User targetUser = getUserById(userId); + int totalKcal = 0; + int totalCarbohydrate = 0; + int totalProtein = 0; + int totalFat = 0; + + for (Food food : foodList) { + BaseNutrition targetFoodNutrition = food.getBaseNutrition(); + totalKcal += targetFoodNutrition.getKcal(); + totalCarbohydrate += targetFoodNutrition.getCarbohydrate(); + totalProtein += targetFoodNutrition.getProtein(); + totalFat += targetFoodNutrition.getFat(); + } + + double ratioKcal = Math.round((((double) totalKcal /(double) targetUser.getBaseNutrition().getKcal())*100.0)*10.0)/10.0; + double ratioCarbohydrate = Math.round((((double) totalCarbohydrate /(double) targetUser.getBaseNutrition().getCarbohydrate())*100.0)*10.0)/10.0; + double ratioProtein = Math.round((((double) totalProtein /(double) targetUser.getBaseNutrition().getProtein())*100.0)*10.0)/10.0; + double ratioFat =Math.round((((double) totalFat /(double) targetUser.getBaseNutrition().getFat())*100.0)*10.0)/10.0; + + return ResponseNutritionSumByDateDto.of(userId, checkDate, nutritionSumType, totalKcal,totalCarbohydrate, totalProtein, totalFat, ratioKcal, ratioCarbohydrate, ratioProtein, ratioFat); + } + /** * 메서드 구현 유의사항 diff --git a/src/test/java/com/diareat/diareat/service/FoodServiceTest.java b/src/test/java/com/diareat/diareat/service/FoodServiceTest.java index b633575..904899c 100644 --- a/src/test/java/com/diareat/diareat/service/FoodServiceTest.java +++ b/src/test/java/com/diareat/diareat/service/FoodServiceTest.java @@ -7,6 +7,7 @@ import com.diareat.diareat.food.repository.FoodRepository; import com.diareat.diareat.food.service.FoodService; import com.diareat.diareat.user.domain.BaseNutrition; +import com.diareat.diareat.user.domain.User; import com.diareat.diareat.user.dto.CreateUserDto; import com.diareat.diareat.user.repository.UserRepository; import com.diareat.diareat.user.service.UserService; @@ -17,6 +18,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.Optional; import static org.junit.jupiter.api.Assertions.*; @@ -153,24 +155,76 @@ void testDeleteFavoriteFood() { @Test void testNutritionSumByDate(){ //given - BaseNutrition testFoodNutrition = BaseNutrition.createNutrition(100,150,200,250); + BaseNutrition testFoodNutrition = BaseNutrition.createNutrition(1400,150,200,250); Long userId = userService.saveUser(CreateUserDto.of("testUser", "testPassword",1, 180, 80, 18)); Long foodId = foodService.saveFood(CreateFoodDto.of(userId,"testFood", testFoodNutrition)); Food food = foodRepository.getReferenceById(foodId); //when ResponseNutritionSumByDateDto responseNutritionSumByDateDto = foodService.getNutritionSumByDate(userId,food.getDate()); - - assertNotNull(responseNutritionSumByDateDto); - assertEquals(100, responseNutritionSumByDateDto.getTotalKcal()); + assertEquals(1400, responseNutritionSumByDateDto.getTotalKcal()); assertEquals(150, responseNutritionSumByDateDto.getTotalCarbohydrate()); assertEquals(200, responseNutritionSumByDateDto.getTotalProtein()); assertEquals(250, responseNutritionSumByDateDto.getTotalFat()); - assertEquals(Math.round((100*1.0)/(2000*1.0))*10.0, responseNutritionSumByDateDto.getRatioKcal()); - assertEquals(Math.round((150*1.0)/(300*1.0))*10.0, responseNutritionSumByDateDto.getRatioCarbohydrate()); - assertEquals(Math.round((200*1.0)/(80*1.0))*10.0, responseNutritionSumByDateDto.getRatioProtein()); - assertEquals(Math.round((250*1.0)/(80*1.0))*10.0, responseNutritionSumByDateDto.getRatioFat()); + assertEquals(Math.round((((double)1400 / (double)2000) * 100.0)*100.0)/100.0, responseNutritionSumByDateDto.getRatioKcal()); + assertEquals(Math.round((((double)150 / (double)300) * 100.0)*100.0)/100.0, responseNutritionSumByDateDto.getRatioCarbohydrate()); + 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 testNutritionSumByWeekAndMonth(){ + //given + BaseNutrition testFoodNutrition = BaseNutrition.createNutrition(100,150,200,250); + Long userId = userService.saveUser(CreateUserDto.of("testUser", "testPassword",1, 180, 80, 18)); + Long foodId = foodService.saveFood(CreateFoodDto.of(userId,"testFood", testFoodNutrition)); + + } + + @Test + void getBest3FoodTest() { + // given + Long userId = userService.saveUser(CreateUserDto.of("testUser", "testPassword", 1, 180, 80, 18)); + foodService.saveFood(CreateFoodDto.of(userId, "Food1", BaseNutrition.createNutrition(100, 100 ,10, 1))); + foodService.saveFood(CreateFoodDto.of(userId, "Food2", BaseNutrition.createNutrition(100, 100 ,8, 2))); + foodService.saveFood(CreateFoodDto.of(userId, "Food3", BaseNutrition.createNutrition(100, 100 ,6, 3))); + foodService.saveFood(CreateFoodDto.of(userId, "Food4", BaseNutrition.createNutrition(100, 100 ,4, 4))); + Long foodId = foodService.saveFood(CreateFoodDto.of(userId, "Food5", BaseNutrition.createNutrition(100, 100 ,2, 5))); + + Food testFood = foodRepository.getReferenceById(foodId); + + // when + ResponseFoodRankDto response = foodService.getBestFoodByWeek(userId, testFood.getDate()); + List top3Foods = response.getRankFoodList(); + + // then + assertEquals(3, top3Foods.size()); + assertEquals("Food1", top3Foods.get(0).getName()); + assertEquals("Food2", top3Foods.get(1).getName()); + assertEquals("Food3", top3Foods.get(2).getName()); + } + + @Test + void getWorst3FoodsTest() { + // given + Long userId = userService.saveUser(CreateUserDto.of("testUser", "testPassword", 1, 180, 80, 18)); + foodService.saveFood(CreateFoodDto.of(userId, "Food1", BaseNutrition.createNutrition(100, 50 ,10, 1))); + foodService.saveFood(CreateFoodDto.of(userId, "Food2", BaseNutrition.createNutrition(100, 100 ,8, 20))); + foodService.saveFood(CreateFoodDto.of(userId, "Food3", BaseNutrition.createNutrition(100, 80 ,6, 7))); + foodService.saveFood(CreateFoodDto.of(userId, "Food4", BaseNutrition.createNutrition(100, 100 ,4, 5))); + Long foodId = foodService.saveFood(CreateFoodDto.of(userId, "Food5", BaseNutrition.createNutrition(100, 90 ,2, 6))); + + Food testFood = foodRepository.getReferenceById(foodId); + + // when + ResponseFoodRankDto response = foodService.getWorstFoodByWeek(userId, testFood.getDate()); + List top3Foods = response.getRankFoodList(); + // then + assertEquals(3, top3Foods.size()); + assertEquals("Food2", top3Foods.get(0).getName()); + assertEquals("Food4", top3Foods.get(1).getName()); + assertEquals("Food5", top3Foods.get(2).getName()); } }