diff --git a/gusto/.idea/uiDesigner.xml b/gusto/.idea/uiDesigner.xml
new file mode 100644
index 000000000..2b63946d5
--- /dev/null
+++ b/gusto/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/gusto/src/main/java/com/umc/gusto/GustoApplication.java b/gusto/src/main/java/com/umc/gusto/GustoApplication.java
index a2c8fd69e..2293b6ac7 100644
--- a/gusto/src/main/java/com/umc/gusto/GustoApplication.java
+++ b/gusto/src/main/java/com/umc/gusto/GustoApplication.java
@@ -3,8 +3,10 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+import org.springframework.scheduling.annotation.EnableScheduling;
@EnableJpaAuditing
+@EnableScheduling
@SpringBootApplication
public class GustoApplication {
diff --git a/gusto/src/main/java/com/umc/gusto/domain/group/service/GroupServiceImpl.java b/gusto/src/main/java/com/umc/gusto/domain/group/service/GroupServiceImpl.java
index 798abf885..d1681a7bc 100644
--- a/gusto/src/main/java/com/umc/gusto/domain/group/service/GroupServiceImpl.java
+++ b/gusto/src/main/java/com/umc/gusto/domain/group/service/GroupServiceImpl.java
@@ -360,13 +360,11 @@ public PagingResponse getAllGroupList(Long groupId, Long groupListId) {
// 그룹 리스트에 해당하는 각 상점 정보 조회
List list = groupLists.stream().map(gl -> {
- Optional topReviewOptional = reviewRepository.findFirstByStoreOrderByLikedDesc(gl.getStore()); // 가장 좋아요가 많은 review
- String reviewImg = topReviewOptional.map(Review::getImg1).orElse("");
return GroupListResponse.builder()
.groupListId(gl.getGroupListId())
.storeId(gl.getStore().getStoreId())
.storeName(gl.getStore().getStoreName())
- .storeProfileImg(reviewImg)
+ .storeProfileImg(gl.getStore().getImg1() != null ? gl.getStore().getImg1() : "")
.userProfileImg(gl.getUser().getProfileImage())
.address(gl.getStore().getAddress())
.build();
diff --git a/gusto/src/main/java/com/umc/gusto/domain/myCategory/model/response/PinByMyCategoryResponse.java b/gusto/src/main/java/com/umc/gusto/domain/myCategory/model/response/PinByMyCategoryResponse.java
index d49d8808d..2789b3be7 100644
--- a/gusto/src/main/java/com/umc/gusto/domain/myCategory/model/response/PinByMyCategoryResponse.java
+++ b/gusto/src/main/java/com/umc/gusto/domain/myCategory/model/response/PinByMyCategoryResponse.java
@@ -5,6 +5,8 @@
import lombok.Getter;
import lombok.NoArgsConstructor;
+import java.util.List;
+
@Builder
@Getter
@NoArgsConstructor
@@ -14,6 +16,9 @@ public class PinByMyCategoryResponse{
Long storeId;
String storeName;
String address;
- String reviewImg;
+ List reviewImg3;
+ String img1;
+ String img2;
+ String img3;
Integer reviewCnt;
}
\ No newline at end of file
diff --git a/gusto/src/main/java/com/umc/gusto/domain/myCategory/service/MyCategoryServiceImpl.java b/gusto/src/main/java/com/umc/gusto/domain/myCategory/service/MyCategoryServiceImpl.java
index 9dd458aac..b96aed382 100644
--- a/gusto/src/main/java/com/umc/gusto/domain/myCategory/service/MyCategoryServiceImpl.java
+++ b/gusto/src/main/java/com/umc/gusto/domain/myCategory/service/MyCategoryServiceImpl.java
@@ -9,7 +9,6 @@
import com.umc.gusto.domain.myCategory.model.response.PinByMyCategoryResponse;
import com.umc.gusto.domain.myCategory.repository.MyCategoryRepository;
import com.umc.gusto.domain.myCategory.repository.PinRepository;
-import com.umc.gusto.domain.review.entity.Review;
import com.umc.gusto.domain.review.repository.ReviewRepository;
import com.umc.gusto.domain.store.entity.Store;
import com.umc.gusto.domain.user.entity.User;
@@ -20,6 +19,7 @@
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
+import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Service;
@@ -29,6 +29,7 @@
@Service
@RequiredArgsConstructor
+@EnableScheduling
public class MyCategoryServiceImpl implements MyCategoryService {
private final MyCategoryRepository myCategoryRepository;
@@ -163,16 +164,18 @@ public PagingResponse getAllPinByMyCategory(User user, String nickname, Long myC
List result = pinList.stream() // townName을 기준으로 보일 수 있는 store가 포함된 pin만 보이기
.map(pin -> {
Store store = pin.getStore();
- Optional topReviewOptional = reviewRepository.findFirstByStoreOrderByLikedDesc(store); // 가장 좋아요가 많은 review
- String reviewImg = topReviewOptional.map(Review::getImg1).orElse(""); // 가장 좋아요가 많은 review 이미지(TO DO: 3개 출력으로 변경)
- Integer reviewCnt = reviewRepository.countByStoreAndUserNickname(store, finalUser.getNickname()); // 내가 작성한 리뷰의 개수 == 방문 횟수
+ // 가장 좋아요가 많은 review
+
+ Integer reviewCnt = reviewRepository.countByStoreAndUserNickname(store, finalUser.getNickname()); // 내가 작성한 리뷰의 개수 == 방문 횟수
return PinByMyCategoryResponse.builder()
.pinId(pin.getPinId())
.storeId(store.getStoreId())
.storeName(store.getStoreName())
.address(store.getAddress())
- .reviewImg(reviewImg)
+ .img1(store.getImg1() != null ? store.getImg1() : "")
+ .img2(store.getImg2() != null ? store.getImg2() : "")
+ .img3(store.getImg3() != null ? store.getImg3() : "")
.reviewCnt(reviewCnt)
.build();
})
@@ -184,6 +187,7 @@ public PagingResponse getAllPinByMyCategory(User user, String nickname, Long myC
.build();
}
+
@Transactional
public void createMyCategory(User user, CreateMyCategoryRequest createMyCategory) {
// 중복 이름 체크
diff --git a/gusto/src/main/java/com/umc/gusto/domain/review/service/ReviewService.java b/gusto/src/main/java/com/umc/gusto/domain/review/service/ReviewService.java
index cfd7e8134..e9e293f7c 100644
--- a/gusto/src/main/java/com/umc/gusto/domain/review/service/ReviewService.java
+++ b/gusto/src/main/java/com/umc/gusto/domain/review/service/ReviewService.java
@@ -3,6 +3,7 @@
import com.umc.gusto.domain.review.model.request.CreateReviewRequest;
import com.umc.gusto.domain.review.model.request.UpdateReviewRequest;
import com.umc.gusto.domain.review.model.response.ReviewDetailResponse;
+import com.umc.gusto.domain.store.entity.Store;
import com.umc.gusto.domain.user.entity.User;
import org.springframework.web.multipart.MultipartFile;
@@ -16,4 +17,5 @@ public interface ReviewService {
ReviewDetailResponse getReview(Long reviewId);
void likeReview(User user, Long reviewId);
void unlikeReview(User user, Long reviewId);
+ void updateStoreImages(Store store);
}
diff --git a/gusto/src/main/java/com/umc/gusto/domain/review/service/ReviewServiceImpl.java b/gusto/src/main/java/com/umc/gusto/domain/review/service/ReviewServiceImpl.java
index be947273a..6859c14c9 100644
--- a/gusto/src/main/java/com/umc/gusto/domain/review/service/ReviewServiceImpl.java
+++ b/gusto/src/main/java/com/umc/gusto/domain/review/service/ReviewServiceImpl.java
@@ -22,15 +22,17 @@
import com.umc.gusto.global.exception.customException.NotFoundException;
import com.umc.gusto.global.exception.customException.PrivateItemException;
import com.umc.gusto.global.util.S3Service;
-import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
+import org.springframework.transaction.annotation.Propagation;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
@@ -216,4 +218,15 @@ private void updateImages(List images, Review review){
if(imageUrls.size()>3) review.updateImg4(imageUrls.get(3));
}
+ @Transactional(propagation = Propagation.REQUIRES_NEW) // 메소드가 호출될 때마다 새로운 트랜잭션이 시작됨을 의미
+ public void updateStoreImages(Store store) {
+ List top4Reviews = reviewRepository.findFirst4ByStoreOrderByLikedDesc(store);
+ List reviewImages = top4Reviews.stream()
+ .map(Review::getImg1)
+ .collect(Collectors.toList());
+
+ store.updateImages(reviewImages);
+ storeRepository.save(store);
+ }
+
}
diff --git a/gusto/src/main/java/com/umc/gusto/domain/store/entity/Store.java b/gusto/src/main/java/com/umc/gusto/domain/store/entity/Store.java
index 6cdc5cba9..e1a108c87 100644
--- a/gusto/src/main/java/com/umc/gusto/domain/store/entity/Store.java
+++ b/gusto/src/main/java/com/umc/gusto/domain/store/entity/Store.java
@@ -7,6 +7,8 @@
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
+import java.util.List;
+
@Entity
@Getter
@Builder
@@ -58,6 +60,14 @@ public class Store extends BaseTime {
@Column(columnDefinition = "VARCHAR(20)")
private String contact;
+ private String img1;
+
+ private String img2;
+
+ private String img3;
+
+ private String img4;
+
@Builder.Default
@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false, length = 10)
@@ -66,5 +76,22 @@ public class Store extends BaseTime {
public enum StoreStatus {
ACTIVE, INACTIVE, CLOSED
}
+
+ public void updateImages(List reviewImages) {
+ // reviewImages 리스트에서 이미지를 가져와 각 필드에 할당
+ if (!reviewImages.isEmpty()) {
+ this.img1 = reviewImages.get(0);
+ }
+ if (reviewImages.size() > 1) {
+ this.img2 = reviewImages.get(1);
+ }
+ if (reviewImages.size() > 2) {
+ this.img3 = reviewImages.get(2);
+ }
+ if (reviewImages.size() > 3) {
+ this.img4 = reviewImages.get(3);
+ }
+ }
+
}
diff --git a/gusto/src/main/java/com/umc/gusto/domain/store/model/response/GetStoreDetailResponse.java b/gusto/src/main/java/com/umc/gusto/domain/store/model/response/GetStoreDetailResponse.java
index b86c9690e..276bfc6a6 100644
--- a/gusto/src/main/java/com/umc/gusto/domain/store/model/response/GetStoreDetailResponse.java
+++ b/gusto/src/main/java/com/umc/gusto/domain/store/model/response/GetStoreDetailResponse.java
@@ -20,7 +20,10 @@ public class GetStoreDetailResponse{
String storeName;
String address;
Boolean pin; // 찜 여부
- List reviewImg4;
+ String img1;
+ String img2;
+ String img3;
+ String img4;
PagingResponse reviews;
}
diff --git a/gusto/src/main/java/com/umc/gusto/domain/store/model/response/GetStoreInfoResponse.java b/gusto/src/main/java/com/umc/gusto/domain/store/model/response/GetStoreInfoResponse.java
index d7539ba5c..a0982abe6 100644
--- a/gusto/src/main/java/com/umc/gusto/domain/store/model/response/GetStoreInfoResponse.java
+++ b/gusto/src/main/java/com/umc/gusto/domain/store/model/response/GetStoreInfoResponse.java
@@ -14,5 +14,5 @@ public class GetStoreInfoResponse {
String categoryString;
String storeName;
String address;
- String reviewImg;
+ String img1;
}
\ No newline at end of file
diff --git a/gusto/src/main/java/com/umc/gusto/domain/store/model/response/GetStoreResponse.java b/gusto/src/main/java/com/umc/gusto/domain/store/model/response/GetStoreResponse.java
index f84760437..e217f367b 100644
--- a/gusto/src/main/java/com/umc/gusto/domain/store/model/response/GetStoreResponse.java
+++ b/gusto/src/main/java/com/umc/gusto/domain/store/model/response/GetStoreResponse.java
@@ -25,7 +25,9 @@ public class GetStoreResponse{
Double latitude;
Map businessDay;
String contact;
- List reviewImg3;
+ String img1;
+ String img2;
+ String img3;
Boolean pin; // 찜 여부
// 하루 영업 시간을 나타내는 내부 클래스
diff --git a/gusto/src/main/java/com/umc/gusto/domain/store/service/StoreServiceImpl.java b/gusto/src/main/java/com/umc/gusto/domain/store/service/StoreServiceImpl.java
index ee83a0990..ea4239e9a 100644
--- a/gusto/src/main/java/com/umc/gusto/domain/store/service/StoreServiceImpl.java
+++ b/gusto/src/main/java/com/umc/gusto/domain/store/service/StoreServiceImpl.java
@@ -4,6 +4,7 @@
import com.umc.gusto.domain.myCategory.repository.PinRepository;
import com.umc.gusto.domain.review.entity.Review;
import com.umc.gusto.domain.review.repository.ReviewRepository;
+import com.umc.gusto.domain.review.service.ReviewService;
import com.umc.gusto.domain.store.entity.OpeningHours;
import com.umc.gusto.domain.store.entity.Store;
import com.umc.gusto.domain.store.model.response.*;
@@ -15,7 +16,7 @@
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.PageRequest;
+import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -30,6 +31,8 @@ public class StoreServiceImpl implements StoreService{
private final ReviewRepository reviewRepository;
private final PinRepository pinRepository;
private final OpeningHoursRepository openingHoursRepository;
+ private final ReviewService reviewService;
+
private static final int PAGE_SIZE_FIRST = 3;
private static final int PAGE_SIZE = 6;
@@ -50,12 +53,6 @@ public List getStores(User user, List storeIds) {
);
businessDays.put(openingHours.getBusinessDay(), timing);
}
-
- List top3Reviews = reviewRepository.findFirst3ByStoreOrderByLikedDesc(store);
-
- List reviewImg = top3Reviews.stream()
- .map(review -> Optional.ofNullable(review.getImg1()).orElse(""))
- .collect(Collectors.toList());
boolean isPinned = pinRepository.existsByUserAndStoreStoreId(user, storeId);
@@ -67,7 +64,9 @@ public List getStores(User user, List storeIds) {
.longitude(store.getLongitude())
.latitude(store.getLatitude())
.businessDay(businessDays)
- .reviewImg3(reviewImg)
+ .img1(store.getImg1() != null ? store.getImg1() : "")
+ .img2(store.getImg2() != null ? store.getImg2() : "")
+ .img3(store.getImg3() != null ? store.getImg3() : "")
.pin(isPinned)
.build());
}
@@ -85,11 +84,7 @@ public GetStoreDetailResponse getStoreDetail(User user, Long storeId, LocalDate
// .orElseThrow(() -> new GeneralException(Code.CATEGORY_NOT_FOUND));
Long pinId = pinRepository.findByUserAndStoreStoreId(user, storeId);
- List top4Reviews = reviewRepository.findFirst4ByStoreOrderByLikedDesc(store);
- List reviewImg = top4Reviews.stream()
- .map(review -> Optional.ofNullable(review.getImg1()).orElse(""))
- .collect(Collectors.toList());
// reviews 페이징 처리 (3,6,6...)
int pageSize;
@@ -113,10 +108,10 @@ public GetStoreDetailResponse getStoreDetail(User user, Long storeId, LocalDate
.nickname(reviewer.getNickname())
.liked(review.getLiked())
.comment(review.getComment())
- .img1(review.getImg1())
- .img2(review.getImg2())
- .img3(review.getImg3())
- .img4(review.getImg4())
+ .img1(review.getImg1() != null ? review.getImg1() : "")
+ .img2(review.getImg2() != null ? review.getImg2() : "")
+ .img3(review.getImg3() != null ? review.getImg1() : "")
+ .img4(review.getImg4() != null ? review.getImg1() : "")
.build();
})
.toList();
@@ -129,7 +124,10 @@ public GetStoreDetailResponse getStoreDetail(User user, Long storeId, LocalDate
.categoryString(store.getCategoryString())
.storeName(store.getStoreName())
.address(store.getAddress())
- .reviewImg4(reviewImg)
+ .img1(store.getImg1() != null ? store.getImg1() : "")
+ .img2(store.getImg2() != null ? store.getImg2() : "")
+ .img3(store.getImg3() != null ? store.getImg3() : "")
+ .img4(store.getImg4() != null ? store.getImg4() : "")
.pin(isPinned)
.reviews(PagingResponse.builder()
.hasNext(reviews.hasNext())
@@ -183,8 +181,6 @@ public List getPinStoresByCategoryAndLocation(User user, Lo
for (Pin pin : pins){
Store store = pin.getStore();
- Optional topReviewOptional = reviewRepository.findFirstByStoreOrderByLikedDesc(store);
- String reviewImg = topReviewOptional.map(Review::getImg1).orElse("");
boolean hasVisited = reviewRepository.existsByStoreAndUserNickname(store, user.getNickname());
GetStoreInfoResponse getStoreInfoResponse = GetStoreInfoResponse.builder()
@@ -192,7 +188,7 @@ public List getPinStoresByCategoryAndLocation(User user, Lo
.categoryString(store.getCategoryString())
.storeName(store.getStoreName())
.address(store.getAddress())
- .reviewImg(reviewImg)
+ .img1(store.getImg1() != null ? store.getImg1() : "")
.build();
if(!hasVisited){
@@ -230,16 +226,25 @@ public List searchStore(String keyword) {
return searchResult.stream()
.map(result -> {
- Optional review = reviewRepository.findFirstByStoreOrderByLikedDesc(result);
- String reviewImg = review.map(Review::getImg1).orElse("");
return GetStoreInfoResponse.builder()
.storeId(result.getStoreId())
.storeName(result.getStoreName())
.categoryString(result.getCategoryString())
.address(result.getAddress())
- .reviewImg(reviewImg)
+ .img1(result.getImg1() != null ? result.getImg1() : "")
.build();
})
.collect(Collectors.toList());
}
+
+ //
+ @Scheduled(cron = "0 0 0 1,16 * ?")
+ public void updateAllStoreImages() {
+ List stores = storeRepository.findAll();
+
+ for (Store store : stores) {
+ reviewService.updateStoreImages(store);
+ }
+ }
+
}