From e7b87b94f96b2fcb0a2881ad053196f511edde4e Mon Sep 17 00:00:00 2001 From: Kang Duoh Date: Fri, 22 Nov 2024 14:03:05 +0900 Subject: [PATCH 01/12] =?UTF-8?q?=F0=9F=97=83=20Refactor[#16]:=20StoreCate?= =?UTF-8?q?gory=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/groom/swipo/domain/store/entity/Store.java | 11 +++++++++-- .../domain/store/entity/enums/StoreCategory.java | 5 +++++ .../com/groom/swipo/global/config/SecurityConfig.java | 3 ++- 3 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/groom/swipo/domain/store/entity/enums/StoreCategory.java diff --git a/src/main/java/com/groom/swipo/domain/store/entity/Store.java b/src/main/java/com/groom/swipo/domain/store/entity/Store.java index daacdfb..80f4708 100644 --- a/src/main/java/com/groom/swipo/domain/store/entity/Store.java +++ b/src/main/java/com/groom/swipo/domain/store/entity/Store.java @@ -6,6 +6,7 @@ import com.groom.swipo.domain.payment.entity.Paylist; import com.groom.swipo.domain.point.entity.Cardlist; import com.groom.swipo.domain.point.entity.MyPiece; +import com.groom.swipo.domain.store.entity.enums.StoreCategory; import com.groom.swipo.domain.store.entity.enums.StoreType; import com.groom.swipo.global.common.enums.Area; import com.groom.swipo.global.entity.BaseEntity; @@ -38,9 +39,13 @@ public class Store extends BaseEntity { private String name; @Enumerated(EnumType.STRING) - @Column(nullable = false, length = 20) + @Column(nullable = false) private StoreType type; + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private StoreCategory category; + private String address; @Column(nullable = false) @@ -83,9 +88,11 @@ public class Store extends BaseEntity { // 기타 @Builder - private Store(String name, StoreType type, String address, Double latitude, Double longitude, Integer percent) { + private Store(String name, StoreType type, StoreCategory category, String address, Double latitude, + Double longitude, Integer percent) { this.name = name; this.type = type; + this.category = category; this.address = address; this.latitude = latitude; this.longitude = longitude; diff --git a/src/main/java/com/groom/swipo/domain/store/entity/enums/StoreCategory.java b/src/main/java/com/groom/swipo/domain/store/entity/enums/StoreCategory.java new file mode 100644 index 0000000..8787139 --- /dev/null +++ b/src/main/java/com/groom/swipo/domain/store/entity/enums/StoreCategory.java @@ -0,0 +1,5 @@ +package com.groom.swipo.domain.store.entity.enums; + +public enum StoreCategory { + ALL, CAFE, DESSERT, RESTAURANT, MART, PROP, LODGMENT +} diff --git a/src/main/java/com/groom/swipo/global/config/SecurityConfig.java b/src/main/java/com/groom/swipo/global/config/SecurityConfig.java index cb5d3b3..3a5fb6a 100644 --- a/src/main/java/com/groom/swipo/global/config/SecurityConfig.java +++ b/src/main/java/com/groom/swipo/global/config/SecurityConfig.java @@ -24,7 +24,8 @@ public class SecurityConfig { "swagger-ui/**", "v3/api-docs/**", "/v1/**", - "/profile" + "/profile", + "/**" // 테스트용 }; @Bean From 215e59bcbc4d789209ad18ecb5af6af47017d18f Mon Sep 17 00:00:00 2001 From: Kang Duoh Date: Fri, 22 Nov 2024 14:12:07 +0900 Subject: [PATCH 02/12] =?UTF-8?q?=E2=9C=A8=20Feat[#16]:=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=EB=84=A4=EC=9D=B4=EC=85=98=20Dto=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../groom/swipo/global/common/PageInfo.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/main/java/com/groom/swipo/global/common/PageInfo.java diff --git a/src/main/java/com/groom/swipo/global/common/PageInfo.java b/src/main/java/com/groom/swipo/global/common/PageInfo.java new file mode 100644 index 0000000..125b6f3 --- /dev/null +++ b/src/main/java/com/groom/swipo/global/common/PageInfo.java @@ -0,0 +1,20 @@ +package com.groom.swipo.global.common; + +import org.springframework.data.domain.Page; + +import lombok.Builder; + +@Builder +public record PageInfo( + int currentPage, + int totalPages, + long totalItems +) { + public static PageInfo from(Page entityPage) { + return PageInfo.builder() + .currentPage(entityPage.getNumber()) + .totalPages(entityPage.getTotalPages()) + .totalItems(entityPage.getTotalElements()) + .build(); + } +} From 6a9d38c059f2067a9593aba4475929cce0150580 Mon Sep 17 00:00:00 2001 From: Kang Duoh Date: Fri, 22 Nov 2024 18:16:06 +0900 Subject: [PATCH 03/12] =?UTF-8?q?=E2=9C=A8=20Feat[#16]:=20=EA=B0=80?= =?UTF-8?q?=EA=B2=8C=20=EA=B2=80=EC=83=89=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../store/controller/StoreController.java | 13 +++ .../swipo/domain/store/dto/StoreDetail.java | 36 +++++++ .../dto/response/StoreSearchResponse.java | 21 ++++ .../store/entity/enums/StoreCategory.java | 2 +- .../store/repository/StoreRepository.java | 16 +++ .../domain/store/service/StoreService.java | 101 ++++++++++++++++++ 6 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/groom/swipo/domain/store/dto/StoreDetail.java create mode 100644 src/main/java/com/groom/swipo/domain/store/dto/response/StoreSearchResponse.java diff --git a/src/main/java/com/groom/swipo/domain/store/controller/StoreController.java b/src/main/java/com/groom/swipo/domain/store/controller/StoreController.java index de569e2..9d8b0a6 100644 --- a/src/main/java/com/groom/swipo/domain/store/controller/StoreController.java +++ b/src/main/java/com/groom/swipo/domain/store/controller/StoreController.java @@ -14,6 +14,7 @@ import com.groom.swipo.domain.store.dto.response.MapQueryResponse; import com.groom.swipo.domain.store.dto.response.MapStoreDetailResponse; import com.groom.swipo.domain.store.dto.response.MapTabViewResponse; +import com.groom.swipo.domain.store.dto.response.StoreSearchResponse; import com.groom.swipo.domain.store.service.ReviewsService; import com.groom.swipo.domain.store.service.StoreService; import com.groom.swipo.domain.store.service.WishlistService; @@ -125,4 +126,16 @@ public ResTemplate getStoreTabs(Principal principal) { MapTabViewResponse data = storeService.getStoreTabs(principal); return new ResTemplate<>(HttpStatus.OK, "탭별 가게 조회 성공", data); } + + @GetMapping("/search") + public ResTemplate searchStores( + @RequestParam(name = "keyword") String keyword, + @RequestParam(name = "category", defaultValue = "all") String category, + @RequestParam(name = "type") String type, + @RequestParam(name = "page", defaultValue = "0") int page, + Principal principal + ) { + StoreSearchResponse data = storeService.searchStores(keyword, category, type, page, principal); + return new ResTemplate<>(HttpStatus.OK, "가게 검색 성공", data); + } } diff --git a/src/main/java/com/groom/swipo/domain/store/dto/StoreDetail.java b/src/main/java/com/groom/swipo/domain/store/dto/StoreDetail.java new file mode 100644 index 0000000..71f44b4 --- /dev/null +++ b/src/main/java/com/groom/swipo/domain/store/dto/StoreDetail.java @@ -0,0 +1,36 @@ +package com.groom.swipo.domain.store.dto; + +import java.util.List; + +import com.groom.swipo.domain.store.entity.Store; + +import lombok.Builder; + +@Builder +public record StoreDetail( + Long storeId, + String name, + String address, + Integer percent, + Double stars, + boolean isWish, + Integer reviewsNum, + String review, + Integer imagesNum, + List imageUrls +) { + public static StoreDetail of(Store store, Double stars, boolean isWish, String review, List images) { + return StoreDetail.builder() + .storeId(store.getId()) + .name(store.getName()) + .address(store.getAddress()) + .percent(store.getPercent()) + .stars(stars) + .isWish(isWish) + .reviewsNum(store.getReviews().size()) + .review(review) + .imagesNum(images.size()) + .imageUrls(images) + .build(); + } +} diff --git a/src/main/java/com/groom/swipo/domain/store/dto/response/StoreSearchResponse.java b/src/main/java/com/groom/swipo/domain/store/dto/response/StoreSearchResponse.java new file mode 100644 index 0000000..22795ca --- /dev/null +++ b/src/main/java/com/groom/swipo/domain/store/dto/response/StoreSearchResponse.java @@ -0,0 +1,21 @@ +package com.groom.swipo.domain.store.dto.response; + +import java.util.List; + +import com.groom.swipo.domain.store.dto.StoreDetail; +import com.groom.swipo.global.common.PageInfo; + +import lombok.Builder; + +@Builder +public record StoreSearchResponse( + PageInfo pageInfo, + List stores +) { + public static StoreSearchResponse of(PageInfo pageInfo, List stores) { + return StoreSearchResponse.builder() + .pageInfo(pageInfo) + .stores(stores) + .build(); + } +} diff --git a/src/main/java/com/groom/swipo/domain/store/entity/enums/StoreCategory.java b/src/main/java/com/groom/swipo/domain/store/entity/enums/StoreCategory.java index 8787139..dca1855 100644 --- a/src/main/java/com/groom/swipo/domain/store/entity/enums/StoreCategory.java +++ b/src/main/java/com/groom/swipo/domain/store/entity/enums/StoreCategory.java @@ -1,5 +1,5 @@ package com.groom.swipo.domain.store.entity.enums; public enum StoreCategory { - ALL, CAFE, DESSERT, RESTAURANT, MART, PROP, LODGMENT + CAFE, DESSERT, RESTAURANT, MART, PROP, LODGMENT } diff --git a/src/main/java/com/groom/swipo/domain/store/repository/StoreRepository.java b/src/main/java/com/groom/swipo/domain/store/repository/StoreRepository.java index 6b4f6cb..5c184b0 100644 --- a/src/main/java/com/groom/swipo/domain/store/repository/StoreRepository.java +++ b/src/main/java/com/groom/swipo/domain/store/repository/StoreRepository.java @@ -28,4 +28,20 @@ List findStoresWithinRadius( @Param("longitude") double longitude, @Param("radius") double radius ); + + @Query(""" + SELECT s FROM Store s + LEFT JOIN s.wishlists w ON w.isWish = true + GROUP BY s + ORDER BY COUNT(w) DESC + """) + List findPopularStores(); + + @Query(""" + SELECT s FROM Store s + LEFT JOIN s.reviews r + GROUP BY s + ORDER BY COALESCE(AVG(r.star), 0) DESC + """) + List findTopRatedStores(); } diff --git a/src/main/java/com/groom/swipo/domain/store/service/StoreService.java b/src/main/java/com/groom/swipo/domain/store/service/StoreService.java index 9ff4974..b36464e 100644 --- a/src/main/java/com/groom/swipo/domain/store/service/StoreService.java +++ b/src/main/java/com/groom/swipo/domain/store/service/StoreService.java @@ -9,15 +9,18 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import com.groom.swipo.domain.store.dto.StoreDetail; import com.groom.swipo.domain.store.dto.StoreInfo; import com.groom.swipo.domain.store.dto.StoreTabInfo; import com.groom.swipo.domain.store.dto.response.MapQueryResponse; import com.groom.swipo.domain.store.dto.response.MapStoreDetailResponse; import com.groom.swipo.domain.store.dto.response.MapTabViewResponse; +import com.groom.swipo.domain.store.dto.response.StoreSearchResponse; import com.groom.swipo.domain.store.entity.Reviews; import com.groom.swipo.domain.store.entity.Store; import com.groom.swipo.domain.store.entity.StoreImage; import com.groom.swipo.domain.store.entity.Wishlist; +import com.groom.swipo.domain.store.entity.enums.StoreCategory; import com.groom.swipo.domain.store.entity.enums.StoreType; import com.groom.swipo.domain.store.exception.StoreNotFoundException; import com.groom.swipo.domain.store.repository.ReviewsRepository; @@ -27,6 +30,7 @@ import com.groom.swipo.domain.user.entity.User; import com.groom.swipo.domain.user.exception.UserNotFoundException; import com.groom.swipo.domain.user.repository.UserRepository; +import com.groom.swipo.global.common.PageInfo; import lombok.RequiredArgsConstructor; @@ -35,6 +39,8 @@ @Transactional(readOnly = true) public class StoreService { + private static final int PAGE_SIZE = 5; + private final UserRepository userRepository; private final WishilistRepository wishilistRepository; private final StoreRepository storeRepository; @@ -142,4 +148,99 @@ private List limit(List stores, int limit) { .limit(limit) .collect(Collectors.toList()); } + + public StoreSearchResponse searchStores(String keyword, String category, String type, int page, + Principal principal) { + Long userId = Long.parseLong(principal.getName()); + User user = userRepository.findById(userId).orElseThrow(UserNotFoundException::new); + + List stores = storeRepository.findAll(); + stores = filterByKeyword(stores, keyword); + stores = filterByCategory(stores, category); + stores = filterByType(stores, type, user); + + PageInfo pageInfo = PageInfo.builder() + .currentPage(page) + .totalPages((int)Math.ceil((double)stores.size() / PAGE_SIZE)) + .totalItems(stores.size()) + .build(); + + List storeDetails = stores.stream() + .skip((long)page * PAGE_SIZE) + .limit(PAGE_SIZE) + .map(store -> convertToStoreDetail(store, user)) + .toList(); + + return StoreSearchResponse.of(pageInfo, storeDetails); + } + + private List filterByKeyword(List stores, String keyword) { + if (keyword == null || keyword.isBlank()) { + return stores; + } + + return stores.stream() + .filter(store -> store.getName().contains(keyword) || store.getAddress().contains(keyword)) + .toList(); + } + + private List filterByCategory(List stores, String category) { + if (category.equals("all")) { + return stores; + } + + try { + return stores.stream() + .filter(store -> store.getCategory().equals(StoreCategory.valueOf(category.toUpperCase()))) + .toList(); + } catch (IllegalArgumentException e) { + throw new StoreNotFoundException("존재하지 않는 카테고리입니다."); + } + } + + private List filterByType(List stores, String type, User user) { + return switch (type) { + case "pick" -> stores.stream() + .filter(store -> store.getType() == StoreType.PICK) + .toList(); + case "trend" -> stores.stream() + .filter(store -> store.getType() == StoreType.TREND) + .toList(); + case "taste" -> stores.stream() + .filter(store -> store.getType() == StoreType.TASTE) + .toList(); + case "wish" -> stores.stream() + .filter(store -> wishilistRepository.existsByUserAndStoreAndIsWishTrue(user, store)) + .toList(); + case "popular" -> storeRepository.findPopularStores(); + case "star" -> storeRepository.findTopRatedStores(); + case "near" -> stores; + default -> throw new StoreNotFoundException("존재하지 않는 타입입니다."); + }; + } + + private StoreDetail convertToStoreDetail(Store store, User user) { + Double averageStars = store.getReviews().stream() + .mapToDouble(Reviews::getStar) + .average() + .stream() + .map(avg -> Math.round(avg * 10) / 10.0) + .findFirst() + .orElse(0.0); + + String topReview = store.getReviews().stream() + .map(Reviews::getComment) + .findFirst() + .orElse(null); + + List images = store.getStoreImages().stream() + .map(StoreImage::getUrl) + .toList(); + + boolean isWish = wishilistRepository.findByUserAndStore(user, store) + .map(Wishlist::isWish) + .orElse(false); + + return StoreDetail.of(store, averageStars, isWish, topReview, images); + } } From bb321dbd4558fd4cccd229d8efe5102a863c1869 Mon Sep 17 00:00:00 2001 From: Kang Duoh Date: Fri, 22 Nov 2024 18:18:26 +0900 Subject: [PATCH 04/12] =?UTF-8?q?=F0=9F=93=9D=20Docs[#16]:=20=EA=B0=80?= =?UTF-8?q?=EA=B2=8C=20=EA=B2=80=EC=83=89=20API=EC=97=90=20Swagger=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/store/controller/StoreController.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/com/groom/swipo/domain/store/controller/StoreController.java b/src/main/java/com/groom/swipo/domain/store/controller/StoreController.java index 9d8b0a6..3b9d43d 100644 --- a/src/main/java/com/groom/swipo/domain/store/controller/StoreController.java +++ b/src/main/java/com/groom/swipo/domain/store/controller/StoreController.java @@ -128,6 +128,18 @@ public ResTemplate getStoreTabs(Principal principal) { } @GetMapping("/search") + @Operation( + summary = "가게 검색", + description = "키워드, 카테고리, 타입별, 페이지로 필터링된 가게 리스트를 반환합니다.", + responses = { + @ApiResponse(responseCode = "200", description = "가게 검색 성공"), + @ApiResponse(responseCode = "400", description = "잘못된 요청"), + @ApiResponse(responseCode = "401", description = "인증되지 않은 요청"), + @ApiResponse(responseCode = "403", description = "페이지 접근 권한이 없음"), + @ApiResponse(responseCode = "404", description = "요청한 리소스를 찾을 수 없음"), + @ApiResponse(responseCode = "500", description = "서버 오류") + } + ) public ResTemplate searchStores( @RequestParam(name = "keyword") String keyword, @RequestParam(name = "category", defaultValue = "all") String category, From 931083f13205e50e1e75cc440e6bebbc05f3d76e Mon Sep 17 00:00:00 2001 From: Kang Duoh Date: Fri, 22 Nov 2024 18:25:31 +0900 Subject: [PATCH 05/12] =?UTF-8?q?=F0=9F=92=A1=20Docs[#16]:=20searchStores?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EC=A3=BC=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../swipo/domain/store/repository/StoreRepository.java | 2 ++ .../groom/swipo/domain/store/service/StoreService.java | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/src/main/java/com/groom/swipo/domain/store/repository/StoreRepository.java b/src/main/java/com/groom/swipo/domain/store/repository/StoreRepository.java index 5c184b0..bcfee11 100644 --- a/src/main/java/com/groom/swipo/domain/store/repository/StoreRepository.java +++ b/src/main/java/com/groom/swipo/domain/store/repository/StoreRepository.java @@ -29,6 +29,7 @@ List findStoresWithinRadius( @Param("radius") double radius ); + // 관심 등록 수가 많은 순으로 가게 조회 @Query(""" SELECT s FROM Store s LEFT JOIN s.wishlists w ON w.isWish = true @@ -37,6 +38,7 @@ ORDER BY COUNT(w) DESC """) List findPopularStores(); + // 별점 평균이 높은 순으로 가게 조회 @Query(""" SELECT s FROM Store s LEFT JOIN s.reviews r diff --git a/src/main/java/com/groom/swipo/domain/store/service/StoreService.java b/src/main/java/com/groom/swipo/domain/store/service/StoreService.java index b36464e..d102164 100644 --- a/src/main/java/com/groom/swipo/domain/store/service/StoreService.java +++ b/src/main/java/com/groom/swipo/domain/store/service/StoreService.java @@ -155,16 +155,20 @@ public StoreSearchResponse searchStores(String keyword, String category, String User user = userRepository.findById(userId).orElseThrow(UserNotFoundException::new); List stores = storeRepository.findAll(); + + // 필터링: 키워드, 카테고리, 타입 stores = filterByKeyword(stores, keyword); stores = filterByCategory(stores, category); stores = filterByType(stores, type, user); + // 페이지 정보 생성 PageInfo pageInfo = PageInfo.builder() .currentPage(page) .totalPages((int)Math.ceil((double)stores.size() / PAGE_SIZE)) .totalItems(stores.size()) .build(); + // 현재 페이지에 해당하는 데이터로 변환 List storeDetails = stores.stream() .skip((long)page * PAGE_SIZE) .limit(PAGE_SIZE) @@ -174,6 +178,7 @@ public StoreSearchResponse searchStores(String keyword, String category, String return StoreSearchResponse.of(pageInfo, storeDetails); } + // 키워드 필터링: 가게명이나 주소에 키워드 포함 여부 private List filterByKeyword(List stores, String keyword) { if (keyword == null || keyword.isBlank()) { return stores; @@ -184,6 +189,7 @@ private List filterByKeyword(List stores, String keyword) { .toList(); } + // 카테고리 필터링: 카테고리가 존재하지 않으면 예외 발생 private List filterByCategory(List stores, String category) { if (category.equals("all")) { return stores; @@ -198,6 +204,7 @@ private List filterByCategory(List stores, String category) { } } + // 타입 필터링: 거리순 로직 개발 필요 private List filterByType(List stores, String type, User user) { return switch (type) { case "pick" -> stores.stream() @@ -219,6 +226,7 @@ private List filterByType(List stores, String type, User user) { }; } + // Store 데이터를 StoreDetail로 변환 private StoreDetail convertToStoreDetail(Store store, User user) { Double averageStars = store.getReviews().stream() .mapToDouble(Reviews::getStar) From 73bb5d249822c8896b4f3faa643335321a733050 Mon Sep 17 00:00:00 2001 From: Kang Duoh Date: Fri, 22 Nov 2024 18:28:05 +0900 Subject: [PATCH 06/12] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor[#21]:=20?= =?UTF-8?q?=EC=A0=95=EC=A0=81=20=ED=8C=A9=ED=86=A0=EB=A6=AC=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/groom/swipo/domain/point/dto/PieceInfo.java | 2 +- .../com/groom/swipo/domain/point/service/PointService.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/groom/swipo/domain/point/dto/PieceInfo.java b/src/main/java/com/groom/swipo/domain/point/dto/PieceInfo.java index b8617f3..edd1719 100644 --- a/src/main/java/com/groom/swipo/domain/point/dto/PieceInfo.java +++ b/src/main/java/com/groom/swipo/domain/point/dto/PieceInfo.java @@ -10,7 +10,7 @@ public record PieceInfo( String myPieceId, String pieceName ) { - public static PieceInfo from(MyPiece myPiece,Piece piece) { + public static PieceInfo of(MyPiece myPiece,Piece piece) { return PieceInfo.builder() .myPieceId(String.valueOf(myPiece.getId())) .pieceName(piece.getName()) diff --git a/src/main/java/com/groom/swipo/domain/point/service/PointService.java b/src/main/java/com/groom/swipo/domain/point/service/PointService.java index 162ddcb..ec8953b 100644 --- a/src/main/java/com/groom/swipo/domain/point/service/PointService.java +++ b/src/main/java/com/groom/swipo/domain/point/service/PointService.java @@ -41,7 +41,7 @@ public SwipstoneResponse getSwipstone(Principal principal) { } List pieces = myPieces.stream() - .map(myPiece -> PieceInfo.from(myPiece, myPiece.getPiece())) + .map(myPiece -> PieceInfo.of(myPiece, myPiece.getPiece())) .toList(); Integer piecesNum = pieces.size(); @@ -71,4 +71,4 @@ public SwipstoneSwapResponse swapSwipstone(SwipstoneSwapRequest request, Princip return new SwipstoneSwapResponse(pay.getTotalPay()); } -} \ No newline at end of file +} From 2618528834a7083d4c2792679ea74d5b9180c4c3 Mon Sep 17 00:00:00 2001 From: Kang Duoh Date: Fri, 22 Nov 2024 18:34:50 +0900 Subject: [PATCH 07/12] =?UTF-8?q?=E2=9C=85=20Test[#10]:=20Swagger=20?= =?UTF-8?q?=EC=9D=B8=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/groom/swipo/global/config/SwaggerConfig.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/com/groom/swipo/global/config/SwaggerConfig.java b/src/main/java/com/groom/swipo/global/config/SwaggerConfig.java index 064ea1c..0e05407 100644 --- a/src/main/java/com/groom/swipo/global/config/SwaggerConfig.java +++ b/src/main/java/com/groom/swipo/global/config/SwaggerConfig.java @@ -6,8 +6,11 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; import io.swagger.v3.oas.models.servers.Server; @Configuration @@ -28,6 +31,8 @@ private Info apiInfo() { @Bean public OpenAPI openAPI() { + String authHeader = "Authorization"; + Server localServer = new Server(); localServer.description("Local Server") .url(localUrl); @@ -38,6 +43,13 @@ public OpenAPI openAPI() { return new OpenAPI() .info(apiInfo()) + .addSecurityItem(new SecurityRequirement().addList(authHeader)) + .components(new Components() + .addSecuritySchemes(authHeader, new SecurityScheme() + .name(authHeader) + .type(SecurityScheme.Type.HTTP) + .scheme("Bearer") + .bearerFormat("accessToken"))) .servers(Arrays.asList(localServer, prodServer)); } } From d1a61531c568f63b4769c044c4345851f58b71d4 Mon Sep 17 00:00:00 2001 From: Kang Duoh Date: Fri, 22 Nov 2024 18:36:16 +0900 Subject: [PATCH 08/12] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor[#10]:=20?= =?UTF-8?q?=EC=84=9C=EB=B2=84=20Url=20=EC=88=9C=EC=84=9C=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/groom/swipo/global/config/SwaggerConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/groom/swipo/global/config/SwaggerConfig.java b/src/main/java/com/groom/swipo/global/config/SwaggerConfig.java index 0e05407..c5a313b 100644 --- a/src/main/java/com/groom/swipo/global/config/SwaggerConfig.java +++ b/src/main/java/com/groom/swipo/global/config/SwaggerConfig.java @@ -50,6 +50,6 @@ public OpenAPI openAPI() { .type(SecurityScheme.Type.HTTP) .scheme("Bearer") .bearerFormat("accessToken"))) - .servers(Arrays.asList(localServer, prodServer)); + .servers(Arrays.asList(prodServer, localServer)); } } From dd86a7653096753ff309cf13b9f5261f2d4456d7 Mon Sep 17 00:00:00 2001 From: Kang Duoh Date: Fri, 22 Nov 2024 18:41:17 +0900 Subject: [PATCH 09/12] =?UTF-8?q?=F0=9F=94=A5=20Remove[#9]:=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 --- 1 file changed, 3 deletions(-) diff --git a/build.gradle b/build.gradle index 12c36d8..88f7b9d 100644 --- a/build.gradle +++ b/build.gradle @@ -49,9 +49,6 @@ dependencies { // iamport implementation 'com.github.iamport:iamport-rest-client-java:0.1.6' - // spring security - implementation("org.springframework.boot:spring-boot-starter-security") - // 휴대폰 인증 API (nurigo) implementation 'net.nurigo:sdk:4.3.0' } From 80d8633214b4bb0a4816681ff938fa76946d9cca Mon Sep 17 00:00:00 2001 From: Kang Duoh Date: Fri, 22 Nov 2024 18:49:35 +0900 Subject: [PATCH 10/12] =?UTF-8?q?=F0=9F=94=A5=20Remove[#16]:=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EB=90=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20import=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/groom/swipo/domain/auth/util/JwtValidator.java | 1 - .../com/groom/swipo/domain/payment/entity/Paylist.java | 9 ++++----- .../com/groom/swipo/domain/point/entity/Cardlist.java | 5 +---- .../swipo/domain/point/repository/MyPieceRepository.java | 1 - .../groom/swipo/domain/user/entity/VerificationCode.java | 3 +-- .../user/repository/VerificationCodeRepository.java | 4 +--- 6 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/groom/swipo/domain/auth/util/JwtValidator.java b/src/main/java/com/groom/swipo/domain/auth/util/JwtValidator.java index 6bbd6aa..85d44e4 100644 --- a/src/main/java/com/groom/swipo/domain/auth/util/JwtValidator.java +++ b/src/main/java/com/groom/swipo/domain/auth/util/JwtValidator.java @@ -13,7 +13,6 @@ import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; -import lombok.RequiredArgsConstructor; // 해당 코드는 Jwt 전체에 대해 검증하는 것이 아닌 애플 로그인떄 받아오는 itentity token 검증용 @Component diff --git a/src/main/java/com/groom/swipo/domain/payment/entity/Paylist.java b/src/main/java/com/groom/swipo/domain/payment/entity/Paylist.java index 6cc26ae..cdca7f6 100644 --- a/src/main/java/com/groom/swipo/domain/payment/entity/Paylist.java +++ b/src/main/java/com/groom/swipo/domain/payment/entity/Paylist.java @@ -1,13 +1,10 @@ package com.groom.swipo.domain.payment.entity; import com.groom.swipo.domain.store.entity.Store; -import com.groom.swipo.global.common.enums.Area; import com.groom.swipo.global.entity.BaseEntity; import jakarta.persistence.Column; import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; @@ -42,7 +39,9 @@ public class Paylist extends BaseEntity { private Store store; @Builder - private Paylist(long value) { + private Paylist(long value, Pay pay, Store store) { this.value = value; + this.pay = pay; + this.store = store; } -} \ No newline at end of file +} diff --git a/src/main/java/com/groom/swipo/domain/point/entity/Cardlist.java b/src/main/java/com/groom/swipo/domain/point/entity/Cardlist.java index a064493..2a5c996 100644 --- a/src/main/java/com/groom/swipo/domain/point/entity/Cardlist.java +++ b/src/main/java/com/groom/swipo/domain/point/entity/Cardlist.java @@ -1,13 +1,10 @@ package com.groom.swipo.domain.point.entity; import com.groom.swipo.domain.store.entity.Store; -import com.groom.swipo.global.common.enums.Area; import com.groom.swipo.global.entity.BaseEntity; import jakarta.persistence.Column; import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; @@ -45,4 +42,4 @@ public class Cardlist extends BaseEntity { private Cardlist(long value) { this.value = value; } -} \ No newline at end of file +} diff --git a/src/main/java/com/groom/swipo/domain/point/repository/MyPieceRepository.java b/src/main/java/com/groom/swipo/domain/point/repository/MyPieceRepository.java index 73d01e5..33c736c 100644 --- a/src/main/java/com/groom/swipo/domain/point/repository/MyPieceRepository.java +++ b/src/main/java/com/groom/swipo/domain/point/repository/MyPieceRepository.java @@ -5,7 +5,6 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import com.groom.swipo.domain.point.dto.PieceInfo; import com.groom.swipo.domain.point.entity.MyPiece; import com.groom.swipo.domain.user.entity.User; diff --git a/src/main/java/com/groom/swipo/domain/user/entity/VerificationCode.java b/src/main/java/com/groom/swipo/domain/user/entity/VerificationCode.java index 48f7d45..3f68ce4 100644 --- a/src/main/java/com/groom/swipo/domain/user/entity/VerificationCode.java +++ b/src/main/java/com/groom/swipo/domain/user/entity/VerificationCode.java @@ -1,7 +1,6 @@ package com.groom.swipo.domain.user.entity; import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; import com.groom.swipo.global.entity.BaseEntity; @@ -50,4 +49,4 @@ public String generateCodeMessage() { code ); } -} \ No newline at end of file +} diff --git a/src/main/java/com/groom/swipo/domain/user/repository/VerificationCodeRepository.java b/src/main/java/com/groom/swipo/domain/user/repository/VerificationCodeRepository.java index b0c7ff6..d6fc4d2 100644 --- a/src/main/java/com/groom/swipo/domain/user/repository/VerificationCodeRepository.java +++ b/src/main/java/com/groom/swipo/domain/user/repository/VerificationCodeRepository.java @@ -1,7 +1,5 @@ package com.groom.swipo.domain.user.repository; -import java.util.Optional; - import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @@ -9,4 +7,4 @@ @Repository public interface VerificationCodeRepository extends JpaRepository { -} \ No newline at end of file +} From 8cb1b30617b29c9984a4335927811d16264b7414 Mon Sep 17 00:00:00 2001 From: Kang Duoh Date: Fri, 22 Nov 2024 19:03:40 +0900 Subject: [PATCH 11/12] =?UTF-8?q?=E2=9C=A8=20Feat[#12]:=20=EA=B2=B0?= =?UTF-8?q?=EC=A0=9C=EB=82=B4=EC=97=AD=20=EC=A0=80=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../payment/dto/request/PaymentCompleteRequest.java | 11 +++++++++++ .../swipo/domain/payment/service/PaymentService.java | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/src/main/java/com/groom/swipo/domain/payment/dto/request/PaymentCompleteRequest.java b/src/main/java/com/groom/swipo/domain/payment/dto/request/PaymentCompleteRequest.java index e30ac56..bd19509 100644 --- a/src/main/java/com/groom/swipo/domain/payment/dto/request/PaymentCompleteRequest.java +++ b/src/main/java/com/groom/swipo/domain/payment/dto/request/PaymentCompleteRequest.java @@ -1,9 +1,20 @@ package com.groom.swipo.domain.payment.dto.request; +import com.groom.swipo.domain.payment.entity.Pay; +import com.groom.swipo.domain.payment.entity.Paylist; +import com.groom.swipo.domain.store.entity.Store; + public record PaymentCompleteRequest( Long storeId, String password, Integer amount, Integer usedPoints ) { + public Paylist toEntity(Pay pay, Store store) { + return Paylist.builder() + .value(amount - usedPoints) + .pay(pay) + .store(store) + .build(); + } } diff --git a/src/main/java/com/groom/swipo/domain/payment/service/PaymentService.java b/src/main/java/com/groom/swipo/domain/payment/service/PaymentService.java index 34e84d4..b352800 100644 --- a/src/main/java/com/groom/swipo/domain/payment/service/PaymentService.java +++ b/src/main/java/com/groom/swipo/domain/payment/service/PaymentService.java @@ -8,6 +8,7 @@ import com.groom.swipo.domain.payment.dto.request.PaymentCompleteRequest; import com.groom.swipo.domain.payment.dto.response.PaymentCompleteResponse; import com.groom.swipo.domain.payment.dto.response.PaymentPageResponse; +import com.groom.swipo.domain.payment.entity.Paylist; import com.groom.swipo.domain.payment.exception.PasswordMismatchException; import com.groom.swipo.domain.point.entity.Card; import com.groom.swipo.domain.point.exception.CardNotFoundException; @@ -67,6 +68,9 @@ public PaymentCompleteResponse completePayment(PaymentCompleteRequest request, P user.getPay().updatePay(-netPayment); card.updatePoint(earnedPoints - request.usedPoints()); + Paylist paylist = request.toEntity(user.getPay(), store); + user.getPay().getPaylists().add(paylist); + return PaymentCompleteResponse.of(request.amount(), earnedPoints, user.getPay().getTotalPay()); } } From 70bad865147aecc2b33be48f79844f38ea0efdb0 Mon Sep 17 00:00:00 2001 From: Kang Duoh Date: Fri, 22 Nov 2024 19:28:20 +0900 Subject: [PATCH 12/12] =?UTF-8?q?=F0=9F=90=9B=20Fix[#12]:=20=ED=95=B4?= =?UTF-8?q?=EC=8B=9C=EB=90=9C=20=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8?= =?UTF-8?q?=EC=99=80=20=EB=B9=84=EA=B5=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../groom/swipo/domain/payment/service/PaymentService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/groom/swipo/domain/payment/service/PaymentService.java b/src/main/java/com/groom/swipo/domain/payment/service/PaymentService.java index b352800..6fe8747 100644 --- a/src/main/java/com/groom/swipo/domain/payment/service/PaymentService.java +++ b/src/main/java/com/groom/swipo/domain/payment/service/PaymentService.java @@ -2,6 +2,7 @@ import java.security.Principal; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -29,6 +30,7 @@ public class PaymentService { private final UserRepository userRepository; private final StoreRepository storeRepository; + private final PasswordEncoder passwordEncoder; public PaymentPageResponse getPaymentPage(Long storeId, Principal principal) { Long userId = Long.parseLong(principal.getName()); @@ -54,7 +56,7 @@ public PaymentCompleteResponse completePayment(PaymentCompleteRequest request, P .findFirst() .orElseThrow(CardNotFoundException::new); - if (!user.getPassword().equals(request.password())) { + if (!passwordEncoder.matches(request.password(), user.getPassword())) { throw new PasswordMismatchException(); }