Skip to content

Commit 911f514

Browse files
committed
feat : 모임 검색 like 기반 구현
1 parent ec5a95b commit 911f514

23 files changed

+353
-11358
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
:doctype: book
2+
:icons: font
3+
4+
[[bookshelfItemType]]
5+
include::{snippets}/enum-docs-controller-test/enums/enum-response-fields-groupSearchOption.adoc[]

src/docs/asciidoc/index.adoc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,27 @@ include::{snippets}/book-group-comment-controller-slice-test/delete-book-group-c
888888

889889
include::{snippets}/book-group-comment-controller-slice-test/delete-book-group-comment_-should-return-ok/path-parameters.adoc[]
890890

891+
892+
=== 모임 검색
893+
894+
==== Request
895+
include::{snippets}/book-group-controller-slice-test/find-all-book-groups-by-query/http-request.adoc[]
896+
897+
==== Request Header
898+
include::{snippets}/book-group-controller-slice-test/find-all-book-groups-by-query/request-headers.adoc[]
899+
900+
==== Request Parameter
901+
902+
include::{snippets}/book-group-controller-slice-test/find-all-book-groups-by-query/request-parameters.adoc[]
903+
904+
==== Response
905+
906+
include::{snippets}/book-group-controller-slice-test/find-all-book-groups-by-query/http-response.adoc[]
907+
908+
==== Response Fields
909+
910+
include::{snippets}/book-group-controller-slice-test/find-all-book-groups-by-query/response-fields.adoc[]
911+
891912
==== Response
892913

893914
include::{snippets}/book-group-comment-controller-slice-test/delete-book-group-comment_-should-return-ok/http-response.adoc[]

src/main/java/com/dadok/gaerval/domain/book_group/api/BookGroupController.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupCreateRequest;
2424
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupJoinRequest;
25+
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupQueryRequest;
2526
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupSearchRequest;
2627
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupUpdateRequest;
2728
import com.dadok.gaerval.domain.book_group.dto.response.BookGroupDetailResponse;
@@ -164,4 +165,12 @@ public ResponseEntity<Void> updateBookGroup(
164165
bookGroupService.updateBookGroup(groupId, userPrincipal.getUserId(), bookGroupUpdateRequest);
165166
return ResponseEntity.ok().build();
166167
}
168+
169+
@PreAuthorize(value = "hasAnyRole('ROLE_ANONYMOUS','ROLE_ADMIN', 'ROLE_USER')")
170+
@GetMapping(value = "/search", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE)
171+
public ResponseEntity<BookGroupResponses> findByQuery(
172+
@ModelAttribute BookGroupQueryRequest request
173+
) {
174+
return ResponseEntity.ok(bookGroupService.findByQuery(request));
175+
}
167176
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.dadok.gaerval.domain.book_group.dto.request;
2+
3+
import javax.validation.constraints.Max;
4+
import javax.validation.constraints.Min;
5+
import javax.validation.constraints.NotBlank;
6+
import javax.validation.constraints.NotNull;
7+
8+
import com.dadok.gaerval.global.common.EnumType;
9+
import com.dadok.gaerval.global.util.SortDirection;
10+
11+
import lombok.AllArgsConstructor;
12+
import lombok.Getter;
13+
14+
public record BookGroupQueryRequest(
15+
@Min(value = 0, message = "pageSize는 최소 0 입니다.")
16+
@Max(value = 100, message = "pageSize는 최대 100 입니다.")
17+
Integer pageSize,
18+
19+
Long groupCursorId,
20+
21+
@NotNull
22+
BookGroupQueryRequest.GroupSearchOption option,
23+
24+
@NotBlank(message = "검색어는 비어있으면 안됩니다.")
25+
@Min(value = 2, message = "검색어는 {min} 자 이상이여야 합니다.")
26+
String query,
27+
28+
SortDirection sortDirection
29+
) {
30+
31+
public BookGroupQueryRequest(Integer pageSize,
32+
Long groupCursorId,
33+
GroupSearchOption option,
34+
String query,
35+
SortDirection sortDirection) {
36+
this.pageSize = (pageSize == null) ? 10 : pageSize;
37+
this.groupCursorId = groupCursorId;
38+
this.sortDirection = sortDirection == null ? SortDirection.DESC : sortDirection;
39+
40+
this.option = option;
41+
this.query = query;
42+
}
43+
44+
@Getter
45+
@AllArgsConstructor
46+
public enum GroupSearchOption implements EnumType {
47+
GROUP_NAME("GROUP_NAME", "그룹 이름"),
48+
BOOK_NAME("BOOK_NAME", "책 이름");
49+
50+
private final String name;
51+
52+
private final String description;
53+
54+
@Override
55+
public String getName() {
56+
return name;
57+
}
58+
59+
@Override
60+
public String getDescription() {
61+
return description;
62+
}
63+
}
64+
}

src/main/java/com/dadok/gaerval/domain/book_group/repository/BookGroupSupport.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.dadok.gaerval.domain.book_group.repository;
22

3+
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupQueryRequest;
34
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupSearchRequest;
45
import com.dadok.gaerval.domain.book_group.dto.response.BookGroupDetailResponse;
56
import com.dadok.gaerval.domain.book_group.dto.response.BookGroupResponses;
@@ -12,4 +13,6 @@ interface BookGroupSupport {
1213

1314
BookGroupResponses findAllByUser(BookGroupSearchRequest request, Long userId);
1415

16+
BookGroupResponses findByQuery(BookGroupQueryRequest request);
17+
1518
}

src/main/java/com/dadok/gaerval/domain/book_group/repository/BookGroupSupportImpl.java

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,18 @@
1414
import org.springframework.data.domain.Slice;
1515
import org.springframework.data.domain.Sort;
1616

