Skip to content

Commit

Permalink
[feat] 검색 api
Browse files Browse the repository at this point in the history
  • Loading branch information
jainefer committed Dec 4, 2024
1 parent 3812ff1 commit 829e37d
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.jboss.logging.MDC;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.parameters.P;
import org.springframework.web.bind.annotation.*;
import site.billbill.apiserver.api.borrowPosts.dto.request.PostsRequest;
import site.billbill.apiserver.api.borrowPosts.dto.response.PostsResponse;
Expand Down Expand Up @@ -52,6 +53,23 @@ public BaseResponse<PostsResponse.ViewAllResultResponse> getPostsController(
Sort.Direction direction = "asc".equalsIgnoreCase(order) ? Sort.Direction.ASC : Sort.Direction.DESC;
return new BaseResponse<>(postsService.ViewAllPostService(category,page,direction,sortBy));
}
@GetMapping("/search")
public BaseResponse<PostsResponse.ViewAllResultResponse> getSearchPostsController(
@Parameter(name = "category", description = "카테고리 필터 (예: entire, camp, sports,tools )", example = "entire", in = ParameterIn.QUERY, required = false)
@RequestParam(value ="category",required = false,defaultValue = "entire") String category,
@Parameter(name = "page", description = "페이지 번호 (1부터 시작)", example = "1", in = ParameterIn.QUERY, required = false)
@RequestParam(value ="page",required = false,defaultValue = "1") int page,
@Parameter(name = "order", description = "정렬 방향 (asc: 오름차순, desc: 내림차순)", example = "desc", in = ParameterIn.QUERY, required = false)
@RequestParam(value ="order",required = false,defaultValue = "desc") String order,
@Parameter(name = "sortBy", description = "정렬 기준 (예: price, createdAt, likeCount)", example = "createdAt", in = ParameterIn.QUERY, required = true)
@RequestParam(value="sortBy",required = true,defaultValue = "accuracy") String sortBy,
@Parameter(name="keyword",description = "검색 키워드(예: 6인용+텐트)",in = ParameterIn.QUERY, required = true)
@RequestParam(value = "keyword",required = true) String keyword) {


Sort.Direction direction = "asc".equalsIgnoreCase(order) ? Sort.Direction.ASC : Sort.Direction.DESC;
return new BaseResponse<>(postsService.ViewSearchPostService(category, page, direction, sortBy,keyword));
}
@GetMapping("/{postId}")
public BaseResponse<PostsResponse.ViewPostResponse> getPostController(@PathVariable(value = "postId",required = true)String postId){

Expand All @@ -77,4 +95,5 @@ public BaseResponse<String> updatePostController(@PathVariable(value="postId",re
}



}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public static ItemsBorrowStatusJpaEntity toItemBorrowStatus(ItemsJpaEntity item,
public static PostsResponse.Post toPost(ItemsJpaEntity item,ItemsBorrowJpaEntity borrowItem){
return PostsResponse.Post.builder()
.postId(item.getId())
.title(item.getTitle())
.image(Optional.ofNullable(item.getImages())
.filter(images -> !images.isEmpty())
.map(images -> images.get(0))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public static class ViewAllResultResponse{
public static class Post{
private String postId;
private String image;
private String title;
private int price;
private String userId;
private String userName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ public interface PostsService {

String deletePostService(String postId,String userId);
String UpdatePostService(String postId,String userId,PostsRequest.UploadRequest request);

PostsResponse.ViewAllResultResponse ViewSearchPostService(String category, int page, Sort.Direction direction, String orderType,String keyword);
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,42 +77,9 @@ public PostsResponse.UploadResponse uploadPostService(PostsRequest.UploadRequest
public PostsResponse.ViewAllResultResponse ViewAllPostService(
String category, int page, Sort.Direction direction, String orderType) {

// 기본 정렬 필드와 방향 설정
String sortField = switch (orderType) {
case "price" -> "price";
case "createdAt" -> "createdAt";
case "likeCount" -> "likeCount";
default -> "createdAt"; // 기본 정렬
};

direction = (direction == null) ? Sort.Direction.DESC : direction;

Pageable pageable = PageRequest.of(
Math.max(0, page - 1), // 페이지 번호 조정 (0부터 시작)
20,
Sort.by(direction, sortField)
);

// Repository 호출
Page<ItemsJpaEntity> itemsPage = itemsRepository.findItemsWithConditions(category, pageable, sortField);

// 빈 결과 체크
if (itemsPage.isEmpty()) {
log.warn("No items found for category: {}, page: {}, sortField: {}", category, page, sortField);
return PostsConverter.toViewAllList(List.of());
}

// 데이터 변환
List<PostsResponse.Post> borrowItems = itemsPage.getContent().stream()
.map(item -> {
ItemsBorrowJpaEntity borrowItem = itemsBorrowRepository.findById(item.getId()).orElse(null);
if (borrowItem == null) {
log.warn("No borrow item found for item ID: {}", item.getId());
}
return PostsConverter.toPost(item, borrowItem);
}).toList();

return PostsConverter.toViewAllList(borrowItems);
Pageable pageable = createPageable(page, direction, orderType);
List<PostsResponse.Post> items = findAndConvertItems(category, pageable, null);
return PostsConverter.toViewAllList(items);
}

public PostsResponse.ViewPostResponse ViewPostService(String postId){
Expand Down Expand Up @@ -193,4 +160,55 @@ public String UpdatePostService(String postId,String userId,PostsRequest.UploadR
}
return "success";
}
public PostsResponse.ViewAllResultResponse ViewSearchPostService(String category, int page, Sort.Direction direction, String orderType,String keyword){
Pageable pageable = createPageable(page, direction, orderType);
List<PostsResponse.Post> items = findAndConvertItems(category, pageable, keyword);
return PostsConverter.toViewAllList(items);
}



//모듈화 코드

private Pageable createPageable(int page, Sort.Direction direction, String orderType) {
//카테고리 필드
String sortField = switch (orderType) {
case "price" -> "price";
case "createdAt" -> "createdAt";
case "likeCount" -> "likeCount";
default -> "createdAt"; // 기본 정렬
};
//정렬 순서
direction = (direction == null) ? Sort.Direction.DESC : direction;
//페이지 생성
return PageRequest.of(
Math.max(0, page - 1), // 페이지 번호 조정 (0부터 시작)
20,
Sort.by(direction, sortField)
);
}

private List<PostsResponse.Post> findAndConvertItems(String category, Pageable pageable, String keyword) {
// Repository 호출
Page<ItemsJpaEntity> itemsPage = itemsRepository.findItemsWithConditions(category, pageable, null, keyword);

// 빈 결과 체크
if (itemsPage.isEmpty()) {
log.warn("No items found for category: {}", category);
return List.of();
}

// 데이터 변환
return itemsPage.getContent().stream()
.map(item -> {
ItemsBorrowJpaEntity borrowItem = itemsBorrowRepository.findById(item.getId()).orElse(null);
if (borrowItem == null) {
log.warn("No borrow item found for item ID: {}", item.getId());
}
return PostsConverter.toPost(item, borrowItem);
})
.toList();
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
import site.billbill.apiserver.model.post.ItemsJpaEntity;

public interface ItemDslRepository {
Page<ItemsJpaEntity> findItemsWithConditions(String category, Pageable pageable, String sortField);
Page<ItemsJpaEntity> findItemsWithConditions(String category, Pageable pageable, String sortField,String keyword);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package site.billbill.apiserver.repository.borrowPosts;

import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
Expand All @@ -21,12 +22,12 @@ public class ItemDslRepositoryImpl implements ItemDslRepository{
private final JPAQueryFactory queryFactory;

@Override
public Page<ItemsJpaEntity> findItemsWithConditions(String category, Pageable pageable, String sortField) {
public Page<ItemsJpaEntity> findItemsWithConditions(String category, Pageable pageable, String sortField,String keyword) {
QItemsJpaEntity items = QItemsJpaEntity.itemsJpaEntity;
QItemsBorrowJpaEntity borrow = QItemsBorrowJpaEntity.itemsBorrowJpaEntity;
QItemsCategoryJpaEntity categoryEntity = QItemsCategoryJpaEntity.itemsCategoryJpaEntity;

log.info("Category: {}, Sort Field: {}, Pageable: {}", category, sortField, pageable);


JPAQuery<ItemsJpaEntity> query = queryFactory.selectFrom(items)
.leftJoin(borrow).on(items.id.eq(borrow.item.id)) // 식별 관계 조인
Expand All @@ -39,21 +40,31 @@ public Page<ItemsJpaEntity> findItemsWithConditions(String category, Pageable pa
.fetchOne();

if (fetchedCategory == null) {
log.warn("Category '{}' not found. Returning empty result.", category);
log.warn("카테고리를 찾을 수 없음.", category);
return new PageImpl<>(List.of(), pageable, 0);
}
query.where(items.category.eq(fetchedCategory));
}

// 정렬 조건
if (sortField != null) {
OrderSpecifier<?> orderSpecifier = getOrderSpecifier(sortField, pageable.getSort().getOrderFor(sortField));
if (orderSpecifier != null) {
query.orderBy(orderSpecifier);
} else {
log.warn("Invalid sort field: {}, no sorting applied.", sortField);
//키워드 필터링
if(keyword !=null && !keyword.isEmpty()){
query.where(applyKeywordFilter(items,keyword));
}

// 정렬 조건 처리
pageable.getSort().forEach(order -> {
OrderSpecifier<?> orderSpecifier;
switch (order.getProperty()) {
case "price" -> orderSpecifier = order.isAscending() ? borrow.price.asc() : borrow.price.desc();
case "createdAt" -> orderSpecifier = order.isAscending() ? items.createdAt.asc() : items.createdAt.desc();
case "likeCount" -> orderSpecifier = order.isAscending() ? items.likeCount.asc() : items.likeCount.desc();
default -> {
log.warn("Invalid sort field: {}", order.getProperty());
return;
}
}
}
query.orderBy(orderSpecifier);
});

// 페이징 처리
List<ItemsJpaEntity> content = query.offset(pageable.getOffset())
Expand Down Expand Up @@ -94,6 +105,29 @@ private OrderSpecifier<?> getOrderSpecifier(String sortField, Sort.Order sortOrd
return null; // 기본 정렬 없음
}
}
private BooleanExpression applyKeywordFilter(QItemsJpaEntity items, String keyword) {
if (keyword == null || keyword.isEmpty()) {
return null;
}

// '+'를 기준으로 키워드 분리
String[] keywords = keyword.split("\\+");

// 키워드 조건 생성
BooleanExpression keywordCondition = null;
for (String key : keywords) {
BooleanExpression condition = items.title.containsIgnoreCase(key)
.or(items.content.containsIgnoreCase(key));

if (keywordCondition == null) {
keywordCondition = condition;
} else {
keywordCondition = keywordCondition.or(condition); // AND 대신 OR 사용
}
}

return keywordCondition;
}


}

0 comments on commit 829e37d

Please sign in to comment.