Skip to content

Commit cc9036f

Browse files
authored
Merge pull request #149 from YAPP-Github/feat/PRODUCT-233
[Feat] 상점/응원 API 페이지네이션 추가
2 parents a670285 + 8e1d747 commit cc9036f

File tree

10 files changed

+177
-56
lines changed

10 files changed

+177
-56
lines changed

src/main/java/eatda/controller/cheer/CheerController.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,17 @@ public ResponseEntity<CheerResponse> registerCheer(@RequestPart("request") Cheer
4141
}
4242

4343
@GetMapping("/api/cheer")
44-
public ResponseEntity<CheersResponse> getCheers(@RequestParam @Min(1) @Max(50) int size) {
45-
CheersResponse response = cheerService.getCheers(size);
44+
public ResponseEntity<CheersResponse> getCheers(@RequestParam(defaultValue = "0") @Min(0) int page,
45+
@RequestParam(defaultValue = "5") @Min(1) @Max(50) int size) {
46+
CheersResponse response = cheerService.getCheers(page, size);
4647
return ResponseEntity.ok(response);
4748
}
4849

4950
@GetMapping("/api/shops/{storeId}/cheers")
5051
public ResponseEntity<CheersInStoreResponse> getCheersByStoreId(@PathVariable Long storeId,
51-
@RequestParam @Min(1) @Max(50) int size) {
52-
CheersInStoreResponse response = cheerService.getCheersByStoreId(storeId, size);
52+
@RequestParam(defaultValue = "0") @Min(0) int page,
53+
@RequestParam(defaultValue = "5") @Min(1) @Max(50) int size) {
54+
CheersInStoreResponse response = cheerService.getCheersByStoreId(storeId, page, size);
5355
return ResponseEntity.ok(response);
5456
}
5557
}

src/main/java/eatda/controller/store/StoreController.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@ public ResponseEntity<ImagesResponse> getStoreImages(@PathVariable long storeId)
2929
}
3030

