diff --git a/backend/src/main/java/net/pengcook/recipe/dto/PageRecipeRequest.java b/backend/src/main/java/net/pengcook/recipe/dto/PageRecipeRequest.java index 9a180273..b50cd605 100644 --- a/backend/src/main/java/net/pengcook/recipe/dto/PageRecipeRequest.java +++ b/backend/src/main/java/net/pengcook/recipe/dto/PageRecipeRequest.java @@ -2,6 +2,9 @@ import jakarta.annotation.Nullable; import jakarta.validation.constraints.Min; +import net.pengcook.recipe.exception.InvalidParameterException; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; public record PageRecipeRequest( @Min(0) int pageNumber, @@ -10,4 +13,15 @@ public record PageRecipeRequest( @Nullable String keyword, @Nullable Long userId ) { + + public PageRecipeRequest { + long offset = (long) pageNumber * pageSize; + if (offset > Integer.MAX_VALUE) { + throw new InvalidParameterException("적절하지 않은 페이지 정보입니다."); + } + } + + public Pageable getPageable() { + return PageRequest.of(pageNumber, pageSize); + } } diff --git a/backend/src/main/java/net/pengcook/recipe/service/RecipeService.java b/backend/src/main/java/net/pengcook/recipe/service/RecipeService.java index 2c2ffeb8..bb3778bb 100644 --- a/backend/src/main/java/net/pengcook/recipe/service/RecipeService.java +++ b/backend/src/main/java/net/pengcook/recipe/service/RecipeService.java @@ -1,7 +1,6 @@ package net.pengcook.recipe.service; import java.time.LocalTime; -import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.Optional; @@ -18,19 +17,17 @@ import net.pengcook.recipe.domain.Recipe; import net.pengcook.recipe.dto.CategoryResponse; import net.pengcook.recipe.dto.IngredientResponse; -import net.pengcook.recipe.dto.RecipeHomeResponse; -import net.pengcook.recipe.dto.RecipeHomeWithMineResponse; import net.pengcook.recipe.dto.PageRecipeRequest; import net.pengcook.recipe.dto.RecipeDataResponse; import net.pengcook.recipe.dto.RecipeDescriptionResponse; +import net.pengcook.recipe.dto.RecipeHomeResponse; +import net.pengcook.recipe.dto.RecipeHomeWithMineResponse; import net.pengcook.recipe.dto.RecipeRequest; import net.pengcook.recipe.dto.RecipeResponse; -import net.pengcook.recipe.exception.InvalidParameterException; import net.pengcook.recipe.exception.UnauthorizedException; import net.pengcook.recipe.repository.RecipeRepository; import net.pengcook.user.domain.User; import net.pengcook.user.repository.UserRepository; -import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -53,7 +50,7 @@ public class RecipeService { private final RecipeLikeService recipeLikeService; public List readRecipes(UserInfo userInfo, PageRecipeRequest pageRecipeRequest) { - Pageable pageable = getValidatedPageable(pageRecipeRequest.pageNumber(), pageRecipeRequest.pageSize()); + Pageable pageable = pageRecipeRequest.getPageable(); List recipeIds = recipeRepository.findRecipeIdsByCategoryAndKeyword( pageable, pageRecipeRequest.category(), @@ -138,14 +135,6 @@ private List getCategoryResponses(List gro .collect(Collectors.toList()); } - private Pageable getValidatedPageable(int pageNumber, int pageSize) { - long offset = (long) pageNumber * pageSize; - if (offset > Integer.MAX_VALUE) { - throw new InvalidParameterException("적절하지 않은 페이지 정보입니다."); - } - return PageRequest.of(pageNumber, pageSize); - } - private void verifyUserCanDeleteRecipe(UserInfo userInfo, Recipe recipe) { if (recipe.getAuthor().getId() != userInfo.getId()) { throw new UnauthorizedException("레시피를 삭제할 수 없습니다."); diff --git a/backend/src/test/java/net/pengcook/recipe/dto/PageRecipeRequestTest.java b/backend/src/test/java/net/pengcook/recipe/dto/PageRecipeRequestTest.java new file mode 100644 index 00000000..fbd24d40 --- /dev/null +++ b/backend/src/test/java/net/pengcook/recipe/dto/PageRecipeRequestTest.java @@ -0,0 +1,20 @@ +package net.pengcook.recipe.dto; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import net.pengcook.recipe.exception.InvalidParameterException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class PageRecipeRequestTest { + + @Test + @DisplayName("요청받은 페이지 offset 값이 int 타입의 최댓값을 초과하면 예외가 발생한다.") + void readRecipesWhenPageOffsetIsGreaterThanIntMaxValue() { + int pageNumber = 1073741824; + int pageSize = 2; + + assertThatThrownBy(() -> new PageRecipeRequest(pageNumber, pageSize, null, null, null)) + .isInstanceOf(InvalidParameterException.class); + } +} diff --git a/backend/src/test/java/net/pengcook/recipe/service/RecipeServiceTest.java b/backend/src/test/java/net/pengcook/recipe/service/RecipeServiceTest.java index 72e7a2b4..5e793b84 100644 --- a/backend/src/test/java/net/pengcook/recipe/service/RecipeServiceTest.java +++ b/backend/src/test/java/net/pengcook/recipe/service/RecipeServiceTest.java @@ -8,12 +8,11 @@ import net.pengcook.authentication.domain.UserInfo; import net.pengcook.ingredient.domain.Requirement; import net.pengcook.ingredient.dto.IngredientCreateRequest; -import net.pengcook.recipe.dto.RecipeHomeWithMineResponse; import net.pengcook.recipe.dto.PageRecipeRequest; +import net.pengcook.recipe.dto.RecipeHomeWithMineResponse; import net.pengcook.recipe.dto.RecipeRequest; import net.pengcook.recipe.dto.RecipeResponse; import net.pengcook.recipe.dto.RecipeStepRequest; -import net.pengcook.recipe.exception.InvalidParameterException; import net.pengcook.recipe.exception.UnauthorizedException; import net.pengcook.recipe.repository.RecipeRepository; import org.junit.jupiter.api.DisplayName; @@ -41,7 +40,8 @@ class RecipeServiceTest { void readRecipes(int pageNumber, int pageSize, int expectedFirstRecipeId) { UserInfo userInfo = new UserInfo(1L, "loki@pengcook.net"); PageRecipeRequest pageRecipeRequest = new PageRecipeRequest(pageNumber, pageSize, null, null, null); - List recipeHomeWithMineResponses = recipeService.readRecipes(userInfo, pageRecipeRequest); + List recipeHomeWithMineResponses = recipeService.readRecipes(userInfo, + pageRecipeRequest); assertThat(recipeHomeWithMineResponses.getFirst().recipeId()).isEqualTo(expectedFirstRecipeId); } @@ -51,7 +51,8 @@ void readRecipes(int pageNumber, int pageSize, int expectedFirstRecipeId) { void readRecipesWithUserInfo() { UserInfo userInfo = new UserInfo(1L, "loki@pengcook.net"); PageRecipeRequest pageRecipeRequest = new PageRecipeRequest(0, 2, null, null, null); - List recipeHomeWithMineResponses = recipeService.readRecipes(userInfo, pageRecipeRequest); + List recipeHomeWithMineResponses = recipeService.readRecipes(userInfo, + pageRecipeRequest); assertAll( () -> assertThat(recipeHomeWithMineResponses.getFirst().mine()).isFalse(), @@ -59,18 +60,6 @@ void readRecipesWithUserInfo() { ); } - @Test - @DisplayName("요청받은 페이지 offset 값이 int 타입의 최댓값을 초과하면 예외가 발생한다.") - void readRecipesWhenPageOffsetIsGreaterThanIntMaxValue() { - int pageNumber = 1073741824; - int pageSize = 2; - UserInfo userInfo = new UserInfo(1L, "loki@pengcook.net"); - PageRecipeRequest pageRecipeRequest = new PageRecipeRequest(pageNumber, pageSize, null, null, null); - - assertThatThrownBy(() -> recipeService.readRecipes(userInfo, pageRecipeRequest)) - .isInstanceOf(InvalidParameterException.class); - } - @Test @Sql({"/data/recipe.sql", "/data/like.sql"}) @DisplayName("내가 좋아하는 모든 게시글 개요를 조회한다.")