Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Server] feat : 추천 레시피 관련 추가 요구사항 처리 (#50) #51

Merged
merged 16 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.sundaegukbap.banchango.ai.application;

import com.sundaegukbap.banchango.ai.dto.AiRecipeRecommendRequest;
import com.sundaegukbap.banchango.ai.dto.AiRecipeRecommendResponse;
import com.sundaegukbap.banchango.ingredient.domain.Ingredient;
import com.sundaegukbap.banchango.recipe.domain.RecipeCategory;
import jakarta.transaction.Transactional;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@Component
public class AiRecipeRecommendClient {
@Value("${api.aiBaseUrl}")
private String aiBaseUrl;
private final RestTemplate restTemplate;

public AiRecipeRecommendClient(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}

@Transactional
public List<Long> getRecommendedRecipesFromAI(RecipeCategory category, List<Ingredient> ingredientList) {
AiRecipeRecommendRequest request = AiRecipeRecommendRequest.of(ingredientList);
AiRecipeRecommendResponse response = restTemplate.postForObject(aiBaseUrl + "/recommend", request, AiRecipeRecommendResponse.class);

return response.recommended_recipes();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.sundaegukbap.banchango.ai.dto;

import com.sundaegukbap.banchango.ingredient.domain.Ingredient;

import java.util.List;
import java.util.stream.Collectors;

public record AiRecipeRecommendRequest(
List<Long> ingredients
) {
public static AiRecipeRecommendRequest of(List<Ingredient> ingredients) {
List<Long> ingredientIds = ingredients.stream()
.map(Ingredient::getId)
.collect(Collectors.toList());

return new AiRecipeRecommendRequest(ingredientIds);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.sundaegukbap.banchango.ai.dto;

import java.util.List;

public record AiRecipeRecommendResponse(
List<Long> recommended_recipes
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,23 @@
import com.sundaegukbap.banchango.recipe.repository.RecipeRepository;
import com.sundaegukbap.banchango.user.domain.User;
import com.sundaegukbap.banchango.user.repository.UserRepository;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@Transactional
@RequiredArgsConstructor
public class RecipeBookmarkService {
private final RecipeBookmarkRepository recipeBookmarkRepository;
private final UserRepository userRepository;
private final RecipeRepository recipeRepository;

@Transactional
public List<Long> getBookmarkedRecipes(Long userId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new NoSuchElementException());
Expand All @@ -37,6 +36,7 @@ public List<Long> getBookmarkedRecipes(Long userId) {
return result;
}

@Transactional
public String clickBookmark(Long userId, Long recipeId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new NoSuchElementException("no user"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public RecipeBookmarkController(RecipeBookmarkService recipeBookmarkService) {

@GetMapping("/{userId}")
@Operation(summary = "북마크한 레시피 목록 조회", description = "레시피 북마크 리스트를 조회한다.")
public ResponseEntity<List> getRecommandRecipes(@PathVariable("userId") Long userId) {
public ResponseEntity<List> getRecommendRecipes(@PathVariable("userId") Long userId) {
List<Long> response = recipeBookmarkService.getBookmarkedRecipes(userId);
return new ResponseEntity<>(response, HttpStatus.OK);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.sundaegukbap.banchango.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class AppConfig {

@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,4 @@
@Configuration
@EnableJpaAuditing
public class JpaAuditingConfig {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,20 @@
import com.sundaegukbap.banchango.container.repository.ContainerRepository;
import com.sundaegukbap.banchango.user.domain.User;
import com.sundaegukbap.banchango.user.repository.UserRepository;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.NoSuchElementException;

@Service
@RequiredArgsConstructor
public class ContainerService {
private final ContainerRepository containerRepository;
private final UserRepository userRepository;

public ContainerService(ContainerRepository containerRepository, UserRepository userRepository) {
this.containerRepository = containerRepository;
this.userRepository = userRepository;
}

@Transactional
public void createContainer(Long userId, ContainerInsertRequest request) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new NoSuchElementException("no user"));
Expand All @@ -30,6 +29,7 @@ public void createContainer(Long userId, ContainerInsertRequest request) {
containerRepository.save(container);
}

@Transactional
public List<ContainerDto> getAllContainers(Long userId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new NoSuchElementException("no user"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,28 @@

import com.sundaegukbap.banchango.container.domain.Container;
import com.sundaegukbap.banchango.container.repository.ContainerRepository;
import com.sundaegukbap.banchango.ingredient.domain.ContainerIngredient;
import com.sundaegukbap.banchango.ingredient.domain.Ingredient;
import com.sundaegukbap.banchango.ingredient.domain.RecipeRequiringIngredient;
import com.sundaegukbap.banchango.ingredient.domain.ContainerIngredient;
import com.sundaegukbap.banchango.ingredient.repository.RecipeRequiringIngredientRepository;
import com.sundaegukbap.banchango.ingredient.repository.ContainerIngredientRepository;
import com.sundaegukbap.banchango.ingredient.repository.RecipeRequiringIngredientRepository;
import com.sundaegukbap.banchango.recipe.domain.Recipe;
import com.sundaegukbap.banchango.user.domain.User;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

@Component
@AllArgsConstructor
public class IngredientMatcher {
private ContainerRepository containerRepository;
private ContainerIngredientRepository containerIngredientRepository;
private RecipeRequiringIngredientRepository recipeRequiringIngredientRepository;

public IngredientMatcher(ContainerRepository containerRepository, ContainerIngredientRepository containerIngredientRepository, RecipeRequiringIngredientRepository recipeRequiringIngredientRepository) {
this.containerRepository = containerRepository;
this.containerIngredientRepository = containerIngredientRepository;
this.recipeRequiringIngredientRepository = recipeRequiringIngredientRepository;
}

public HashMap<String,List> checkIngredientRelation(User user, Recipe recipe){
List<Ingredient> havingIngredients = getAllIngredientsWithUser(user);
List<Ingredient> requiringIngredients = getIngredientsWithRecipe(recipe);
Expand All @@ -50,16 +48,12 @@ public HashMap<String,List> checkIngredientRelation(User user, Recipe recipe){

private List<Ingredient> getAllIngredientsWithUser(User user){
List<Container> containers = containerRepository.findAllByUser(user);
List<ContainerIngredient> containerIngredientList = containerIngredientRepository.findByContainerIn(containers);
List<Ingredient> ingredients = containerIngredientList.stream()
.map(ContainerIngredient::getIngredient)
.collect(Collectors.toList());

Set<Ingredient> ingredients = new HashSet<>();
for(Container container : containers){
List<ContainerIngredient> containerIngredientList = containerIngredientRepository.findAllByContainer(container);
for(ContainerIngredient ci : containerIngredientList){
ingredients.add(ci.getIngredient());
}
}

return ingredients.stream().toList();
return ingredients;
}

private List<Ingredient> getIngredientsWithRecipe(Recipe recipe) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,67 +1,43 @@
package com.sundaegukbap.banchango.ingredient.application;

import com.sundaegukbap.banchango.container.domain.Container;
import com.sundaegukbap.banchango.container.repository.ContainerRepository;
import com.sundaegukbap.banchango.ingredient.domain.ContainerIngredient;
import com.sundaegukbap.banchango.ingredient.dto.CategoryIngredientResponse;
import com.sundaegukbap.banchango.ingredient.dto.CategoryIngredientResponses;
import com.sundaegukbap.banchango.ingredient.dto.IngredientDetailResponse;
import com.sundaegukbap.banchango.ingredient.dto.IngredientDetailResponses;
import com.sundaegukbap.banchango.ingredient.dto.dto.ContainerIngredientDto;
import com.sundaegukbap.banchango.ingredient.dto.dto.ContainerIngredientDtos;
import com.sundaegukbap.banchango.ingredient.repository.ContainerIngredientRepository;
import jakarta.transaction.Transactional;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.List;
import java.util.NoSuchElementException;

@Service
@AllArgsConstructor
public class IngredientQueryService {
private final ContainerRepository containerRepository;
private final ContainerIngredientRepository containerIngredientRepository;

public IngredientQueryService(ContainerRepository containerRepository, ContainerIngredientRepository containerIngredientRepository) {
this.containerRepository = containerRepository;
this.containerIngredientRepository = containerIngredientRepository;
}

@Transactional
public ContainerIngredientDtos getUserIngredients(Long userId) {
List<Container> containerList = containerRepository.findAllByUserId(userId);
List<ContainerIngredient> containerIngredientList = containerIngredientRepository.findByContainerIn(containerList);

return ContainerIngredientDtos.of(containerIngredientList);
}

@Transactional
public ContainerIngredientDtos getContainerIngredients(Long containerId) {
List<ContainerIngredient> containerIngredientList = containerIngredientRepository.findAllByContainerId(containerId);

return ContainerIngredientDtos.of(containerIngredientList);
}

@Transactional
public ContainerIngredientDto getIngredientInfo(Long containerIngredientId) {
ContainerIngredient containerIngredient = containerIngredientRepository.findById(containerIngredientId)
.orElseThrow(() -> new NoSuchElementException("no ingredient in container"));
return ContainerIngredientDto.of(containerIngredient);
}

public CategoryIngredientResponses getCategoryIngredientResponses(Long containerId) {
List<ContainerIngredient> containerIngredients = containerIngredientRepository.findAllByContainerId(containerId);

Map<String, List<ContainerIngredient>> kindIngredientsMap = containerIngredients.stream()
.collect(Collectors.groupingBy(userHavingIngredient -> userHavingIngredient.getIngredient().getKind()));

List<CategoryIngredientResponse> categoryIngredientResponseList = new ArrayList<>();
kindIngredientsMap.forEach((kind, userHavingIngredientsList) -> {
List<IngredientDetailResponse> ingredientDetailResponseList = userHavingIngredientsList.stream()
.map(IngredientDetailResponse::of)
.collect(Collectors.toList());

IngredientDetailResponses ingredientDetailResponses = IngredientDetailResponses.of(ingredientDetailResponseList);

categoryIngredientResponseList.add(CategoryIngredientResponse.of(kind, ingredientDetailResponses));
});

return CategoryIngredientResponses.of(categoryIngredientResponseList);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,28 @@

import com.sundaegukbap.banchango.container.domain.Container;
import com.sundaegukbap.banchango.container.repository.ContainerRepository;
import com.sundaegukbap.banchango.ingredient.domain.Ingredient;
import com.sundaegukbap.banchango.ingredient.domain.ContainerIngredient;
import com.sundaegukbap.banchango.ingredient.domain.Ingredient;
import com.sundaegukbap.banchango.ingredient.dto.IngredientInsertRequest;
import com.sundaegukbap.banchango.ingredient.repository.IngredientRepository;
import com.sundaegukbap.banchango.ingredient.repository.ContainerIngredientRepository;
import com.sundaegukbap.banchango.user.repository.UserRepository;
import com.sundaegukbap.banchango.ingredient.repository.IngredientRepository;
import com.sundaegukbap.banchango.ingredient.dto.event.IngredientChangedEvent;
import jakarta.transaction.Transactional;
import lombok.AllArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

import java.util.NoSuchElementException;

@Service
@AllArgsConstructor
public class IngredientService {
private final ContainerIngredientRepository containerIngredientRepository;
private final UserRepository userRepository;
private final IngredientRepository ingredientRepository;
private final ContainerRepository containerRepository;
private final ApplicationEventPublisher applicationEventPublisher;

public IngredientService(ContainerIngredientRepository containerIngredientRepository, UserRepository userRepository, IngredientRepository ingredientRepository, ContainerRepository containerRepository) {
this.containerIngredientRepository = containerIngredientRepository;
this.userRepository = userRepository;
this.ingredientRepository = ingredientRepository;
this.containerRepository = containerRepository;
}

@Transactional
public void insertIngredient(Long userId, IngredientInsertRequest request) {
Container container = containerRepository.findById(request.containerId())
.orElseThrow(() -> new NoSuchElementException("no container"));
Expand All @@ -34,12 +32,17 @@ public void insertIngredient(Long userId, IngredientInsertRequest request) {

ContainerIngredient containerIngredient = request.toEntity(container, ingredient);
containerIngredientRepository.save(containerIngredient);

applicationEventPublisher.publishEvent(new IngredientChangedEvent(userId));
}

public void removeIngredient(Long containerIngredientId) {
@Transactional
public void removeIngredient(Long userId, Long containerIngredientId) {
ContainerIngredient containerIngredient = containerIngredientRepository.findById(containerIngredientId)
.orElseThrow(() -> new NoSuchElementException("no ingredient in container"));

containerIngredientRepository.delete(containerIngredient);

applicationEventPublisher.publishEvent(new IngredientChangedEvent(userId));
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.sundaegukbap.banchango.ingredient.domain;

import jakarta.persistence.*;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

Expand All @@ -24,4 +27,7 @@ public class Ingredient {
private String kind;
private String image;

public Ingredient(Long id) {
this.id = id;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.sundaegukbap.banchango.ingredient.dto.event;

public record IngredientChangedEvent(
Long userId
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public ResponseEntity<String> insertIngredient(@PathVariable("userId") Long user
@DeleteMapping("/{containerIngredientId}")
@Operation(summary = "소유 재료 제거", description = "소유한 재료를 제거한다.")
public ResponseEntity<String> removeIngredient(@PathVariable("containerIngredientId") Long containerIngredientId) {
ingredientService.removeIngredient(containerIngredientId);
ingredientService.removeIngredient(1L,containerIngredientId);
return new ResponseEntity<>("success remove ingredient", HttpStatus.OK);
}

Expand Down
Loading