3131
@GetMapping("/api/shops")
32-
public ResponseEntity<StoresResponse> getStores(@RequestParam @Min(1) @Max(50) int size,
32+
public ResponseEntity<StoresResponse> getStores(@RequestParam(defaultValue = "0") @Min(0) int page,
33+
@RequestParam(defaultValue = "5") @Min(1) @Max(50) int size,
3334
@RequestParam(required = false) String category) {
34-
return ResponseEntity.ok(storeService.getStores(size, category));
35+
StoresResponse response = storeService.getStores(page, size, category);
36+
return ResponseEntity.ok(response);
3537
}
3638

3739
@GetMapping("/api/shops/{storeId}")

src/main/java/eatda/service/cheer/CheerService.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import eatda.storage.image.ImageStorage;
2020
import java.util.List;
2121
import lombok.RequiredArgsConstructor;
22-
import org.springframework.data.domain.Pageable;
22+
import org.springframework.data.domain.PageRequest;
2323
import org.springframework.stereotype.Service;
2424
import org.springframework.transaction.annotation.Transactional;
2525

@@ -58,8 +58,8 @@ private void validateRegisterCheer(Member member, String storeKakaoId) {
5858
}
5959

6060
@Transactional(readOnly = true)
61-
public CheersResponse getCheers(int size) {
62-
List<Cheer> cheers = cheerRepository.findAllByOrderByCreatedAtDesc(Pageable.ofSize(size));
61+
public CheersResponse getCheers(int page, int size) {
62+
List<Cheer> cheers = cheerRepository.findAllByOrderByCreatedAtDesc(PageRequest.of(page, size));
6363
return toCheersResponse(cheers);
6464
}
6565

@@ -71,9 +71,9 @@ private CheersResponse toCheersResponse(List<Cheer> cheers) {
7171
}
7272

7373
@Transactional(readOnly = true)
74-
public CheersInStoreResponse getCheersByStoreId(Long storeId, int size) {
74+
public CheersInStoreResponse getCheersByStoreId(Long storeId, int page, int size) {
7575
Store store = storeRepository.getById(storeId);
76-
List<Cheer> cheers = cheerRepository.findAllByStoreOrderByCreatedAtDesc(store, Pageable.ofSize(size));
76+
List<Cheer> cheers = cheerRepository.findAllByStoreOrderByCreatedAtDesc(store, PageRequest.of(page, size));
7777

7878
List<CheerInStoreResponse> cheersResponse = cheers.stream()
7979
.map(CheerInStoreResponse::new)

src/main/java/eatda/service/store/StoreService.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import java.util.List;
1616
import java.util.Optional;
1717
import lombok.RequiredArgsConstructor;
18-
import org.springframework.data.domain.Pageable;
18+
import org.springframework.data.domain.PageRequest;
1919
import org.springframework.lang.Nullable;
2020
import org.springframework.stereotype.Service;
2121

@@ -33,19 +33,19 @@ public StoreResponse getStore(long storeId) {
3333
}
3434

3535
// TODO : N+1 문제 해결
36-
public StoresResponse getStores(int size, @Nullable String category) {
37-
return findStores(size, category)
36+
public StoresResponse getStores(int page, int size, @Nullable String category) {
37+
return findStores(page, size, category)
3838
.stream()
3939
.map(store -> new StorePreviewResponse(store, getStoreImageUrl(store).orElse(null)))
4040
.collect(collectingAndThen(toList(), StoresResponse::new));
4141
}
4242

43-
private List<Store> findStores(int size, @Nullable String category) {
43+
private List<Store> findStores(int page, int size, @Nullable String category) {
4444
if (category == null || category.isBlank()) {
45-
return storeRepository.findAllByOrderByCreatedAtDesc(Pageable.ofSize(size));
45+
return storeRepository.findAllByOrderByCreatedAtDesc(PageRequest.of(page, size));
4646
}
4747
return storeRepository.findAllByCategoryOrderByCreatedAtDesc(
48-
StoreCategory.from(category), Pageable.ofSize(size));
48+
StoreCategory.from(category), PageRequest.of(page, size));
4949
}
5050

5151
public ImagesResponse getStoreImages(long storeId) {

src/test/java/eatda/controller/cheer/CheerControllerTest.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,13 @@ class GetCheers {
6969
Cheer cheer1 = cheerGenerator.generateAdmin(member, store1, startAt);
7070
Cheer cheer2 = cheerGenerator.generateAdmin(member, store1, startAt.plusHours(1));
7171
Cheer cheer3 = cheerGenerator.generateAdmin(member, store2, startAt.plusHours(2));
72+
int page = 0;
73+
int size = 2;
7274

7375
CheersResponse response = given()
7476
.when()
75-
.queryParam("size", 2)
77+
.queryParam("page", page)
78+
.queryParam("size", size)
7679
.get("/api/cheer")
7780
.then()
7881
.statusCode(200)
@@ -99,10 +102,13 @@ class GetCheersByStoreId {
99102
Cheer cheer1 = cheerGenerator.generateCommon(member1, store);
100103
Thread.sleep(5);
101104
Cheer cheer2 = cheerGenerator.generateCommon(member2, store);
105+
int page = 0;
106+
int size = 2;
102107

103108
CheersInStoreResponse response = given()
104109
.when()
105-
.queryParam("size", 2)
110+
.queryParam("page", page)
111+
.queryParam("size", size)
106112
.get("/api/shops/{storeId}/cheers", store.getId())
107113
.then()
108114
.statusCode(200)

src/test/java/eatda/controller/store/StoreControllerTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,11 @@ class GetStores {
5656
cheerGenerator.generateCommon(member, store2, "image-key-2");
5757
cheerGenerator.generateCommon(member, store3, "image-key-3");
5858

59+
int page = 0;
5960
int size = 2;
6061

6162
StoresResponse response = given()
63+
.queryParam("page", page)
6264
.queryParam("size", size)
6365
.when()
6466
.get("/api/shops")
@@ -86,10 +88,12 @@ class GetStores {
8688
cheerGenerator.generateCommon(member, store2, "image-key-2");
8789
cheerGenerator.generateCommon(member, store3, "image-key-3");
8890

91+
int page = 0;
8992
int size = 2;
9093
StoreCategory category = StoreCategory.CAFE;
9194

9295
StoresResponse response = given()
96+
.queryParam("page", page)
9397
.queryParam("size", size)
9498
.queryParam("category", category.getCategoryName())
9599
.when()

src/test/java/eatda/document/store/CheerDocumentTest.java

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package eatda.document.store;
22

33
import static org.mockito.ArgumentMatchers.any;
4-
import static org.mockito.ArgumentMatchers.anyInt;
54
import static org.mockito.ArgumentMatchers.anyLong;
65
import static org.mockito.ArgumentMatchers.eq;
76
import static org.mockito.Mockito.doReturn;
@@ -137,7 +136,8 @@ class GetCheers {
137136
.tag(Tag.CHEER_API)
138137
.summary("최신 응원 검색")
139138
.queryParameter(
140-
parameterWithName("size").description("조회 개수 (최소 1, 최대 50)")
139+
parameterWithName("page").description("조회 페이지 (기본값 0, 최소 0)").optional(),
140+
parameterWithName("size").description("조회 개수 (기본값 5, 최소 1, 최대 50)").optional()
141141
);
142142

143143
RestDocsResponse responseDocument = response()
@@ -155,14 +155,15 @@ class GetCheers {
155155

156156
@Test
157157
void 음식점_검색_성공() {
158+
int page = 0;
158159
int size = 2;
159160
CheersResponse responses = new CheersResponse(List.of(
160161
new CheerPreviewResponse(2L, "https://example.image", "농민백암순대 본점", "강남구", "선릉구", "한식", 2L,
161162
"너무 맛있어요!"),
162163
new CheerPreviewResponse(1L, null, "석관동떡볶이", "성북구", "석관동", "기타", 1L,
163164
"너무 매워요! 하지만 맛있어요!")
164165
));
165-
doReturn(responses).when(cheerService).getCheers(anyInt());
166+
doReturn(responses).when(cheerService).getCheers(page, size);
166167

167168
var document = document("cheer/get-many", 200)
168169
.request(requestDocument)
@@ -179,8 +180,9 @@ class GetCheers {
179180
@EnumSource(value = BusinessErrorCode.class, names = {"PRESIGNED_URL_GENERATION_FAILED"})
180181
@ParameterizedTest
181182
void 음식점_검색_실패(BusinessErrorCode errorCode) {
183+
int page = 0;
182184
int size = 2;
183-
doThrow(new BusinessException(errorCode)).when(cheerService).getCheers(anyInt());
185+
doThrow(new BusinessException(errorCode)).when(cheerService).getCheers(page, size);
184186

185187
var document = document("cheer/get-many", errorCode)
186188
.request(requestDocument)
@@ -205,7 +207,8 @@ class GetCheersByStoreId {
205207
parameterWithName("storeId").description("가게 ID")
206208
)
207209
.queryParameter(
208-
parameterWithName("size").description("조회 개수 (최소 1, 최대 50)")
210+
parameterWithName("page").description("조회 페이지 (기본값 0, 최소 0)").optional(),
211+
parameterWithName("size").description("조회 개수 (기본값 5, 최소 1, 최대 50)").optional()
209212
);
210213

211214
RestDocsResponse responseDocument = response()
@@ -220,12 +223,13 @@ class GetCheersByStoreId {
220223
@Test
221224
void 가게별_응원_검색_성공() {
222225
Long storeId = 1L;
226+
int page = 0;
223227
int size = 2;
224228
CheersInStoreResponse responses = new CheersInStoreResponse(List.of(
225229
new CheerInStoreResponse(20L, 5L, "커찬", "너무 맛있어요!"),
226230
new CheerInStoreResponse(10L, 3L, "찬커", "너무 매워요! 하지만 맛있어요!")
227231
));
228-
doReturn(responses).when(cheerService).getCheersByStoreId(storeId, size);
232+
doReturn(responses).when(cheerService).getCheersByStoreId(storeId, page, size);
229233

230234
var document = document("cheer/get-store-id", 200)
231235
.request(requestDocument)
@@ -234,6 +238,7 @@ class GetCheersByStoreId {
234238

235239
given(document)
236240
.contentType(ContentType.JSON)
241+
.queryParam("page", page)
237242
.queryParam("size", size)
238243
.when().get("/api/shops/{storeId}/cheers", storeId)
239244
.then().statusCode(200);
@@ -243,8 +248,9 @@ class GetCheersByStoreId {
243248
@ParameterizedTest
244249
void 가게별_응원_검색_실패(BusinessErrorCode errorCode) {
245250
Long storeId = 1L;
251+
int page = 0;
246252
int size = 2;
247-
doThrow(new BusinessException(errorCode)).when(cheerService).getCheersByStoreId(eq(storeId), anyInt());
253+
doThrow(new BusinessException(errorCode)).when(cheerService).getCheersByStoreId(storeId, page, size);
248254

249255
var document = document("cheer/get-store-id", errorCode)
250256
.request(requestDocument)
@@ -253,6 +259,7 @@ class GetCheersByStoreId {
253259

254260
given(document)
255261
.contentType(ContentType.JSON)
262+
.queryParam("page", page)
256263
.queryParam("size", size)
257264
.when().get("/api/shops/{storeId}/cheers", storeId)
258265
.then().statusCode(errorCode.getStatus().value());

src/test/java/eatda/document/store/StoreDocumentTest.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package eatda.document.store;
22

3-
43
import static org.mockito.ArgumentMatchers.anyLong;
54
import static org.mockito.ArgumentMatchers.anyString;
65
import static org.mockito.Mockito.doReturn;
@@ -100,7 +99,8 @@ class GetStores {
10099
.tag(Tag.STORE_API)
101100
.summary("음식점 목록 조회")
102101
.queryParameter(
103-
parameterWithName("size").description("조회할 음식점 개수 (최소 1, 최대 50)"),
102+
parameterWithName("page").description("조회할 음식점 페이지 (기본 값 0,시작 값 0)").optional(),
103+
parameterWithName("size").description("조회할 음식점 개수 (기본 값 5, 최소 1, 최대 50)").optional(),
104104
parameterWithName("category")
105105
.description("음식점 카테고리(기본값: 전체) (한식,중식,일식,양식,카페/디저트,기타)").optional()
106106
);
@@ -118,13 +118,14 @@ class GetStores {
118118

119119
@Test
120120
void 음식점_목록_최신순으로_조회() {
121+
int page = 0;
121122
int size = 2;
122123
StoreCategory category = StoreCategory.CAFE;
123124
StoresResponse response = new StoresResponse(List.of(
124125
new StorePreviewResponse(2L, "https://example.image", "농민백암순대", "강남구", "대치동", "한식"),
125126
new StorePreviewResponse(1L, "https://example.image", "석관동떡볶이", "성북구", "석관동", "한식")
126127
));
127-
doReturn(response).when(storeService).getStores(size, category.getCategoryName());
128+
doReturn(response).when(storeService).getStores(page, size, category.getCategoryName());
128129

129130
var document = document("store/get", 200)
130131
.request(requestDocument)
@@ -133,6 +134,7 @@ class GetStores {
133134

134135
given(document)
135136
.contentType(ContentType.JSON)
137+
.queryParam("page", page)
136138
.queryParam("size", size)
137139
.queryParam("category", category.getCategoryName())
138140
.when().get("/api/shops")
@@ -142,9 +144,11 @@ class GetStores {
142144
@EnumSource(value = BusinessErrorCode.class, names = {"PRESIGNED_URL_GENERATION_FAILED"})
143145
@ParameterizedTest
144146
void 음식점_목록_조회_실패(BusinessErrorCode errorCode) {
147+
int page = 0;
145148
int size = 2;
146149
StoreCategory category = StoreCategory.CAFE;
147-
doThrow(new BusinessException(errorCode)).when(storeService).getStores(size, category.getCategoryName());
150+
doThrow(new BusinessException(errorCode))
151+
.when(storeService).getStores(page, size, category.getCategoryName());
148152

149153
var document = document("store/get", errorCode)
150154
.request(requestDocument)
@@ -153,6 +157,7 @@ class GetStores {
153157

154158
given(document)
155159
.contentType(ContentType.JSON)
160+
.queryParam("page", page)
156161
.queryParam("size", size)
157162
.queryParam("category", category.getCategoryName())
158163
.when().get("/api/shops")

0 commit comments

Comments
 (0)