Skip to content

Commit

Permalink
Release:v1.0.0-beta.17
Browse files Browse the repository at this point in the history
ygyg[v1.0.0-beta.17]
- 게시글 검색 API 개발
  • Loading branch information
Hwan0518 authored Jan 31, 2025
2 parents 49e44e3 + 4be9b28 commit 562f44c
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package foiegras.ygyg.global.common.querydsl;


import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.BooleanExpression;
import foiegras.ygyg.post.infrastructure.entity.QItemImageUrlEntity;
import foiegras.ygyg.post.infrastructure.entity.QParticipatingUsersEntity;
Expand All @@ -13,7 +15,7 @@


@Component
public class PostDomainBooleanExpression {
public class PostDomainQueryDslUtil {

// query dsl value
private final static QUserPostEntity userPostEntity = QUserPostEntity.userPostEntity;
Expand All @@ -32,6 +34,8 @@ public class PostDomainBooleanExpression {
* Post 도메인의 BooleanExpressions
* 1. cursor로 다음 userPost 조회
* 2. 타입별 userPost 조회
* 3. 타입별 정렬 기준 설정
* 4. 최소 참여인원 달성한 소분글만 조회 여부
*/

// 1. cursor로 다음 userPost 조회
Expand Down Expand Up @@ -59,4 +63,21 @@ public BooleanExpression selectType(String type, UUID userUuid, LocalDateTime cu
};
}


// 3. 타입별 정렬 기준 설정
public OrderSpecifier<?> getSortBy(String sortBy) {
return switch (sortBy) {
case "soonest" -> userPostEntity.portioningDate.asc();
case "lowestPrice" -> userPostEntity.expectedMinimumPrice.asc();
case "lowestRemain" -> userPostEntity.remainCount.asc();
default -> userPostEntity.id.desc();
};
}


// 4. 최소 참여인원 달성한 소분글만 조회 여부
public Predicate isMinimumPeopleMet(Boolean isMinimumPeopleMet) {
return isMinimumPeopleMet ? userPostEntity.isFullMinimum.eq(true) : null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public class SecurityConfig {
private static final RequestMatcher[] postUrl = new RequestMatcher[] {
new AntPathRequestMatcher("/api/v1/post/list", GET),
new AntPathRequestMatcher("/api/v1/post/list/**", GET),

new AntPathRequestMatcher("/api/v1/post/search", GET),
};

private final JwtAuthenticationFilter jwtAuthenticationFilter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@
import foiegras.ygyg.post.api.request.GetMyPostListRequest;
import foiegras.ygyg.post.api.response.GetUserPostListByCursorResponse;
import foiegras.ygyg.post.api.response.GetUserPostListResponse;
import foiegras.ygyg.post.application.dto.userpost.in.GetMyPostListInDto;
import foiegras.ygyg.post.application.dto.userpost.in.GetUserPostListByCategoryInDto;
import foiegras.ygyg.post.application.dto.userpost.in.GetUserPostListInDto;
import foiegras.ygyg.post.application.dto.userpost.in.JoinPortioningInDto;
import foiegras.ygyg.post.application.dto.userpost.in.*;
import foiegras.ygyg.post.application.dto.userpost.out.GetUserPostListByCursorOutDto;
import foiegras.ygyg.post.application.dto.userpost.out.GetUserPostListOutDto;
import foiegras.ygyg.post.application.facade.JoinPortioningFacade;
Expand Down Expand Up @@ -44,6 +41,7 @@ public class UserPostController {
* 2. 소분글 전체목록 조회
* 3. 소분글 카테고리별 목록 조회
* 4. 타입별 소분글 목록 조회
* 5. 제목으로 소분글 검색
*/

// 1. 소분글 참여하기
Expand Down Expand Up @@ -93,4 +91,21 @@ public BaseResponse<GetUserPostListByCursorResponse> getMyPostListByType(GetMyPo
return new BaseResponse<>(response.toBuilder().myPost(outDto.getContent()).build());
}


// 5. 제목으로 소분글 검색
@Operation(summary = "제목으로 소분글 검색", description = "제목으로 소분글 목록을 조회한다. sortBy type은 latest, soonest, lowestPrice, lowestRemain 네 가지중 하나를 택한다", tags = { "Post" })
@GetMapping("/search")
public BaseResponse<GetUserPostListResponse> searchPostList(@RequestParam(name = "keyword") String keyword, @RequestParam(name = "isMinimumPeopleMet") Boolean isMinimumPeopleMet,
@RequestParam(name = "sortBy") String sortBy, @PageableDefault(size = 9) Pageable pageable) {
SearchPostInDto inDto = SearchPostInDto.builder()
.keyword(keyword)
.isMinimumPeopleMet(isMinimumPeopleMet)
.sortBy(sortBy)
.pageable(pageable)
.build();
GetUserPostListOutDto outDto = userPostService.searchPost(inDto);
GetUserPostListResponse response = modelMapper.map(outDto, GetUserPostListResponse.class);
return new BaseResponse<>(response);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package foiegras.ygyg.post.application.dto.userpost.in;


import lombok.Builder;
import lombok.Getter;
import org.springframework.data.domain.Pageable;


@Getter
@Builder
public class SearchPostInDto {

private String keyword;
private String sortBy;
private Pageable pageable;
private Boolean isMinimumPeopleMet;

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import foiegras.ygyg.post.application.dto.userpost.in.GetMyPostListInDto;
import foiegras.ygyg.post.application.dto.userpost.in.GetUserPostListByCategoryInDto;
import foiegras.ygyg.post.application.dto.userpost.in.GetUserPostListInDto;
import foiegras.ygyg.post.application.dto.userpost.in.SearchPostInDto;
import foiegras.ygyg.post.application.dto.userpost.out.*;
import foiegras.ygyg.post.infrastructure.entity.ItemImageUrlEntity;
import foiegras.ygyg.post.infrastructure.entity.PostEntity;
Expand Down Expand Up @@ -58,6 +59,7 @@ public class UserPostService {
* 6. 소분글 리스트 조회
* 7. 카테고리로 소분글 리스트 조회
* 8. 타입별 내 소분글 리스트 조회
* 9. 카테고리 및 검색어로 소분글 리스트 조회
*/

// 1. id로 UserPost 조회
Expand Down Expand Up @@ -184,4 +186,22 @@ public GetUserPostListByCursorOutDto getMyPostListByType(GetMyPostListInDto inDt
.build();
}


// 9. 검색어로 소분글 리스트 조회
public GetUserPostListOutDto searchPost(SearchPostInDto inDto) {
Pageable basePageable = inDto.getPageable();
Pageable newPageable = PageRequest.of(basePageable.getPageNumber(), basePageable.getPageSize(), createSortBy(inDto.getSortBy()));
Page<UserPostEntity> result = userPostQueryDslRepository.searchPost(inDto, newPageable);
return GetUserPostListOutDto.builder()
.items(result.getContent().stream()
.map(this::convertToListItemDto)
.toList())
.pageInfoDto(PageInfoDto.builder()
.totalItemsLength(result.getTotalElements())
.currentPage(result.getNumber() + 1)
.size(result.getContent().size())
.build())
.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@


import foiegras.ygyg.post.application.dto.userpost.in.GetMyPostListInDto;
import foiegras.ygyg.post.application.dto.userpost.in.SearchPostInDto;
import foiegras.ygyg.post.application.dto.userpost.out.UserPostListQueryDataByCursorOutDto;
import foiegras.ygyg.post.infrastructure.entity.UserPostEntity;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.time.LocalDateTime;
import java.util.List;
Expand All @@ -18,4 +21,7 @@ public interface UserPostQueryDslRepository {
// 유저 UUID로, 타입별 소분글 조회
UserPostListQueryDataByCursorOutDto findPostListByCursor(GetMyPostListInDto inDto);

// 키워드로 소분글 검색
Page<UserPostEntity> searchPost(SearchPostInDto inDto, Pageable newPageable);

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@

import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import foiegras.ygyg.global.common.querydsl.PostDomainBooleanExpression;
import foiegras.ygyg.global.common.querydsl.PostDomainQueryDslUtil;
import foiegras.ygyg.global.common.querydsl.QueryDslService;
import foiegras.ygyg.post.application.dto.userpost.in.GetMyPostListInDto;
import foiegras.ygyg.post.application.dto.userpost.in.SearchPostInDto;
import foiegras.ygyg.post.application.dto.userpost.out.UserPostItemDto;
import foiegras.ygyg.post.application.dto.userpost.out.UserPostListQueryDataByCursorOutDto;
import foiegras.ygyg.post.infrastructure.entity.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Repository;
Expand All @@ -35,14 +38,15 @@ public class UserPostQueryDslRepositoryImpl implements UserPostQueryDslRepositor
private final static String DESC = "desc";
// querydsl
private final JPAQueryFactory queryFactory;
private final PostDomainBooleanExpression booleanExpression;
private final PostDomainQueryDslUtil queryDslUtil;
private final QueryDslService queryDslService;


/**
* UserPostQueryDslRepository
* 1. 유저 UUID로, 유저가 참여한 진행중인 소분글 조회
* 2. 유저 UUID로, 타입별 소분글 조회
* 3. 키워드로 소분글 검색
*/

// 1. 유저 UUID로, 유저가 참여한 진행중인 소분글 조회
Expand Down Expand Up @@ -80,8 +84,8 @@ public UserPostListQueryDataByCursorOutDto findPostListByCursor(GetMyPostListInD
.leftJoin(itemImageUrlEntity).on(itemImageUrlEntity.postEntity.id.eq(postEntity.id)).limit(1)
.leftJoin(participatingUsersEntity).on(participatingUsersEntity.userPostEntity.id.eq(userPostEntity.id))
.where(
booleanExpression.selectType(inDto.getType(), inDto.getUserUuid(), inDto.getCurrentTime()),
booleanExpression.getNextUserPost(inDto.getLastCursor(), inDto.getOrder()))
queryDslUtil.selectType(inDto.getType(), inDto.getUserUuid(), inDto.getCurrentTime()),
queryDslUtil.getNextUserPost(inDto.getLastCursor(), inDto.getOrder()))
.orderBy(inDto.getOrder().equals(ASC) ? userPostEntity.id.asc() : userPostEntity.id.desc())
.distinct()
.limit(pageable.getPageSize() + 1) // 다음 페이지 여부 확인을 위해 +1개 조회
Expand All @@ -96,4 +100,35 @@ public UserPostListQueryDataByCursorOutDto findPostListByCursor(GetMyPostListInD
return new UserPostListQueryDataByCursorOutDto(finalContent, pageable, hasNext, lastCursorId);
}


// 3. 키워드로 소분글 검색
@Override
public Page<UserPostEntity> searchPost(SearchPostInDto inDto, Pageable pageable) {
// content limited by size
List<UserPostEntity> content = queryFactory
.selectFrom(userPostEntity)
.join(postEntity).on(postEntity.id.eq(userPostEntity.postEntity.id))
.where(
userPostEntity.postTitle.contains(inDto.getKeyword()),
queryDslUtil.isMinimumPeopleMet(inDto.getIsMinimumPeopleMet())
)
.orderBy(queryDslUtil.getSortBy(inDto.getSortBy()))
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
// total contents count
Long totalResult = queryFactory
.select(userPostEntity.count())
.from(userPostEntity)
.join(postEntity).on(postEntity.id.eq(userPostEntity.postEntity.id))
.where(
userPostEntity.postTitle.contains(inDto.getKeyword()),
queryDslUtil.isMinimumPeopleMet(inDto.getIsMinimumPeopleMet())
)
.fetchOne();
long total = totalResult != null ? totalResult : 0;
// result
return new PageImpl<>(content, pageable, total);
}

}

0 comments on commit 562f44c

Please sign in to comment.