From 356edebae83a6388f322bc474bdabfd34f2b2990 Mon Sep 17 00:00:00 2001 From: devk0ng Date: Sun, 22 Oct 2023 22:30:24 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=EC=A2=8B=EC=95=84=EC=9A=94,=20=EC=8B=AB?= =?UTF-8?q?=EC=96=B4=EC=9A=94=20=EA=B5=AC=ED=98=84(=EC=9D=BC=EB=B6=80=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pyonsnalcolor/config/SecurityConfig.java | 7 ++-- .../controller/EventProductController.java | 14 ++++--- .../controller/PbProductController.java | 14 ++++--- .../pyonsnalcolor/product/dto/ReviewDto.java | 7 +++- .../product/dto/ReviewRequestDto.java | 20 ++++++++++ .../product/entity/HateCount.java | 16 ++++++++ .../product/entity/LikeCount.java | 16 ++++++++ .../pyonsnalcolor/product/entity/Review.java | 38 +++++++++++++------ .../product/service/ProductService.java | 19 +++++----- 9 files changed, 113 insertions(+), 38 deletions(-) create mode 100644 src/main/java/com/pyonsnalcolor/product/dto/ReviewRequestDto.java create mode 100644 src/main/java/com/pyonsnalcolor/product/entity/HateCount.java create mode 100644 src/main/java/com/pyonsnalcolor/product/entity/LikeCount.java diff --git a/src/main/java/com/pyonsnalcolor/config/SecurityConfig.java b/src/main/java/com/pyonsnalcolor/config/SecurityConfig.java index 418180d..995e77b 100644 --- a/src/main/java/com/pyonsnalcolor/config/SecurityConfig.java +++ b/src/main/java/com/pyonsnalcolor/config/SecurityConfig.java @@ -38,7 +38,8 @@ public WebSecurityCustomizer webSecurityCustomizer() { .antMatchers( "/resources/**", "/v3/api-docs/**", "/swagger-ui/**", - "/health-check" + "/health-check", + "/products/**" ); } @@ -51,7 +52,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() - .antMatchers("/auth/**", "/promotions/**", "/fcm/**", "/manage/**").permitAll() + .antMatchers("/products/**","/auth/**", "/promotions/**", "/fcm/**", "/manage/**").permitAll() .antMatchers("/member/**").hasRole("USER") .anyRequest().authenticated() .and() @@ -77,4 +78,4 @@ public UserDetailsService userDetailsService() { public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) { return restTemplateBuilder.build(); } -} \ No newline at end of file +} diff --git a/src/main/java/com/pyonsnalcolor/product/controller/EventProductController.java b/src/main/java/com/pyonsnalcolor/product/controller/EventProductController.java index 7dc88b2..81d5a61 100644 --- a/src/main/java/com/pyonsnalcolor/product/controller/EventProductController.java +++ b/src/main/java/com/pyonsnalcolor/product/controller/EventProductController.java @@ -5,7 +5,7 @@ import com.pyonsnalcolor.product.dto.EventProductResponseDto; import com.pyonsnalcolor.product.dto.ProductFilterRequestDto; import com.pyonsnalcolor.product.dto.ProductResponseDto; -import com.pyonsnalcolor.product.dto.ReviewDto; +import com.pyonsnalcolor.product.dto.ReviewRequestDto; import com.pyonsnalcolor.product.enumtype.ProductType; import com.pyonsnalcolor.product.service.EventProductService; import io.swagger.v3.oas.annotations.Operation; @@ -51,7 +51,7 @@ public ResponseEntity> getEventProductsByFilter( public ResponseEntity registerReview( @PathVariable String id, @RequestPart(value = "imageFile", required = false) MultipartFile imageFile, - @RequestPart(value = "reviewDto") ReviewDto reviewDto + @RequestPart(value = "reviewDto") ReviewRequestDto reviewDto ) throws Throwable { eventProductService.registerReview(imageFile, reviewDto, id); @@ -72,8 +72,9 @@ public ResponseEntity getEventProduct( @Operation(summary = "event 상품 리뷰 좋아요", description = "id에 해당하는 event 상품의 리뷰 좋아요 카운트 증가.") @PutMapping("/products/event-products/{productId}/reviews/{reviewId}/like") public ResponseEntity likeReview(@PathVariable("productId") String productId, - @PathVariable("reviewId") String reviewId) throws Throwable { - eventProductService.likeReview(productId, reviewId); + @PathVariable("reviewId") String reviewId, + @RequestParam("writerId") Long writerId) throws Throwable { + eventProductService.likeReview(productId, reviewId, writerId); return ResponseEntity.ok().build(); } @@ -81,8 +82,9 @@ public ResponseEntity likeReview(@PathVariable("productId") String product @Operation(summary = "event 상품 리뷰 싫어요", description = "id에 해당하는 event 상품의 리뷰 싫어요 카운트 증가.") @PutMapping("/products/event-products/{productId}/reviews/{reviewId}/hate") public ResponseEntity hateReview(@PathVariable("productId") String productId, - @PathVariable("reviewId") String reviewId) throws Throwable { - eventProductService.hateReview(productId, reviewId); + @PathVariable("reviewId") String reviewId, + @RequestParam("writerId") Long writerId) throws Throwable { + eventProductService.hateReview(productId, reviewId, writerId); return ResponseEntity.ok().build(); } diff --git a/src/main/java/com/pyonsnalcolor/product/controller/PbProductController.java b/src/main/java/com/pyonsnalcolor/product/controller/PbProductController.java index 10ef93f..bde1dfe 100644 --- a/src/main/java/com/pyonsnalcolor/product/controller/PbProductController.java +++ b/src/main/java/com/pyonsnalcolor/product/controller/PbProductController.java @@ -5,7 +5,7 @@ import com.pyonsnalcolor.product.dto.PbProductResponseDto; import com.pyonsnalcolor.product.dto.ProductFilterRequestDto; import com.pyonsnalcolor.product.dto.ProductResponseDto; -import com.pyonsnalcolor.product.dto.ReviewDto; +import com.pyonsnalcolor.product.dto.ReviewRequestDto; import com.pyonsnalcolor.product.enumtype.ProductType; import com.pyonsnalcolor.product.service.PbProductService; import io.swagger.v3.oas.annotations.Operation; @@ -51,7 +51,7 @@ public ResponseEntity> getPbProductsByFilter( public ResponseEntity registerReview( @PathVariable String id, @RequestPart(value = "imageFile", required = false) MultipartFile imageFile, - @RequestPart(value = "reviewDto") ReviewDto reviewDto + @RequestPart(value = "reviewDto") ReviewRequestDto reviewDto ) throws Throwable { pbProductService.registerReview(imageFile, reviewDto, id); @@ -72,8 +72,9 @@ public ResponseEntity getPbProduct( @Operation(summary = "PB 상품 리뷰 좋아요", description = "id에 해당하는 PB 상품의 리뷰 좋아요 카운트 증가.") @PutMapping("/products/pb-products/{productId}/reviews/{reviewId}/like") public ResponseEntity likeReview(@PathVariable("productId") String productId, - @PathVariable("reviewId") String reviewId) throws Throwable { - pbProductService.likeReview(productId, reviewId); + @PathVariable("reviewId") String reviewId, + @RequestParam("writerId") Long writerId) throws Throwable { + pbProductService.likeReview(productId, reviewId, writerId); return ResponseEntity.ok().build(); } @@ -81,8 +82,9 @@ public ResponseEntity likeReview(@PathVariable("productId") String product @Operation(summary = "PB 상품 리뷰 싫어요", description = "id에 해당하는 PB 상품의 리뷰 싫어요 카운트 증가.") @PutMapping("/products/pb-products/{productId}/reviews/{reviewId}/hate") public ResponseEntity hateReview(@PathVariable("productId") String productId, - @PathVariable("reviewId") String reviewId) throws Throwable { - pbProductService.hateReview(productId, reviewId); + @PathVariable("reviewId") String reviewId, + @RequestParam("writerId") Long writerId) throws Throwable { + pbProductService.hateReview(productId, reviewId, writerId); return ResponseEntity.ok().build(); } diff --git a/src/main/java/com/pyonsnalcolor/product/dto/ReviewDto.java b/src/main/java/com/pyonsnalcolor/product/dto/ReviewDto.java index 9e3d2ee..c595efb 100644 --- a/src/main/java/com/pyonsnalcolor/product/dto/ReviewDto.java +++ b/src/main/java/com/pyonsnalcolor/product/dto/ReviewDto.java @@ -5,6 +5,8 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import com.pyonsnalcolor.product.entity.HateCount; +import com.pyonsnalcolor.product.entity.LikeCount; import com.pyonsnalcolor.product.enumtype.Like; import lombok.AllArgsConstructor; import lombok.Data; @@ -16,6 +18,7 @@ @AllArgsConstructor @NoArgsConstructor public class ReviewDto { + private String reviewId; private Like taste; //맛 private Like quality; //퀄리티 private Like valueForMoney; //가성비 @@ -32,6 +35,6 @@ public class ReviewDto { @JsonSerialize(using = LocalDateTimeSerializer.class) @JsonDeserialize(using = LocalDateTimeDeserializer.class) private LocalDateTime updatedTime; - private Long likeCount; - private Long hateCount; + private LikeCount likeCount; + private HateCount hateCount; } diff --git a/src/main/java/com/pyonsnalcolor/product/dto/ReviewRequestDto.java b/src/main/java/com/pyonsnalcolor/product/dto/ReviewRequestDto.java new file mode 100644 index 0000000..b8288c8 --- /dev/null +++ b/src/main/java/com/pyonsnalcolor/product/dto/ReviewRequestDto.java @@ -0,0 +1,20 @@ +package com.pyonsnalcolor.product.dto; + +import com.pyonsnalcolor.product.enumtype.Like; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ReviewRequestDto { + private Like taste; //맛 + private Like quality; //퀄리티 + private Like valueForMoney; //가성비 + private float score; //별점 + private String contents; //내용 + + private Long writerId; //작성자 <- 이후 기능 확장 고려한 필드 + private String writerName; // 닉네임 +} diff --git a/src/main/java/com/pyonsnalcolor/product/entity/HateCount.java b/src/main/java/com/pyonsnalcolor/product/entity/HateCount.java new file mode 100644 index 0000000..76920a7 --- /dev/null +++ b/src/main/java/com/pyonsnalcolor/product/entity/HateCount.java @@ -0,0 +1,16 @@ +package com.pyonsnalcolor.product.entity; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class HateCount { + private List writerIds = new ArrayList<>(); + private Long hateCount = 0L; + + public void addWriter(Long writerId) { + this.writerIds.add(writerId); + } +} diff --git a/src/main/java/com/pyonsnalcolor/product/entity/LikeCount.java b/src/main/java/com/pyonsnalcolor/product/entity/LikeCount.java new file mode 100644 index 0000000..986ba9c --- /dev/null +++ b/src/main/java/com/pyonsnalcolor/product/entity/LikeCount.java @@ -0,0 +1,16 @@ +package com.pyonsnalcolor.product.entity; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class LikeCount { + private List writerIds = new ArrayList<>(); + private Long likeCount = 0L; + + public void addWriter(Long writerId) { + this.writerIds.add(writerId); + } +} diff --git a/src/main/java/com/pyonsnalcolor/product/entity/Review.java b/src/main/java/com/pyonsnalcolor/product/entity/Review.java index 350b4f3..34d4205 100644 --- a/src/main/java/com/pyonsnalcolor/product/entity/Review.java +++ b/src/main/java/com/pyonsnalcolor/product/entity/Review.java @@ -23,25 +23,41 @@ public class Review { private String writerName; private LocalDateTime createdTime; private LocalDateTime updatedTime; - private Long likeCount; - private Long hateCount; + private LikeCount likeCount; + private HateCount hateCount; public ReviewDto convertToDto() { - return new ReviewDto(taste, quality, valueForMoney, score, contents, image, writerId, writerName, + return new ReviewDto(reviewId, taste, quality, valueForMoney, score, contents, image, writerId, writerName, createdTime, updatedTime, likeCount, hateCount); } - public void likeReview() { - if(this.likeCount == null) { - this.likeCount = 0L; + public void likeReview(Long writerId) { + if (this.likeCount == null) { + this.likeCount = new LikeCount(); + } + if (this.likeCount.getWriterIds().contains(writerId)) { + return; + } + this.likeCount.addWriter(writerId); + this.likeCount.setLikeCount(this.likeCount.getLikeCount() + 1); + + if (this.hateCount != null && this.hateCount.getWriterIds().contains(writerId)) { + this.hateCount.setHateCount(this.hateCount.getHateCount() - 1); } - this.likeCount += 1; } - public void hateReview() { - if(this.hateCount == null) { - this.hateCount = 0L; + public void hateReview(Long writerId) { + if (this.hateCount == null) { + this.hateCount = new HateCount(); + } + if (this.hateCount.getWriterIds().contains(writerId)) { + return; + } + this.hateCount.addWriter(writerId); + this.hateCount.setHateCount(this.hateCount.getHateCount() + 1); + + if (this.likeCount != null && this.likeCount.getWriterIds().contains(writerId)) { + this.likeCount.setLikeCount(this.likeCount.getLikeCount() - 1); } - this.hateCount += 1; } } diff --git a/src/main/java/com/pyonsnalcolor/product/service/ProductService.java b/src/main/java/com/pyonsnalcolor/product/service/ProductService.java index ada0714..e80e28f 100644 --- a/src/main/java/com/pyonsnalcolor/product/service/ProductService.java +++ b/src/main/java/com/pyonsnalcolor/product/service/ProductService.java @@ -4,9 +4,8 @@ import com.pyonsnalcolor.product.dto.ProductFilterRequestDto; import com.pyonsnalcolor.product.dto.ProductResponseDto; import com.pyonsnalcolor.product.dto.ReviewDto; -import com.pyonsnalcolor.product.entity.BaseProduct; -import com.pyonsnalcolor.product.entity.Review; -import com.pyonsnalcolor.product.entity.UUIDGenerator; +import com.pyonsnalcolor.product.dto.ReviewRequestDto; +import com.pyonsnalcolor.product.entity.*; import com.pyonsnalcolor.product.enumtype.*; import com.pyonsnalcolor.product.repository.BasicProductRepository; import com.pyonsnalcolor.product.repository.ImageRepository; @@ -85,7 +84,7 @@ private Criteria createFilterCriteria(List recommends, List } //리뷰 좋아요 - public void likeReview(String productId, String reviewId) throws Throwable { + public void likeReview(String productId, String reviewId, Long writerId) throws Throwable { BaseProduct baseProduct = (BaseProduct) basicProductRepository .findById(productId) .orElseThrow(NoSuchElementException::new); @@ -95,13 +94,13 @@ public void likeReview(String productId, String reviewId) throws Throwable { ).findFirst() .orElseThrow(NoSuchElementException::new); - review.likeReview(); + review.likeReview(writerId); basicProductRepository.save(baseProduct); } //리뷰 싫어요 - public void hateReview(String productId, String reviewId) throws Throwable { + public void hateReview(String productId, String reviewId, Long writerId) throws Throwable { BaseProduct baseProduct = (BaseProduct) basicProductRepository .findById(productId) .orElseThrow(NoSuchElementException::new); @@ -111,13 +110,13 @@ public void hateReview(String productId, String reviewId) throws Throwable { ).findFirst() .orElseThrow(NoSuchElementException::new); - review.hateReview(); + review.hateReview(writerId); basicProductRepository.save(baseProduct); } //리뷰 등록 - public void registerReview(MultipartFile image, ReviewDto reviewDto, String productId) throws Throwable { + public void registerReview(MultipartFile image, ReviewRequestDto reviewDto, String productId) throws Throwable { BaseProduct baseProduct = (BaseProduct) basicProductRepository .findById(productId) .orElseThrow(NoSuchElementException::new); @@ -140,8 +139,8 @@ public void registerReview(MultipartFile image, ReviewDto reviewDto, String prod .writerName(reviewDto.getWriterName()) .updatedTime(LocalDateTime.now()) .createdTime(LocalDateTime.now()) - .hateCount(0L) - .likeCount(0L) + .hateCount(new HateCount()) + .likeCount(new LikeCount()) .build(); baseProduct.addReview(review); From 711c3e4103de959fe85c7640bc08537705615159 Mon Sep 17 00:00:00 2001 From: devk0ng Date: Sun, 22 Oct 2023 22:31:12 +0900 Subject: [PATCH 2/3] =?UTF-8?q?security=20=EC=9E=98=EB=AA=BB=EB=90=9C=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=9B=90=EB=B3=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/pyonsnalcolor/config/SecurityConfig.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/pyonsnalcolor/config/SecurityConfig.java b/src/main/java/com/pyonsnalcolor/config/SecurityConfig.java index 995e77b..61fcd00 100644 --- a/src/main/java/com/pyonsnalcolor/config/SecurityConfig.java +++ b/src/main/java/com/pyonsnalcolor/config/SecurityConfig.java @@ -38,8 +38,7 @@ public WebSecurityCustomizer webSecurityCustomizer() { .antMatchers( "/resources/**", "/v3/api-docs/**", "/swagger-ui/**", - "/health-check", - "/products/**" + "/health-check" ); } @@ -52,7 +51,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() - .antMatchers("/products/**","/auth/**", "/promotions/**", "/fcm/**", "/manage/**").permitAll() + .antMatchers("/auth/**", "/promotions/**", "/fcm/**", "/manage/**").permitAll() .antMatchers("/member/**").hasRole("USER") .anyRequest().authenticated() .and() From ee002a0728ac1e5ec15aec596d2de94c4dba9c5d Mon Sep 17 00:00:00 2001 From: devk0ng Date: Sun, 22 Oct 2023 22:34:21 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/pyonsnalcolor/product/entity/Review.java | 2 ++ .../java/com/pyonsnalcolor/product/service/ProductService.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/main/java/com/pyonsnalcolor/product/entity/Review.java b/src/main/java/com/pyonsnalcolor/product/entity/Review.java index 34d4205..454474d 100644 --- a/src/main/java/com/pyonsnalcolor/product/entity/Review.java +++ b/src/main/java/com/pyonsnalcolor/product/entity/Review.java @@ -43,6 +43,7 @@ public void likeReview(Long writerId) { if (this.hateCount != null && this.hateCount.getWriterIds().contains(writerId)) { this.hateCount.setHateCount(this.hateCount.getHateCount() - 1); + this.hateCount.getWriterIds().remove(writerId); } } @@ -58,6 +59,7 @@ public void hateReview(Long writerId) { if (this.likeCount != null && this.likeCount.getWriterIds().contains(writerId)) { this.likeCount.setLikeCount(this.likeCount.getLikeCount() - 1); + this.likeCount.getWriterIds().remove(writerId); } } } diff --git a/src/main/java/com/pyonsnalcolor/product/service/ProductService.java b/src/main/java/com/pyonsnalcolor/product/service/ProductService.java index e80e28f..ed5150f 100644 --- a/src/main/java/com/pyonsnalcolor/product/service/ProductService.java +++ b/src/main/java/com/pyonsnalcolor/product/service/ProductService.java @@ -84,6 +84,7 @@ private Criteria createFilterCriteria(List recommends, List } //리뷰 좋아요 + @Transactional public void likeReview(String productId, String reviewId, Long writerId) throws Throwable { BaseProduct baseProduct = (BaseProduct) basicProductRepository .findById(productId) @@ -100,6 +101,7 @@ public void likeReview(String productId, String reviewId, Long writerId) throws } //리뷰 싫어요 + @Transactional public void hateReview(String productId, String reviewId, Long writerId) throws Throwable { BaseProduct baseProduct = (BaseProduct) basicProductRepository .findById(productId)