코딩블로그
[Spring] 검색기능-QueryDsl로 무한스크롤로 넘겨주기 본문
728x90
팝콘메이트에서는 검색 기능이 있는데, 프론트 분들이 무한 스크롤 형식으로 넘겨달라고 부탁하셔서 Querydsl 적용해보는 겸 구현해 보았다!
💖 Controller
@GetMapping("/screenings/search")
public SliceResponse<Screening> searchScreenings(
@RequestParam(required = false,value = "title") String title,
@RequestParam(required = false,value= "category") Category category,
@ParameterObject @PageableDefault(size = 10) Pageable pageable
) {
return screeningAdaptor.searchScreenings(title, category, pageable);
}
💖 ScreeningAdaptor
public SliceResponse<Screening> searchScreenings(String title, Category category, Pageable pageable) {
return screeningRepository.querySliceScreening(title, category, pageable);
}
💖 ScreeningRepositoryCustom
public interface ScreeningRepositoryCustom {
SliceResponse<Screening> querySliceScreening(String title, Category category, Pageable pageable);
SliceResponse<Screening> querySliceScreeningByDate(String title, Category category, Pageable pageable);
}
(여기서 명명방식이 중요하다!! 이 형식으로 하지 않으면 인식하지 않게 되어 구현 불가능하다 )
💖 ScreeningRepositoryImpl
@RequiredArgsConstructor
public class ScreeningRepositoryImpl implements ScreeningRepositoryCustom {
private final JPAQueryFactory queryFactory;
@Override
public SliceResponse<Screening> querySliceScreening(String title, Category category, Pageable pageable) {
List<Screening> query = queryFactory.selectFrom(QScreening.screening)
.where(
containsTitle(title),
hasCategory(category),
QScreening.screening.isPrivate.eq(false)
)
.orderBy(QScreening.screening.createdAt.desc()) // Adjust the sorting as needed
.offset(pageable.getOffset())
.limit(pageable.getPageSize()+1)
.fetch();
return SliceResponse.of(SliceUtil.toSlice(query, pageable));
}
}
여기까지는 모두가 다 똑같이 하셨을 것 같은데 나는 따로 SliceResponse, SliceUtil을 만들어서 프론트분들이 조금 더 쉽게 받아보실 수 있게 구현하였다
💖 SliceResponse
public record SliceResponse<T>(List<T> content, long page, int size, boolean hasNext) {
public static <T> SliceResponse<T> of(Slice<T> slice) {
return new SliceResponse<>(
slice.getContent(),
slice.getNumber(),
slice.getNumberOfElements(),
slice.hasNext());
}
}
레코드는 클래스와 유사하지만, 간단한 데이터 전송 객체를 만드는 데 특화되어 있어서 record를 사용하였다
여기서 다양한 ResponseDto나 Entity를 받아들일 수 있도록 제네릭 클래스를 사용하였다. 제네릭 클래스는 다양한 데이터 타입을 수용할 수 있는 클래스이다. 즉, 클래스를 정의할 때 클래스 내부에서 사용되는 데이터 타입을 특정하지 않고, 어떤 타입이든지 사용할 수 있도록 유연하게 만드는 기능을 제공하는 것이다.
💖 SliceUtil
public class SliceUtil {
public static <T> Slice<T> toSlice(List<T> contents, Pageable pageable) {
boolean hasNext = hasNext(contents, pageable);
return new SliceImpl<>(
hasNext ? getContent(contents, pageable) : contents, pageable, hasNext);
}
// 다음 페이지 있는지 확인
private static <T> boolean hasNext(List<T> content, Pageable pageable) {
return pageable.isPaged() && content.size() > pageable.getPageSize();
}
// 데이터 1개 빼고 반환
private static <T> List<T> getContent(List<T> content, Pageable pageable) {
return content.subList(0, pageable.getPageSize());
}
}
💖 스웨거상에서 요청할 수 있는 parameter
💖 요청 후 예시 Response
{
"content": [
{
"createdAt": "2024-02-14T13:38:45.537Z",
"updatedAt": "2024-02-14T13:38:45.537Z",
"id": 0,
"title": "string",
"posterImgUrl": "string",
"hostInfo": {
"hostName": "string",
"hostPhoneNumber": "string",
"hostEmail": "string"
},
"positiveCount": {
"cineMaster": 0,
"greatFilming": 0,
"pom": 0,
"animationIsGood": 0,
"artIsGood": 0,
"setIsArt": 0,
"custom": 0,
"music": 0,
"ost": 0,
"writtenByGod": 0,
"topicIsGood": 0,
"linesAreGood": 0,
"endingIsGood": 0,
"castingIsGood": 0,
"actingIsGood": 0,
"chemistryIsGood": 0
},
"negativeCount": {
"iffy": 0,
"badEditing": 0,
"badAngle": 0,
"badDetail": 0,
"badColor": 0,
"badCustom": 0,
"badMusic": 0,
"badSound": 0,
"badEnding": 0,
"endingLoose": 0,
"noDetail": 0,
"badTopic": 0,
"badActing": 0,
"badCasting": 0
},
"month": "2024-02-14T13:38:45.537Z",
"screeningStartDate": "2024-02-14T13:38:45.537Z",
"screeningEndDate": "2024-02-14T13:38:45.537Z",
"screeningStartTime": "2024-02-14T13:38:45.537Z",
"location": "string",
"participationUrl": "string",
"information": "string",
"hasAgreed": true,
"category": "GRADUATE",
"screeningRate": 0,
"movieReviewCountNeg": 0,
"movieReviewCountPos": 0,
"locationCountNeg": 0,
"locationCountPos": 0,
"serviceCountNeg": 0,
"serviceCountPos": 0,
"private": true
}
],
"page": 0,
"size": 0,
"hasNext": true
}
728x90
'PopcornMate' 카테고리의 다른 글
멀티 모듈 환경에서 내가 만든 api 테스트해보기 Feat. MockMvc, profileResolver, WithCustomUser (0) | 2024.03.24 |
---|---|
[Spring] FCM 구축하기 & FCM과 @Scheduled을 이용하여 특정 시간대에 알림 보내기 (4) | 2024.03.11 |
[Spring] Amazons S3 Presigned Url 구현하기 (0) | 2024.03.11 |
[리팩토링]InteliJ를 활용하여 멀티모듈 패키지 의존성 사이클 검사 및 개선 (1) | 2024.02.16 |
[인프라] 멀티모듈 적용기 (1) | 2024.02.08 |