diff --git a/src/main/java/com/mpnp/baechelin/review/repository/ReviewQueryRepository.java b/src/main/java/com/mpnp/baechelin/review/repository/ReviewQueryRepository.java index 8634a53..06849db 100644 --- a/src/main/java/com/mpnp/baechelin/review/repository/ReviewQueryRepository.java +++ b/src/main/java/com/mpnp/baechelin/review/repository/ReviewQueryRepository.java @@ -11,7 +11,7 @@ import java.util.List; import static com.mpnp.baechelin.config.QuerydslConfig.locationBuilder; -import static com.mpnp.baechelin.review.domain.QReview.review1; +import static com.mpnp.baechelin.review.domain.QReview.review; import static com.mpnp.baechelin.store.domain.QStore.store; @Repository @@ -31,11 +31,12 @@ public List findRecentReviews(BigDecimal latStart, int limit) { BooleanBuilder builder = locationBuilder(latStart, latEnd, lngStart, lngEnd); // 위도 경도에 해당하는 가게를 찾음 -> 해당 댓글을 다 가져옴 -> 내림차순 정렬 -> limit - return queryFactory.selectFrom(review1) - .innerJoin(review1.storeId, store) - .on(review1.storeId.id.eq(store.id)) + // TODO 쿼리문 개선하기 + return queryFactory.selectFrom(review) + .innerJoin(review.storeId, store) + .on(review.storeId.id.eq(store.id)) .where(builder) - .orderBy(review1.createdAt.desc()) + .orderBy(review.createdAt.desc()) .limit(limit) .fetch(); } diff --git a/src/main/java/com/mpnp/baechelin/store/controller/StoreController.java b/src/main/java/com/mpnp/baechelin/store/controller/StoreController.java index 8391320..26d4c1a 100644 --- a/src/main/java/com/mpnp/baechelin/store/controller/StoreController.java +++ b/src/main/java/com/mpnp/baechelin/store/controller/StoreController.java @@ -43,26 +43,22 @@ public List getStoreInRange(@RequestParam(required = false) Bi } @GetMapping("/point") - public List getStoreInRangeHighPoint(@RequestParam(required = false) BigDecimal latStart, - @RequestParam(required = false) BigDecimal latEnd, - @RequestParam(required = false) BigDecimal lngStart, - @RequestParam(required = false) BigDecimal lngEnd, + public List getStoreInRangeHighPoint(@RequestParam(required = false) BigDecimal lat, + @RequestParam(required = false) BigDecimal lng, @RequestParam(required = false) String category, @RequestParam(required = false) List facility, @PageableDefault Pageable pageable) { - List betweenLngLat = storeQueryRepository.findStoreOrderByPoint(latStart, latEnd, lngStart, lngEnd, category, facility, pageable); + List betweenLngLat = storeQueryRepository.findStoreOrderByPoint(lat, lng, category, facility, pageable); return betweenLngLat.parallelStream().map(storeService::storeToResDto).collect(Collectors.toList());// 순서보장 } @GetMapping("/bookmark") - public List getStoreInRangeHighBookmark(@RequestParam(required = false) BigDecimal latStart, - @RequestParam(required = false) BigDecimal latEnd, - @RequestParam(required = false) BigDecimal lngStart, - @RequestParam(required = false) BigDecimal lngEnd, + public List getStoreInRangeHighBookmark(@RequestParam(required = false) BigDecimal lat, + @RequestParam(required = false) BigDecimal lng, @RequestParam(required = false) String category, @RequestParam(required = false) List facility, @RequestParam int limit) { - List betweenLngLat = storeQueryRepository.findStoreOrderByBookmark(latStart, latEnd, lngStart, lngEnd, category, facility, limit); + List betweenLngLat = storeQueryRepository.findStoreOrderByBookmark(lat, lng, category, facility, limit); return betweenLngLat.parallelStream().map(storeService::storeToResDto).collect(Collectors.toList());// 순서보장 } } diff --git a/src/main/java/com/mpnp/baechelin/store/dto/StoreCardDto.java b/src/main/java/com/mpnp/baechelin/store/dto/StoreCardDto.java new file mode 100644 index 0000000..2328675 --- /dev/null +++ b/src/main/java/com/mpnp/baechelin/store/dto/StoreCardDto.java @@ -0,0 +1,69 @@ +package com.mpnp.baechelin.store.dto; + +import com.mpnp.baechelin.review.domain.Review; +import com.mpnp.baechelin.review.dto.ReviewImageResponseDto; +import com.mpnp.baechelin.review.dto.ReviewResponseDto; +import com.mpnp.baechelin.store.domain.Store; +import com.mpnp.baechelin.user.domain.User; +import lombok.*; +import lombok.extern.slf4j.Slf4j; + +import java.math.BigDecimal; +import java.util.List; +import java.util.stream.Collectors; + +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PACKAGE) +@Getter +@Setter +@Builder +@Slf4j +public class StoreCardDto implements Comparable { + private int storeId; + private String category; + private String name; + private BigDecimal latitude; + private BigDecimal longitude; + private String address; + private String elevator; + private String toilet; + private String parking; + private String phoneNumber; + private String heightDifferent; + private String approach; + private List storeImgList; + private boolean bookmark; + + @Builder.Default + private double pointAvg = 0.0; + + @Override + public int compareTo(StoreCardDto sad) { + if (this.pointAvg > sad.pointAvg) { + return 1; + } else if (this.pointAvg < sad.pointAvg) { + return -1; + } + return 0; + } + + + public StoreCardDto(Store store, User user) { + this.storeId = store.getId(); + this.category = store.getCategory(); + this.name = store.getName(); + this.latitude = store.getLatitude(); + this.longitude = store.getLongitude(); + this.address = store.getAddress(); + this.elevator = store.getElevator(); + this.toilet = store.getToilet(); + this.parking = store.getParking(); + this.phoneNumber = store.getPhoneNumber(); + this.heightDifferent = store.getHeightDifferent(); + this.approach = store.getApproach(); + this.storeImgList = store.getStoreImageList().parallelStream().map(StoreImgResponseDto::new).collect(Collectors.toList()); + this.pointAvg =Double.parseDouble(String.format(store.getReviewList().stream() + .collect(Collectors.averagingDouble(Review::getPoint)).toString(), 0.1f)); + this.bookmark = true; + } +} diff --git a/src/main/java/com/mpnp/baechelin/store/dto/StoreImgResponseDto.java b/src/main/java/com/mpnp/baechelin/store/dto/StoreImgResponseDto.java index 8ebe241..2eb5123 100644 --- a/src/main/java/com/mpnp/baechelin/store/dto/StoreImgResponseDto.java +++ b/src/main/java/com/mpnp/baechelin/store/dto/StoreImgResponseDto.java @@ -1,11 +1,14 @@ package com.mpnp.baechelin.store.dto; +import com.mpnp.baechelin.store.domain.StoreImage; import lombok.Getter; @Getter public class StoreImgResponseDto { private String storeImageUrl; - + public StoreImgResponseDto(StoreImage storeImage){ + this.storeImageUrl = storeImage.getStoreImageUrl(); + } public StoreImgResponseDto(String storeImageUrl) { this.storeImageUrl = storeImageUrl; } diff --git a/src/main/java/com/mpnp/baechelin/store/repository/StoreQueryRepository.java b/src/main/java/com/mpnp/baechelin/store/repository/StoreQueryRepository.java index 475bee8..7846453 100644 --- a/src/main/java/com/mpnp/baechelin/store/repository/StoreQueryRepository.java +++ b/src/main/java/com/mpnp/baechelin/store/repository/StoreQueryRepository.java @@ -1,24 +1,28 @@ package com.mpnp.baechelin.store.repository; -import com.mpnp.baechelin.config.QuerydslConfig; import com.mpnp.baechelin.store.domain.Store; +import com.mpnp.baechelin.store.dto.StoreResponseDto; import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.core.types.dsl.StringPath; import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport; import org.springframework.stereotype.Repository; import javax.transaction.Transactional; import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.List; +import java.util.stream.Collectors; import static com.mpnp.baechelin.config.QuerydslConfig.locationBuilder; import static com.mpnp.baechelin.store.domain.QStore.store; @Repository @Transactional +@Slf4j public class StoreQueryRepository extends QuerydslRepositorySupport { private final JPAQueryFactory queryFactory; @@ -37,52 +41,70 @@ public List findBetweenLngLat(BigDecimal latStart, Pageable pageable) { BooleanBuilder builder = locAndConditions(latStart, latEnd, lngStart, lngEnd, category, facility); - - return queryFactory.selectFrom(store) + BigDecimal nowLat = (latStart.add(latEnd)).divide(new BigDecimal("2"), 22, RoundingMode.HALF_UP); + BigDecimal nowLng = (lngStart.add(lngEnd)).divide(new BigDecimal("2"), 22, RoundingMode.HALF_UP); + List storeResultList = queryFactory.selectFrom(store) .where(builder) - .limit(pageable.getPageSize()) - .offset(pageable.getOffset()) .fetch(); + // 가까운순으로 정렬하기 + storeResultList.sort((thisStore, newStore) -> { + BigDecimal thisDiff = nowLat.subtract(thisStore.getLatitude()).abs().add(nowLng.subtract(thisStore.getLongitude()).abs()); + BigDecimal newDiff = nowLat.subtract(newStore.getLatitude()).abs().add(nowLng.subtract(newStore.getLongitude()).abs()); + return thisDiff.compareTo(newDiff); + }); + // 총 페이지 개수 * 시작 페이지 = 시작 페이지 + getStorePaged(storeResultList, pageable); + return storeResultList; +// 업데이트 쿼리 +// return queryFactory.selectFrom(store) +// .where(builder) +// .limit(pageable.getPageSize()) +// .offset(pageable.getOffset()) +// .fetch(); } - //TODO 별점순 - public List findStoreOrderByPoint(BigDecimal latStart, - BigDecimal latEnd, - BigDecimal lngStart, - BigDecimal lngEnd, + //TODO 별점순 - 쿼리 결과로 산출된 리스트의 평균 구하기, 정렬, 페이징 + public List findStoreOrderByPoint(BigDecimal lat, + BigDecimal lng, String category, List facility, Pageable pageable) { - BooleanBuilder builder = locAndConditions(latStart, latEnd, lngStart, lngEnd, category, facility); + BooleanBuilder builder = locTwoPointAndConditions(lat, lng, category, facility); - return queryFactory.selectFrom(store) + List resultList = queryFactory.selectFrom(store) .where(builder) - .limit(pageable.getPageSize()) - .offset(pageable.getOffset()) - .orderBy(store.pointAvg.desc()) .fetch(); + + List resultAvgList = resultList.stream().sorted() + .map(StoreResponseDto::new).collect(Collectors.toList()); + + getStorePaged(resultAvgList, pageable); + + +// return queryFactory.selectFrom(store) +// .where(builder) +// .limit(pageable.getPageSize()) +// .offset(pageable.getOffset()) +// .orderBy(store.pointAvg.desc()) +// .fetch(); } //TODO 북마크순 - public List findStoreOrderByBookmark(BigDecimal latStart, - BigDecimal latEnd, - BigDecimal lngStart, - BigDecimal lngEnd, + public List findStoreOrderByBookmark(BigDecimal lat, + BigDecimal lng, String category, List facility, int limit) { - BooleanBuilder builder = locAndConditions(latStart, latEnd, lngStart, lngEnd, category, facility); - + BooleanBuilder builder = locTwoPointAndConditions(lat, lng, category, facility); return queryFactory.selectFrom(store) .where(builder) .orderBy(store.bookMarkCount.desc()) .limit(limit) .fetch(); - } private BooleanExpression facilityTF(String facility) { @@ -99,12 +121,27 @@ private StringPath givePath(String dbFacility) { return store.parking; if (dbFacility.equals("approach")) return store.approach; - else + if (dbFacility.equals("toilet")) return store.toilet; + throw new IllegalArgumentException("배리어 프리 태그를 확인해주세요"); } private BooleanBuilder locAndConditions(BigDecimal latStart, BigDecimal latEnd, BigDecimal lngStart, BigDecimal lngEnd, String category, List facility) { BooleanBuilder builder = locationBuilder(latStart, latEnd, lngStart, lngEnd); + return getBooleanBuilder(category, facility, builder); + } + + + private BooleanBuilder locTwoPointAndConditions(BigDecimal latitude, BigDecimal longitude, String category, List facility) { + BooleanBuilder builder = new BooleanBuilder(); + if (latitude != null && longitude != null) { + BigDecimal[] location = getRange(latitude, longitude, 20); + builder = locationBuilder(location[0], location[1], location[2], location[3]); + } + return getBooleanBuilder(category, facility, builder); + } + + private BooleanBuilder getBooleanBuilder(String category, List facility, BooleanBuilder builder) { builder.and(category == null ? null : store.category.eq(category)); if (facility != null && facility.size() > 0) { for (String fac : facility) { @@ -113,4 +150,26 @@ private BooleanBuilder locAndConditions(BigDecimal latStart, BigDecimal latEnd, } return builder; } + + private BigDecimal[] getRange(BigDecimal lat, BigDecimal lng, int km) { + // km->lat,lng로 변환하기 + final BigDecimal latitude = BigDecimal.valueOf(km / 110.569); // 반경 + final BigDecimal longitude = BigDecimal.valueOf(km / 111.322); + // 남서, 북동으로 받아오기 + // start lat-lng, end lat-lng으로 Array 받아오기 + return new BigDecimal[]{lat.subtract(latitude), lat.add(latitude), + lng.subtract(longitude), lng.add(longitude)}; + } + + private void getStorePaged(List storeResultList, Pageable pageable) { + int pageStartIndex = Long.valueOf(storeResultList.size() / pageable.getPageSize() * pageable.getOffset()).intValue(); + + // index 처리하기 + int start = 0, end = storeResultList.size(); + start = Math.max(start, pageStartIndex); + end = Math.min(end, pageStartIndex + pageable.getPageSize() - 1); + + storeResultList = storeResultList.subList(start, end); + } + }