17+
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupQueryRequest;
18+
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupQueryRequest.GroupSearchOption;
1719
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupSearchRequest;
1820
import com.dadok.gaerval.domain.book_group.dto.response.BookGroupDetailResponse;
1921
import com.dadok.gaerval.domain.book_group.dto.response.BookGroupResponse;
2022
import com.dadok.gaerval.domain.book_group.dto.response.BookGroupResponses;
2123
import com.dadok.gaerval.domain.book_group.entity.BookGroup;
2224
import com.dadok.gaerval.global.error.exception.ResourceNotfoundException;
2325
import com.dadok.gaerval.global.util.QueryDslUtil;
26+
import com.querydsl.core.BooleanBuilder;
2427
import com.querydsl.core.Tuple;
28+
import com.querydsl.core.types.Predicate;
2529
import com.querydsl.core.types.Projections;
2630
import com.querydsl.jpa.impl.JPAQueryFactory;
2731

@@ -193,4 +197,73 @@ public BookGroupResponses findAllByUser(BookGroupSearchRequest request, Long use
193197
return new BookGroupResponses(bookGroupResponses);
194198
}
195199

200+
@Override
201+
public BookGroupResponses findByQuery(BookGroupQueryRequest request) {
202+
Sort.Direction direction = request.sortDirection().toDirection();
203+
204+
List<BookGroupResponse> groupResponses = query.select(constructor(BookGroupResponse.class,
205+
bookGroup.id.as("bookGroupId"),
206+
bookGroup.title.as("title"),
207+
bookGroup.introduce.as("introduce"),
208+
bookGroup.startDate.as("startDate"),
209+
bookGroup.endDate.as("endDate"),
210+
bookGroup.maxMemberCount.as("maxMemberCount"),
211+
bookGroup.hasJoinPasswd.as("hasJoinPasswd"),
212+
bookGroup.isPublic.as("isPublic"),
213+
214+
groupMember.countDistinct().as("memberCount"),
215+
groupComment.countDistinct().as("commentCount"),
216+
217+
Projections.constructor(BookGroupResponse.BookResponse.class,
218+
book.id.as("bookId"),
219+
book.imageUrl.as("imageUrl")
220+
),
221+
222+
Projections.constructor(BookGroupResponse.OwnerResponse.class,
223+
user.id.as("ownerId"),
224+
user.profileImage.as("ownerProfileUrl"),
225+
user.nickname.nickname.as("ownerNickname")
226+
)
227+
))
228+
.from(bookGroup)
229+
.innerJoin(book).on(book.id.eq(bookGroup.book.id))
230+
.leftJoin(user).on(user.id.eq(bookGroup.ownerId))
231+
.leftJoin(bookGroup.groupMembers, groupMember)
232+
.leftJoin(bookGroup.comments, groupComment)
233+
.where(
234+
QueryDslUtil.generateCursorWhereCondition(bookGroup.id, request.groupCursorId(), direction),
235+
searchQuery(request.option(), request.query())
236+
)
237+
.groupBy(bookGroup.id
238+
)
239+
.orderBy(QueryDslUtil.getOrder(bookGroup.id, direction))
240+
.limit(request.pageSize() + 1)
241+
.distinct()
242+
.fetch();
243+
244+
Slice<BookGroupResponse> bookGroupResponses = QueryDslUtil.toSlice(groupResponses,
245+
PageRequest.of(0, request.pageSize(), Sort.by(direction, "id")));
246+
247+
return new BookGroupResponses(bookGroupResponses);
248+
}
249+
250+
private Predicate searchQuery(GroupSearchOption option, String query) {
251+
BooleanBuilder booleanBuilder = new BooleanBuilder();
252+
253+
if (option == null) {
254+
return booleanBuilder.or(bookGroup.title.startsWith(query))
255+
.or(book.title.startsWith(query)).getValue();
256+
}
257+
258+
switch (option) {
259+
case BOOK_NAME -> {
260+
return book.title.startsWith(query);
261+
}
262+
case GROUP_NAME -> {
263+
return bookGroup.title.startsWith(query);
264+
}
265+
default -> throw new IllegalStateException("Unexpected value: " + option);
266+
}
267+
}
268+
196269
}

src/main/java/com/dadok/gaerval/domain/book_group/service/BookGroupService.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupCreateRequest;
66
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupJoinRequest;
7+
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupQueryRequest;
78
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupSearchRequest;
89
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupUpdateRequest;
910
import com.dadok.gaerval.domain.book_group.dto.response.BookGroupDetailResponse;
@@ -33,4 +34,7 @@ public interface BookGroupService {
3334
boolean checkGroupMember(Long userId, Long bookGroupId);
3435

3536
void leave(Long groupId, Long userId);
37+
38+
BookGroupResponses findByQuery(BookGroupQueryRequest request);
39+
3640
}

src/main/java/com/dadok/gaerval/domain/book_group/service/DefaultBookGroupService.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.dadok.gaerval.domain.book.service.BookService;
1111
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupCreateRequest;
1212
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupJoinRequest;
13+
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupQueryRequest;
1314
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupSearchRequest;
1415
import com.dadok.gaerval.domain.book_group.dto.request.BookGroupUpdateRequest;
1516
import com.dadok.gaerval.domain.book_group.dto.response.BookGroupDetailResponse;
@@ -139,4 +140,10 @@ public BookGroupResponses findAllBookGroupsByUser(BookGroupSearchRequest request
139140
return bookGroupRepository.findAllByUser(request, userId);
140141
}
141142

143+
@Transactional(readOnly = true)
144+
@Override
145+
public BookGroupResponses findByQuery(BookGroupQueryRequest request) {
146+
return this.bookGroupRepository.findByQuery(request);
147+
}
148+
142149
}

0 commit comments

Comments
 (0)