오늘 몸 상태 최악...^^
어젯밤부터 온수매트 짱짱하게 틀었는데 손발이 거의 얼음장이었는데 오늘도 그렇다...
감기이기엔 평소에 개심한 비염이라 긴가민가했는데 이건 감기 기운이 맞다...
리뷰 가게명/메뉴명 검색
가게명/메뉴명으로 검색할 수 있게 하고 싶은데...
쿼리를... 어떻게 짜야하냐.... (세상 복잡)
어차피 queryDSL을 써야한다면 여기서도 함 써봐야할 것 같다.
🧶QueryDSL을 알아보자
QueryDSL이라.. 이 녀석도 처음임..ㅎ 우선 세팅을 먼저 진행해보자!Gradle 추가//QueryDSL의 버전 //plugin 보다 앞에 둘 것buildscript { ext { queryDslVersion = "5.0.0" }}dependencies { //QueryDSL JPA 라이브러리 implementat
chooobb.tistory.com
이거 참고해서 어렵게 queryDSL 설정을 넣고 어찌어찌 코드 좀 써넣었는데...
뒤늦게 팀장님이 주문 API PR하신 걸 알고 Pull 받으니 이미 해놓으셨더라.
PR 안 하신 줄 알고 테스트 어떡하지 하고 있었는데... 개발하기 전에 Pull 땡기는 습관을 가져야만...ㅜㅜ
ReviewServiceImpl
@Override
public Page<ReviewResponseDto> searchReviewsByKeyword(User user, int searchType, String keyword, int page, int size, String sortBy, boolean isAsc) {
Sort.Direction direction = isAsc ? Sort.Direction.ASC : Sort.Direction.DESC;
Sort sort = Sort.by(direction, sortBy);
Pageable pageable = PageRequest.of(page, getValidPageSize(size), sort);
Page<Review> reviews;
if (searchType == 1) { // 가게명 검색
reviews = reviewRepository.findReviewsByStoreName(user.getId(), keyword, pageable);
} else if (searchType == 2) { // 메뉴명 검색
reviews = reviewRepository.findReviewsByMenuName(user.getId(), keyword, pageable);
} else {
throw new IllegalArgumentException("searchType은 1(가게명) 또는 2(메뉴명)이어야 합니다.");
}
return reviews.map(ReviewResponseDto::new);
}
private int getValidPageSize(int size) {
// 허용되는 페이지 크기 목록
List<Integer> allowedSizes = Arrays.asList(10, 30, 50);
// 페이지 크기가 허용된 값에 없으면 기본 10으로 설정
if (!allowedSizes.contains(size)) {
return 10;
}
return size;
}
ReviewRepository
ReveiwRepositoryCustom도 extends하도록 JpaRepository 뒤에 붙힘.
package com.sparta.tentenbackend.domain.review.repository;
import com.sparta.tentenbackend.domain.review.entity.Review;
import java.util.UUID;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ReviewRepository extends JpaRepository<Review, UUID> , ReviewRepositoryCustom {
Page<Review> findAllByOrder_User_IdAndIsDeletedFalse(Long id, Pageable pageable);
}
ReviewRepositoryCustom
package com.sparta.tentenbackend.domain.review.repository;
import com.sparta.tentenbackend.domain.review.entity.Review;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
public interface ReviewRepositoryCustom {
Page<Review> findReviewsByStoreName(Long userId, String keyword, Pageable pageable);
Page<Review> findReviewsByMenuName(Long userId, String keyword, Pageable pageable);
}
ReviewRepositoryImpl
package com.sparta.tentenbackend.domain.review.repository;
import com.querydsl.core.QueryFactory;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.sparta.tentenbackend.domain.menu.entity.QMenu;
import com.sparta.tentenbackend.domain.menu.entity.QMenuOrder;
import com.sparta.tentenbackend.domain.order.entity.QOrder;
import com.sparta.tentenbackend.domain.review.entity.QReview;
import com.sparta.tentenbackend.domain.review.entity.Review;
import com.sparta.tentenbackend.domain.store.entity.QStore;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import org.springframework.stereotype.Repository;
@Repository
public class ReviewRepositoryImpl extends QuerydslRepositorySupport implements ReviewRepositoryCustom {
private final JPAQueryFactory queryFactory;
public ReviewRepositoryImpl(JPAQueryFactory queryFactory) {
super(Review.class);
this.queryFactory = queryFactory;
}
@Override
public Page<Review> findReviewsByStoreName(Long userId, String keyword, Pageable pageable) {
QReview review = QReview.review;
QOrder order = QOrder.order;
QStore store = QStore.store;
JPAQuery<Review> query = queryFactory.selectFrom(review)
.join(review.order, order)
.join(order.store, store)
.where(store.name.containsIgnoreCase(keyword)
.and(order.user.id.eq(userId))
.and(review.isDeleted.isFalse()));
List<Review> reviews = getQuerydsl().applyPagination(pageable, query).fetch();
long total = query.fetchCount();
return new PageImpl<>(reviews, pageable, total);
}
@Override
public Page<Review> findReviewsByMenuName(Long userId, String keyword, Pageable pageable) {
QReview review = QReview.review;
QOrder order = QOrder.order;
QStore store = QStore.store;
QMenuOrder menuOrder = QMenuOrder.menuOrder;
QMenu menu = QMenu.menu;
JPAQuery<Review> query = queryFactory.selectFrom(review)
.join(review.order, order)
.join(order.store, store)
.join(order.menuOrderList, menuOrder) // 메뉴 주문 목록과 연결
.join(menuOrder.menu, menu) // 메뉴와 연결
.where(menu.name.containsIgnoreCase(keyword) // 메뉴명으로 검색
.and(order.user.id.eq(userId)) // 사용자 ID로 필터링
.and(review.isDeleted.isFalse())); // 삭제되지 않은 리뷰만 필터링
List<Review> reviews = getQuerydsl().applyPagination(pageable, query).fetch();
long total = query.fetchCount();
return new PageImpl<>(reviews, pageable, total);
}
}
리뷰 정렬
정렬 기준에 따라 OrderSpecifier 생성했다. 요구사항에 따르면 생성일, 수정일순으로 정렬되어야 함.
private OrderSpecifier<?> getOrderSpecifier(String sortBy, boolean isAsc) {
QReview review = QReview.review;
// 정렬 기준을 받아 정렬 설정
if ("createdAt".equalsIgnoreCase(sortBy)) {
return isAsc ? review.createdAt.asc() : review.createdAt.desc(); // 생성일 기준
} else if ("updatedAt".equalsIgnoreCase(sortBy)) {
return isAsc ? review.updatedAt.asc() : review.updatedAt.desc(); // 수정일 기준
} else {
// 기본적으로 생성일 기준으로 정렬
return isAsc ? review.createdAt.asc() : review.createdAt.desc();
}
}
사실 리뷰 전체 목록 조회는 굳이 queryDSL을 쓸 필요는 없을 것 같아서 그냥 ... 이렇게 했다ㅎㅎ
// ReviewServiceImpl
// 리뷰 목록 조회
@Override
public Page<ReviewResponseDto> findAllReviews(User user, int page, int size, String sortBy, boolean isAsc) {
Sort.Direction direction = isAsc ? Sort.Direction.ASC : Sort.Direction.DESC;
Sort sort = getSortByField(sortBy, direction);
Pageable pageable = PageRequest.of(page, size, sort);
// review 테이블에 저장된 order로 order.getUser().getId() == user.getId() 인 리뷰 목록/isDeleted=false만 조회하기
Page<Review> reviews = reviewRepository.findAllByOrder_User_IdAndIsDeletedFalse(user.getId(), pageable);
return reviews.map(ReviewResponseDto::new);
}
// 정렬 기준
private Sort getSortByField(String sortBy, Sort.Direction direction) {
if ("updatedAt".equalsIgnoreCase(sortBy)) {
return Sort.by(direction, "updatedAt");
} else if ("createdAt".equalsIgnoreCase(sortBy)) {
return Sort.by(direction, "createdAt");
} else {
// 기본값으로 생성일 기준 정렬
return Sort.by(direction, "createdAt");
}
}
고민
지금 사장님의 리뷰에서 주문내역에 저장된 가게의 사장님과 로그인 유저가 같을 때, 그 아이디를 불러오는 게 너무 ...
이게 맞나...? 싶어서 어케 해야할지 모르겠다.
Long ownerUserId = review.getOrder().getStore().getUser().getId(); < 이거...
@Override
public OwnerReviewResponseDto addOwnerReview(OwnerReviewRequestDto requestDto, User user) {
UUID reviewId = UUID.fromString(requestDto.getReviewId());
Review review = reviewRepository.findById(reviewId)
.orElseThrow(() -> new NotFoundException("해당 리뷰를 찾을 수 없습니다."));
// 유저가 OWNER고, 유저아이디가 가게 사장님 아이디와 일치할 때
Long ownerUserId = review.getOrder().getStore().getUser().getId();
if (user.getRole() == UserRoleEnum.OWNER && user.getId() == ownerUserId) {
OwnerReview ownerReview = ownerReviewRepository.save(new OwnerReview(requestDto, review));
return new OwnerReviewResponseDto(ownerReview);
} else {
throw new UnauthorizedException("해당 리뷰에 대한 권한이 없습니다.");
}
}
잇츠 고민고민...
'TIL' 카테고리의 다른 글
TIL11. 테스트의 늪 (0) | 2025.02.25 |
---|---|
TIL10. 리팩토링, 카테고리별 가게 목록 조회, soft-delete (1) | 2025.02.24 |
TIL8. AI API (0) | 2025.02.20 |
TIL7. S3 Bucket 적용, DTO Validation (0) | 2025.02.19 |
TIL6. Paging, S3 Bucket (0) | 2025.02.18 |