From 216c9dd20c091404ce32f81e9603cf6be99eabc0 Mon Sep 17 00:00:00 2001 From: Suhun0331 Date: Mon, 30 Dec 2024 11:49:10 +0900 Subject: [PATCH 1/9] Create new branch & struct --- src/main/java/kw/zeropick/home/controller/HomeController.java | 4 ++++ src/main/java/kw/zeropick/home/service/HomeService.java | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 src/main/java/kw/zeropick/home/controller/HomeController.java create mode 100644 src/main/java/kw/zeropick/home/service/HomeService.java diff --git a/src/main/java/kw/zeropick/home/controller/HomeController.java b/src/main/java/kw/zeropick/home/controller/HomeController.java new file mode 100644 index 0000000..2a274b5 --- /dev/null +++ b/src/main/java/kw/zeropick/home/controller/HomeController.java @@ -0,0 +1,4 @@ +package kw.zeropick.home.controller; + +public class HomeController { +} diff --git a/src/main/java/kw/zeropick/home/service/HomeService.java b/src/main/java/kw/zeropick/home/service/HomeService.java new file mode 100644 index 0000000..17665f8 --- /dev/null +++ b/src/main/java/kw/zeropick/home/service/HomeService.java @@ -0,0 +1,4 @@ +package kw.zeropick.home.service; + +public class HomeService { +} From 378accf12c955a613caa38e190452b6a071f8391 Mon Sep 17 00:00:00 2001 From: inswal843 Date: Wed, 8 Jan 2025 14:39:12 +0900 Subject: [PATCH 2/9] =?UTF-8?q?Fix:=20=EB=A6=AC=EB=B7=B0=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=EC=97=90=20=EA=B8=B0=EC=A1=B4=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=82=AD=EC=A0=9C,=20=EC=83=88=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=EC=97=85=EB=A1=9C=EB=93=9C=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../review/controller/ReviewController.java | 2 +- .../review/service/ReviewService.java | 2 +- .../review/service/ReviewServiceImpl.java | 21 +++++++++++++++++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/main/java/kw/zeropick/review/controller/ReviewController.java b/src/main/java/kw/zeropick/review/controller/ReviewController.java index 07f9a35..92f2386 100644 --- a/src/main/java/kw/zeropick/review/controller/ReviewController.java +++ b/src/main/java/kw/zeropick/review/controller/ReviewController.java @@ -48,7 +48,7 @@ public ResponseEntity updateReview( @PathVariable Long reviewId, @RequestPart(value = "review") ReviewRequestDto reviewRequestDto, @RequestPart(value = "files", required = false) List files) { - reviewService.updateReview(reviewId, reviewRequestDto); + reviewService.updateReview(reviewId, reviewRequestDto, files); return ResponseEntity.ok("리뷰가 성공적으로 수정되었습니다."); } diff --git a/src/main/java/kw/zeropick/review/service/ReviewService.java b/src/main/java/kw/zeropick/review/service/ReviewService.java index 74b58ec..4216c9f 100644 --- a/src/main/java/kw/zeropick/review/service/ReviewService.java +++ b/src/main/java/kw/zeropick/review/service/ReviewService.java @@ -12,5 +12,5 @@ public interface ReviewService { Page getReviews(Long productId, PositiveTagEnum positiveTag, String sort, Pageable pageable); void createReview(ReviewRequestDto reviewRequestDto, List files); - void updateReview(Long reviewId, ReviewRequestDto reviewRequestDto); + void updateReview(Long reviewId, ReviewRequestDto reviewRequestDto, List files); } diff --git a/src/main/java/kw/zeropick/review/service/ReviewServiceImpl.java b/src/main/java/kw/zeropick/review/service/ReviewServiceImpl.java index a7ec896..984d42d 100644 --- a/src/main/java/kw/zeropick/review/service/ReviewServiceImpl.java +++ b/src/main/java/kw/zeropick/review/service/ReviewServiceImpl.java @@ -122,7 +122,7 @@ public void createReview(ReviewRequestDto reviewRequestDto, List @Override @Transactional - public void updateReview(Long reviewId, ReviewRequestDto reviewRequestDto) { + public void updateReview(Long reviewId, ReviewRequestDto reviewRequestDto, List files) { Review existingReview = reviewRepository.findById(reviewId) .orElseThrow(() -> new EntityNotFoundException("해당 리뷰를 찾을 수 없습니다.")); @@ -136,7 +136,24 @@ public void updateReview(Long reviewId, ReviewRequestDto reviewRequestDto) { // 리뷰 정보 업데이트 existingReview.setRating(reviewRequestDto.getRating()); existingReview.setContent(reviewRequestDto.getContent()); - existingReview.setImageUrls(reviewRequestDto.getImageUrls()); + List oldImageUrls = existingReview.getImageUrls(); + if(!oldImageUrls.isEmpty()) { + for (String imageUrl : oldImageUrls) { + s3Util.deleteFile(imageUrl); + } + } + List newImageUrls = new ArrayList<>(); + // 이미지 파일 처리 및 S3 업로드 + if (files != null && !files.isEmpty()) { + for (MultipartFile file : files) { + if (file != null && !file.isEmpty()) { + String imageUrl = s3Util.upload(file); + System.out.println(imageUrl); + newImageUrls.add(imageUrl); + } + } + } + existingReview.setImageUrls(newImageUrls); reviewRepository.save(existingReview); // 기존 태그 매핑 삭제 From 19a7454c96b8b52b46c7bc4db70df93435b295aa Mon Sep 17 00:00:00 2001 From: Suhun0331 Date: Wed, 8 Jan 2025 14:54:31 +0900 Subject: [PATCH 3/9] =?UTF-8?q?Feat=20:=20=EB=A6=AC=EB=B7=B0=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zeropick/common/domain/QBaseEntity.java | 78 ++++----- .../kw/zeropick/member/domain/QMember.java | 106 ++++++------ .../kw/zeropick/product/domain/QBookmark.java | 124 +++++++------- .../kw/zeropick/product/domain/QCompare.java | 124 +++++++------- .../zeropick/product/domain/QIngredient.java | 146 ++++++++-------- .../kw/zeropick/product/domain/QProduct.java | 162 +++++++++--------- .../kw/zeropick/review/domain/QReview.java | 134 +++++++-------- .../kw/zeropick/review/domain/QReviewTag.java | 94 +++++----- .../review/domain/QReviewTagMapping.java | 124 +++++++------- .../review/controller/ReviewController.java | 20 +-- .../review/service/ReviewService.java | 1 + .../review/service/ReviewServiceImpl.java | 47 +++++ 12 files changed, 603 insertions(+), 557 deletions(-) diff --git a/src/main/generated/kw/zeropick/common/domain/QBaseEntity.java b/src/main/generated/kw/zeropick/common/domain/QBaseEntity.java index e3ce6cc..432a09e 100644 --- a/src/main/generated/kw/zeropick/common/domain/QBaseEntity.java +++ b/src/main/generated/kw/zeropick/common/domain/QBaseEntity.java @@ -1,39 +1,39 @@ -package kw.zeropick.common.domain; - -import static com.querydsl.core.types.PathMetadataFactory.*; - -import com.querydsl.core.types.dsl.*; - -import com.querydsl.core.types.PathMetadata; -import javax.annotation.processing.Generated; -import com.querydsl.core.types.Path; - - -/** - * QBaseEntity is a Querydsl query type for BaseEntity - */ -@Generated("com.querydsl.codegen.DefaultSupertypeSerializer") -public class QBaseEntity extends EntityPathBase { - - private static final long serialVersionUID = -693329954L; - - public static final QBaseEntity baseEntity = new QBaseEntity("baseEntity"); - - public final DateTimePath createdAt = createDateTime("createdAt", java.time.LocalDateTime.class); - - public final DateTimePath updatedAt = createDateTime("updatedAt", java.time.LocalDateTime.class); - - public QBaseEntity(String variable) { - super(BaseEntity.class, forVariable(variable)); - } - - public QBaseEntity(Path path) { - super(path.getType(), path.getMetadata()); - } - - public QBaseEntity(PathMetadata metadata) { - super(BaseEntity.class, metadata); - } - -} - +package kw.zeropick.common.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; + + +/** + * QBaseEntity is a Querydsl query type for BaseEntity + */ +@Generated("com.querydsl.codegen.DefaultSupertypeSerializer") +public class QBaseEntity extends EntityPathBase { + + private static final long serialVersionUID = -693329954L; + + public static final QBaseEntity baseEntity = new QBaseEntity("baseEntity"); + + public final DateTimePath createdAt = createDateTime("createdAt", java.time.LocalDateTime.class); + + public final DateTimePath updatedAt = createDateTime("updatedAt", java.time.LocalDateTime.class); + + public QBaseEntity(String variable) { + super(BaseEntity.class, forVariable(variable)); + } + + public QBaseEntity(Path path) { + super(path.getType(), path.getMetadata()); + } + + public QBaseEntity(PathMetadata metadata) { + super(BaseEntity.class, metadata); + } + +} + diff --git a/src/main/generated/kw/zeropick/member/domain/QMember.java b/src/main/generated/kw/zeropick/member/domain/QMember.java index 17b700f..897a07a 100644 --- a/src/main/generated/kw/zeropick/member/domain/QMember.java +++ b/src/main/generated/kw/zeropick/member/domain/QMember.java @@ -1,53 +1,53 @@ -package kw.zeropick.member.domain; - -import static com.querydsl.core.types.PathMetadataFactory.*; - -import com.querydsl.core.types.dsl.*; - -import com.querydsl.core.types.PathMetadata; -import javax.annotation.processing.Generated; -import com.querydsl.core.types.Path; - - -/** - * QMember is a Querydsl query type for Member - */ -@Generated("com.querydsl.codegen.DefaultEntitySerializer") -public class QMember extends EntityPathBase { - - private static final long serialVersionUID = 213773267L; - - public static final QMember member = new QMember("member1"); - - public final DatePath birthDate = createDate("birthDate", java.time.LocalDate.class); - - public final DatePath deleteDate = createDate("deleteDate", java.time.LocalDate.class); - - public final StringPath email = createString("email"); - - public final NumberPath id = createNumber("id", Long.class); - - public final EnumPath marketingAgree = createEnum("marketingAgree", MarketingAgree.class); - - public final StringPath name = createString("name"); - - public final StringPath password = createString("password"); - - public final StringPath phoneNumber = createString("phoneNumber"); - - public final EnumPath userState = createEnum("userState", State.class); - - public QMember(String variable) { - super(Member.class, forVariable(variable)); - } - - public QMember(Path path) { - super(path.getType(), path.getMetadata()); - } - - public QMember(PathMetadata metadata) { - super(Member.class, metadata); - } - -} - +package kw.zeropick.member.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; + + +/** + * QMember is a Querydsl query type for Member + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QMember extends EntityPathBase { + + private static final long serialVersionUID = 213773267L; + + public static final QMember member = new QMember("member1"); + + public final DatePath birthDate = createDate("birthDate", java.time.LocalDate.class); + + public final DatePath deleteDate = createDate("deleteDate", java.time.LocalDate.class); + + public final StringPath email = createString("email"); + + public final NumberPath id = createNumber("id", Long.class); + + public final EnumPath marketingAgree = createEnum("marketingAgree", MarketingAgree.class); + + public final StringPath name = createString("name"); + + public final StringPath password = createString("password"); + + public final StringPath phoneNumber = createString("phoneNumber"); + + public final EnumPath userState = createEnum("userState", State.class); + + public QMember(String variable) { + super(Member.class, forVariable(variable)); + } + + public QMember(Path path) { + super(path.getType(), path.getMetadata()); + } + + public QMember(PathMetadata metadata) { + super(Member.class, metadata); + } + +} + diff --git a/src/main/generated/kw/zeropick/product/domain/QBookmark.java b/src/main/generated/kw/zeropick/product/domain/QBookmark.java index 2c2e5df..b0d889e 100644 --- a/src/main/generated/kw/zeropick/product/domain/QBookmark.java +++ b/src/main/generated/kw/zeropick/product/domain/QBookmark.java @@ -1,62 +1,62 @@ -package kw.zeropick.product.domain; - -import static com.querydsl.core.types.PathMetadataFactory.*; - -import com.querydsl.core.types.dsl.*; - -import com.querydsl.core.types.PathMetadata; -import javax.annotation.processing.Generated; -import com.querydsl.core.types.Path; -import com.querydsl.core.types.dsl.PathInits; - - -/** - * QBookmark is a Querydsl query type for Bookmark - */ -@Generated("com.querydsl.codegen.DefaultEntitySerializer") -public class QBookmark extends EntityPathBase { - - private static final long serialVersionUID = -1896262562L; - - private static final PathInits INITS = PathInits.DIRECT2; - - public static final QBookmark bookmark = new QBookmark("bookmark"); - - public final kw.zeropick.common.domain.QBaseEntity _super = new kw.zeropick.common.domain.QBaseEntity(this); - - //inherited - public final DateTimePath createdAt = _super.createdAt; - - public final NumberPath id = createNumber("id", Long.class); - - public final kw.zeropick.member.domain.QMember member; - - public final QProduct product; - - //inherited - public final DateTimePath updatedAt = _super.updatedAt; - - public QBookmark(String variable) { - this(Bookmark.class, forVariable(variable), INITS); - } - - public QBookmark(Path path) { - this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); - } - - public QBookmark(PathMetadata metadata) { - this(metadata, PathInits.getFor(metadata, INITS)); - } - - public QBookmark(PathMetadata metadata, PathInits inits) { - this(Bookmark.class, metadata, inits); - } - - public QBookmark(Class type, PathMetadata metadata, PathInits inits) { - super(type, metadata, inits); - this.member = inits.isInitialized("member") ? new kw.zeropick.member.domain.QMember(forProperty("member")) : null; - this.product = inits.isInitialized("product") ? new QProduct(forProperty("product"), inits.get("product")) : null; - } - -} - +package kw.zeropick.product.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.PathInits; + + +/** + * QBookmark is a Querydsl query type for Bookmark + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QBookmark extends EntityPathBase { + + private static final long serialVersionUID = -1896262562L; + + private static final PathInits INITS = PathInits.DIRECT2; + + public static final QBookmark bookmark = new QBookmark("bookmark"); + + public final kw.zeropick.common.domain.QBaseEntity _super = new kw.zeropick.common.domain.QBaseEntity(this); + + //inherited + public final DateTimePath createdAt = _super.createdAt; + + public final NumberPath id = createNumber("id", Long.class); + + public final kw.zeropick.member.domain.QMember member; + + public final QProduct product; + + //inherited + public final DateTimePath updatedAt = _super.updatedAt; + + public QBookmark(String variable) { + this(Bookmark.class, forVariable(variable), INITS); + } + + public QBookmark(Path path) { + this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); + } + + public QBookmark(PathMetadata metadata) { + this(metadata, PathInits.getFor(metadata, INITS)); + } + + public QBookmark(PathMetadata metadata, PathInits inits) { + this(Bookmark.class, metadata, inits); + } + + public QBookmark(Class type, PathMetadata metadata, PathInits inits) { + super(type, metadata, inits); + this.member = inits.isInitialized("member") ? new kw.zeropick.member.domain.QMember(forProperty("member")) : null; + this.product = inits.isInitialized("product") ? new QProduct(forProperty("product"), inits.get("product")) : null; + } + +} + diff --git a/src/main/generated/kw/zeropick/product/domain/QCompare.java b/src/main/generated/kw/zeropick/product/domain/QCompare.java index 169f4c5..44aeca2 100644 --- a/src/main/generated/kw/zeropick/product/domain/QCompare.java +++ b/src/main/generated/kw/zeropick/product/domain/QCompare.java @@ -1,62 +1,62 @@ -package kw.zeropick.product.domain; - -import static com.querydsl.core.types.PathMetadataFactory.*; - -import com.querydsl.core.types.dsl.*; - -import com.querydsl.core.types.PathMetadata; -import javax.annotation.processing.Generated; -import com.querydsl.core.types.Path; -import com.querydsl.core.types.dsl.PathInits; - - -/** - * QCompare is a Querydsl query type for Compare - */ -@Generated("com.querydsl.codegen.DefaultEntitySerializer") -public class QCompare extends EntityPathBase { - - private static final long serialVersionUID = 1378814141L; - - private static final PathInits INITS = PathInits.DIRECT2; - - public static final QCompare compare = new QCompare("compare"); - - public final kw.zeropick.common.domain.QBaseEntity _super = new kw.zeropick.common.domain.QBaseEntity(this); - - //inherited - public final DateTimePath createdAt = _super.createdAt; - - public final NumberPath id = createNumber("id", Long.class); - - public final kw.zeropick.member.domain.QMember member; - - public final QProduct product; - - //inherited - public final DateTimePath updatedAt = _super.updatedAt; - - public QCompare(String variable) { - this(Compare.class, forVariable(variable), INITS); - } - - public QCompare(Path path) { - this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); - } - - public QCompare(PathMetadata metadata) { - this(metadata, PathInits.getFor(metadata, INITS)); - } - - public QCompare(PathMetadata metadata, PathInits inits) { - this(Compare.class, metadata, inits); - } - - public QCompare(Class type, PathMetadata metadata, PathInits inits) { - super(type, metadata, inits); - this.member = inits.isInitialized("member") ? new kw.zeropick.member.domain.QMember(forProperty("member")) : null; - this.product = inits.isInitialized("product") ? new QProduct(forProperty("product"), inits.get("product")) : null; - } - -} - +package kw.zeropick.product.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.PathInits; + + +/** + * QCompare is a Querydsl query type for Compare + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QCompare extends EntityPathBase { + + private static final long serialVersionUID = 1378814141L; + + private static final PathInits INITS = PathInits.DIRECT2; + + public static final QCompare compare = new QCompare("compare"); + + public final kw.zeropick.common.domain.QBaseEntity _super = new kw.zeropick.common.domain.QBaseEntity(this); + + //inherited + public final DateTimePath createdAt = _super.createdAt; + + public final NumberPath id = createNumber("id", Long.class); + + public final kw.zeropick.member.domain.QMember member; + + public final QProduct product; + + //inherited + public final DateTimePath updatedAt = _super.updatedAt; + + public QCompare(String variable) { + this(Compare.class, forVariable(variable), INITS); + } + + public QCompare(Path path) { + this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); + } + + public QCompare(PathMetadata metadata) { + this(metadata, PathInits.getFor(metadata, INITS)); + } + + public QCompare(PathMetadata metadata, PathInits inits) { + this(Compare.class, metadata, inits); + } + + public QCompare(Class type, PathMetadata metadata, PathInits inits) { + super(type, metadata, inits); + this.member = inits.isInitialized("member") ? new kw.zeropick.member.domain.QMember(forProperty("member")) : null; + this.product = inits.isInitialized("product") ? new QProduct(forProperty("product"), inits.get("product")) : null; + } + +} + diff --git a/src/main/generated/kw/zeropick/product/domain/QIngredient.java b/src/main/generated/kw/zeropick/product/domain/QIngredient.java index 48ac0dd..d82bc2f 100644 --- a/src/main/generated/kw/zeropick/product/domain/QIngredient.java +++ b/src/main/generated/kw/zeropick/product/domain/QIngredient.java @@ -1,73 +1,73 @@ -package kw.zeropick.product.domain; - -import static com.querydsl.core.types.PathMetadataFactory.*; - -import com.querydsl.core.types.dsl.*; - -import com.querydsl.core.types.PathMetadata; -import javax.annotation.processing.Generated; -import com.querydsl.core.types.Path; -import com.querydsl.core.types.dsl.PathInits; - - -/** - * QIngredient is a Querydsl query type for Ingredient - */ -@Generated("com.querydsl.codegen.DefaultEntitySerializer") -public class QIngredient extends EntityPathBase { - - private static final long serialVersionUID = -176883975L; - - private static final PathInits INITS = PathInits.DIRECT2; - - public static final QIngredient ingredient = new QIngredient("ingredient"); - - public final NumberPath allulose = createNumber("allulose", Float.class); - - public final NumberPath carb = createNumber("carb", Float.class); - - public final NumberPath cholesterol = createNumber("cholesterol", Float.class); - - public final NumberPath erythritol = createNumber("erythritol", Float.class); - - public final NumberPath fat = createNumber("fat", Float.class); - - public final NumberPath id = createNumber("id", Long.class); - - public final NumberPath kcal = createNumber("kcal", Float.class); - - public final NumberPath natrium = createNumber("natrium", Float.class); - - public final QProduct product; - - public final NumberPath protein = createNumber("protein", Float.class); - - public final NumberPath saturatedFat = createNumber("saturatedFat", Float.class); - - public final NumberPath sweet = createNumber("sweet", Float.class); - - public final NumberPath transFat = createNumber("transFat", Float.class); - - public QIngredient(String variable) { - this(Ingredient.class, forVariable(variable), INITS); - } - - public QIngredient(Path path) { - this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); - } - - public QIngredient(PathMetadata metadata) { - this(metadata, PathInits.getFor(metadata, INITS)); - } - - public QIngredient(PathMetadata metadata, PathInits inits) { - this(Ingredient.class, metadata, inits); - } - - public QIngredient(Class type, PathMetadata metadata, PathInits inits) { - super(type, metadata, inits); - this.product = inits.isInitialized("product") ? new QProduct(forProperty("product"), inits.get("product")) : null; - } - -} - +package kw.zeropick.product.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.PathInits; + + +/** + * QIngredient is a Querydsl query type for Ingredient + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QIngredient extends EntityPathBase { + + private static final long serialVersionUID = -176883975L; + + private static final PathInits INITS = PathInits.DIRECT2; + + public static final QIngredient ingredient = new QIngredient("ingredient"); + + public final NumberPath allulose = createNumber("allulose", Float.class); + + public final NumberPath carb = createNumber("carb", Float.class); + + public final NumberPath cholesterol = createNumber("cholesterol", Float.class); + + public final NumberPath erythritol = createNumber("erythritol", Float.class); + + public final NumberPath fat = createNumber("fat", Float.class); + + public final NumberPath id = createNumber("id", Long.class); + + public final NumberPath kcal = createNumber("kcal", Float.class); + + public final NumberPath natrium = createNumber("natrium", Float.class); + + public final QProduct product; + + public final NumberPath protein = createNumber("protein", Float.class); + + public final NumberPath saturatedFat = createNumber("saturatedFat", Float.class); + + public final NumberPath sweet = createNumber("sweet", Float.class); + + public final NumberPath transFat = createNumber("transFat", Float.class); + + public QIngredient(String variable) { + this(Ingredient.class, forVariable(variable), INITS); + } + + public QIngredient(Path path) { + this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); + } + + public QIngredient(PathMetadata metadata) { + this(metadata, PathInits.getFor(metadata, INITS)); + } + + public QIngredient(PathMetadata metadata, PathInits inits) { + this(Ingredient.class, metadata, inits); + } + + public QIngredient(Class type, PathMetadata metadata, PathInits inits) { + super(type, metadata, inits); + this.product = inits.isInitialized("product") ? new QProduct(forProperty("product"), inits.get("product")) : null; + } + +} + diff --git a/src/main/generated/kw/zeropick/product/domain/QProduct.java b/src/main/generated/kw/zeropick/product/domain/QProduct.java index 1bff03f..4bdef2b 100644 --- a/src/main/generated/kw/zeropick/product/domain/QProduct.java +++ b/src/main/generated/kw/zeropick/product/domain/QProduct.java @@ -1,81 +1,81 @@ -package kw.zeropick.product.domain; - -import static com.querydsl.core.types.PathMetadataFactory.*; - -import com.querydsl.core.types.dsl.*; - -import com.querydsl.core.types.PathMetadata; -import javax.annotation.processing.Generated; -import com.querydsl.core.types.Path; -import com.querydsl.core.types.dsl.PathInits; - - -/** - * QProduct is a Querydsl query type for Product - */ -@Generated("com.querydsl.codegen.DefaultEntitySerializer") -public class QProduct extends EntityPathBase { - - private static final long serialVersionUID = 118855879L; - - private static final PathInits INITS = PathInits.DIRECT2; - - public static final QProduct product = new QProduct("product"); - - public final StringPath bigCategory = createString("bigCategory"); - - public final NumberPath bookmarkCount = createNumber("bookmarkCount", Integer.class); - - public final StringPath brand = createString("brand"); - - public final EnumPath category = createEnum("category", Category.class); - - public final StringPath foodName = createString("foodName"); - - public final NumberPath id = createNumber("id", Long.class); - - public final StringPath imageUrl = createString("imageUrl"); - - public final QIngredient ingredient; - - public final NumberPath price = createNumber("price", Integer.class); - - public final StringPath productName = createString("productName"); - - public final NumberPath reviewCount = createNumber("reviewCount", Integer.class); - - public final ListPath reviews = this.createList("reviews", kw.zeropick.review.domain.Review.class, kw.zeropick.review.domain.QReview.class, PathInits.DIRECT2); - - public final NumberPath starRate = createNumber("starRate", Double.class); - - public final ListPath> tags = this.>createList("tags", kw.zeropick.review.domain.PositiveTagEnum.class, EnumPath.class, PathInits.DIRECT2); - - public final NumberPath viewCount = createNumber("viewCount", Integer.class); - - public final BooleanPath zeroKcal = createBoolean("zeroKcal"); - - public final BooleanPath zeroSugar = createBoolean("zeroSugar"); - - public QProduct(String variable) { - this(Product.class, forVariable(variable), INITS); - } - - public QProduct(Path path) { - this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); - } - - public QProduct(PathMetadata metadata) { - this(metadata, PathInits.getFor(metadata, INITS)); - } - - public QProduct(PathMetadata metadata, PathInits inits) { - this(Product.class, metadata, inits); - } - - public QProduct(Class type, PathMetadata metadata, PathInits inits) { - super(type, metadata, inits); - this.ingredient = inits.isInitialized("ingredient") ? new QIngredient(forProperty("ingredient"), inits.get("ingredient")) : null; - } - -} - +package kw.zeropick.product.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.PathInits; + + +/** + * QProduct is a Querydsl query type for Product + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QProduct extends EntityPathBase { + + private static final long serialVersionUID = 118855879L; + + private static final PathInits INITS = PathInits.DIRECT2; + + public static final QProduct product = new QProduct("product"); + + public final StringPath bigCategory = createString("bigCategory"); + + public final NumberPath bookmarkCount = createNumber("bookmarkCount", Integer.class); + + public final StringPath brand = createString("brand"); + + public final EnumPath category = createEnum("category", Category.class); + + public final StringPath foodName = createString("foodName"); + + public final NumberPath id = createNumber("id", Long.class); + + public final StringPath imageUrl = createString("imageUrl"); + + public final QIngredient ingredient; + + public final NumberPath price = createNumber("price", Integer.class); + + public final StringPath productName = createString("productName"); + + public final NumberPath reviewCount = createNumber("reviewCount", Integer.class); + + public final ListPath reviews = this.createList("reviews", kw.zeropick.review.domain.Review.class, kw.zeropick.review.domain.QReview.class, PathInits.DIRECT2); + + public final NumberPath starRate = createNumber("starRate", Double.class); + + public final ListPath> tags = this.>createList("tags", kw.zeropick.review.domain.PositiveTagEnum.class, EnumPath.class, PathInits.DIRECT2); + + public final NumberPath viewCount = createNumber("viewCount", Integer.class); + + public final BooleanPath zeroKcal = createBoolean("zeroKcal"); + + public final BooleanPath zeroSugar = createBoolean("zeroSugar"); + + public QProduct(String variable) { + this(Product.class, forVariable(variable), INITS); + } + + public QProduct(Path path) { + this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); + } + + public QProduct(PathMetadata metadata) { + this(metadata, PathInits.getFor(metadata, INITS)); + } + + public QProduct(PathMetadata metadata, PathInits inits) { + this(Product.class, metadata, inits); + } + + public QProduct(Class type, PathMetadata metadata, PathInits inits) { + super(type, metadata, inits); + this.ingredient = inits.isInitialized("ingredient") ? new QIngredient(forProperty("ingredient"), inits.get("ingredient")) : null; + } + +} + diff --git a/src/main/generated/kw/zeropick/review/domain/QReview.java b/src/main/generated/kw/zeropick/review/domain/QReview.java index 385323e..7c46872 100644 --- a/src/main/generated/kw/zeropick/review/domain/QReview.java +++ b/src/main/generated/kw/zeropick/review/domain/QReview.java @@ -1,67 +1,67 @@ -package kw.zeropick.review.domain; - -import static com.querydsl.core.types.PathMetadataFactory.*; - -import com.querydsl.core.types.dsl.*; - -import com.querydsl.core.types.PathMetadata; -import javax.annotation.processing.Generated; -import com.querydsl.core.types.Path; -import com.querydsl.core.types.dsl.PathInits; - - -/** - * QReview is a Querydsl query type for Review - */ -@Generated("com.querydsl.codegen.DefaultEntitySerializer") -public class QReview extends EntityPathBase { - - private static final long serialVersionUID = 2055381199L; - - private static final PathInits INITS = PathInits.DIRECT2; - - public static final QReview review = new QReview("review"); - - public final kw.zeropick.common.domain.QBaseEntity _super = new kw.zeropick.common.domain.QBaseEntity(this); - - public final StringPath content = createString("content"); - - //inherited - public final DateTimePath createdAt = _super.createdAt; - - public final NumberPath id = createNumber("id", Long.class); - - public final ListPath imageUrls = this.createList("imageUrls", String.class, StringPath.class, PathInits.DIRECT2); - - public final kw.zeropick.product.domain.QProduct product; - - public final NumberPath rating = createNumber("rating", Long.class); - - public final ListPath tagMappings = this.createList("tagMappings", ReviewTagMapping.class, QReviewTagMapping.class, PathInits.DIRECT2); - - //inherited - public final DateTimePath updatedAt = _super.updatedAt; - - public QReview(String variable) { - this(Review.class, forVariable(variable), INITS); - } - - public QReview(Path path) { - this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); - } - - public QReview(PathMetadata metadata) { - this(metadata, PathInits.getFor(metadata, INITS)); - } - - public QReview(PathMetadata metadata, PathInits inits) { - this(Review.class, metadata, inits); - } - - public QReview(Class type, PathMetadata metadata, PathInits inits) { - super(type, metadata, inits); - this.product = inits.isInitialized("product") ? new kw.zeropick.product.domain.QProduct(forProperty("product"), inits.get("product")) : null; - } - -} - +package kw.zeropick.review.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.PathInits; + + +/** + * QReview is a Querydsl query type for Review + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QReview extends EntityPathBase { + + private static final long serialVersionUID = 2055381199L; + + private static final PathInits INITS = PathInits.DIRECT2; + + public static final QReview review = new QReview("review"); + + public final kw.zeropick.common.domain.QBaseEntity _super = new kw.zeropick.common.domain.QBaseEntity(this); + + public final StringPath content = createString("content"); + + //inherited + public final DateTimePath createdAt = _super.createdAt; + + public final NumberPath id = createNumber("id", Long.class); + + public final ListPath imageUrls = this.createList("imageUrls", String.class, StringPath.class, PathInits.DIRECT2); + + public final kw.zeropick.product.domain.QProduct product; + + public final NumberPath rating = createNumber("rating", Long.class); + + public final ListPath tagMappings = this.createList("tagMappings", ReviewTagMapping.class, QReviewTagMapping.class, PathInits.DIRECT2); + + //inherited + public final DateTimePath updatedAt = _super.updatedAt; + + public QReview(String variable) { + this(Review.class, forVariable(variable), INITS); + } + + public QReview(Path path) { + this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); + } + + public QReview(PathMetadata metadata) { + this(metadata, PathInits.getFor(metadata, INITS)); + } + + public QReview(PathMetadata metadata, PathInits inits) { + this(Review.class, metadata, inits); + } + + public QReview(Class type, PathMetadata metadata, PathInits inits) { + super(type, metadata, inits); + this.product = inits.isInitialized("product") ? new kw.zeropick.product.domain.QProduct(forProperty("product"), inits.get("product")) : null; + } + +} + diff --git a/src/main/generated/kw/zeropick/review/domain/QReviewTag.java b/src/main/generated/kw/zeropick/review/domain/QReviewTag.java index 4d11d88..1f47d8d 100644 --- a/src/main/generated/kw/zeropick/review/domain/QReviewTag.java +++ b/src/main/generated/kw/zeropick/review/domain/QReviewTag.java @@ -1,47 +1,47 @@ -package kw.zeropick.review.domain; - -import static com.querydsl.core.types.PathMetadataFactory.*; - -import com.querydsl.core.types.dsl.*; - -import com.querydsl.core.types.PathMetadata; -import javax.annotation.processing.Generated; -import com.querydsl.core.types.Path; - - -/** - * QReviewTag is a Querydsl query type for ReviewTag - */ -@Generated("com.querydsl.codegen.DefaultEntitySerializer") -public class QReviewTag extends EntityPathBase { - - private static final long serialVersionUID = -1487355829L; - - public static final QReviewTag reviewTag = new QReviewTag("reviewTag"); - - public final NumberPath id = createNumber("id", Long.class); - - public final EnumPath negativeTagEnum = createEnum("negativeTagEnum", NegativeTagEnum.class); - - public final BooleanPath positiveNegative = createBoolean("positiveNegative"); - - public final EnumPath positiveTagEnum = createEnum("positiveTagEnum", PositiveTagEnum.class); - - public final NumberPath productId = createNumber("productId", Long.class); - - public final NumberPath tagCount = createNumber("tagCount", Integer.class); - - public QReviewTag(String variable) { - super(ReviewTag.class, forVariable(variable)); - } - - public QReviewTag(Path path) { - super(path.getType(), path.getMetadata()); - } - - public QReviewTag(PathMetadata metadata) { - super(ReviewTag.class, metadata); - } - -} - +package kw.zeropick.review.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; + + +/** + * QReviewTag is a Querydsl query type for ReviewTag + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QReviewTag extends EntityPathBase { + + private static final long serialVersionUID = -1487355829L; + + public static final QReviewTag reviewTag = new QReviewTag("reviewTag"); + + public final NumberPath id = createNumber("id", Long.class); + + public final EnumPath negativeTagEnum = createEnum("negativeTagEnum", NegativeTagEnum.class); + + public final BooleanPath positiveNegative = createBoolean("positiveNegative"); + + public final EnumPath positiveTagEnum = createEnum("positiveTagEnum", PositiveTagEnum.class); + + public final NumberPath productId = createNumber("productId", Long.class); + + public final NumberPath tagCount = createNumber("tagCount", Integer.class); + + public QReviewTag(String variable) { + super(ReviewTag.class, forVariable(variable)); + } + + public QReviewTag(Path path) { + super(path.getType(), path.getMetadata()); + } + + public QReviewTag(PathMetadata metadata) { + super(ReviewTag.class, metadata); + } + +} + diff --git a/src/main/generated/kw/zeropick/review/domain/QReviewTagMapping.java b/src/main/generated/kw/zeropick/review/domain/QReviewTagMapping.java index 60f8bb0..91f9089 100644 --- a/src/main/generated/kw/zeropick/review/domain/QReviewTagMapping.java +++ b/src/main/generated/kw/zeropick/review/domain/QReviewTagMapping.java @@ -1,62 +1,62 @@ -package kw.zeropick.review.domain; - -import static com.querydsl.core.types.PathMetadataFactory.*; - -import com.querydsl.core.types.dsl.*; - -import com.querydsl.core.types.PathMetadata; -import javax.annotation.processing.Generated; -import com.querydsl.core.types.Path; -import com.querydsl.core.types.dsl.PathInits; - - -/** - * QReviewTagMapping is a Querydsl query type for ReviewTagMapping - */ -@Generated("com.querydsl.codegen.DefaultEntitySerializer") -public class QReviewTagMapping extends EntityPathBase { - - private static final long serialVersionUID = -882108925L; - - private static final PathInits INITS = PathInits.DIRECT2; - - public static final QReviewTagMapping reviewTagMapping = new QReviewTagMapping("reviewTagMapping"); - - public final kw.zeropick.common.domain.QBaseEntity _super = new kw.zeropick.common.domain.QBaseEntity(this); - - //inherited - public final DateTimePath createdAt = _super.createdAt; - - public final NumberPath id = createNumber("id", Long.class); - - public final QReview review; - - public final QReviewTag reviewTag; - - //inherited - public final DateTimePath updatedAt = _super.updatedAt; - - public QReviewTagMapping(String variable) { - this(ReviewTagMapping.class, forVariable(variable), INITS); - } - - public QReviewTagMapping(Path path) { - this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); - } - - public QReviewTagMapping(PathMetadata metadata) { - this(metadata, PathInits.getFor(metadata, INITS)); - } - - public QReviewTagMapping(PathMetadata metadata, PathInits inits) { - this(ReviewTagMapping.class, metadata, inits); - } - - public QReviewTagMapping(Class type, PathMetadata metadata, PathInits inits) { - super(type, metadata, inits); - this.review = inits.isInitialized("review") ? new QReview(forProperty("review"), inits.get("review")) : null; - this.reviewTag = inits.isInitialized("reviewTag") ? new QReviewTag(forProperty("reviewTag")) : null; - } - -} - +package kw.zeropick.review.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.PathInits; + + +/** + * QReviewTagMapping is a Querydsl query type for ReviewTagMapping + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QReviewTagMapping extends EntityPathBase { + + private static final long serialVersionUID = -882108925L; + + private static final PathInits INITS = PathInits.DIRECT2; + + public static final QReviewTagMapping reviewTagMapping = new QReviewTagMapping("reviewTagMapping"); + + public final kw.zeropick.common.domain.QBaseEntity _super = new kw.zeropick.common.domain.QBaseEntity(this); + + //inherited + public final DateTimePath createdAt = _super.createdAt; + + public final NumberPath id = createNumber("id", Long.class); + + public final QReview review; + + public final QReviewTag reviewTag; + + //inherited + public final DateTimePath updatedAt = _super.updatedAt; + + public QReviewTagMapping(String variable) { + this(ReviewTagMapping.class, forVariable(variable), INITS); + } + + public QReviewTagMapping(Path path) { + this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); + } + + public QReviewTagMapping(PathMetadata metadata) { + this(metadata, PathInits.getFor(metadata, INITS)); + } + + public QReviewTagMapping(PathMetadata metadata, PathInits inits) { + this(ReviewTagMapping.class, metadata, inits); + } + + public QReviewTagMapping(Class type, PathMetadata metadata, PathInits inits) { + super(type, metadata, inits); + this.review = inits.isInitialized("review") ? new QReview(forProperty("review"), inits.get("review")) : null; + this.reviewTag = inits.isInitialized("reviewTag") ? new QReviewTag(forProperty("reviewTag")) : null; + } + +} + diff --git a/src/main/java/kw/zeropick/review/controller/ReviewController.java b/src/main/java/kw/zeropick/review/controller/ReviewController.java index 07f9a35..a0ba0df 100644 --- a/src/main/java/kw/zeropick/review/controller/ReviewController.java +++ b/src/main/java/kw/zeropick/review/controller/ReviewController.java @@ -15,14 +15,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RequestPart; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @Tag(name = "review", description = "리뷰 관련 API") @@ -34,7 +27,7 @@ public class ReviewController { private final ReviewService reviewService; @Operation(summary = "리뷰 등록", description = "새로운 리뷰를 등록합니다.") - @PostMapping("/create") + @PostMapping() public ResponseEntity createReview( @RequestPart(value = "review") ReviewRequestDto reviewRequestDto, @RequestPart(value = "files", required = false) List files) { @@ -43,7 +36,7 @@ public ResponseEntity createReview( } @Operation(summary = "리뷰 수정", description = "리뷰를 수정합니다.") - @PostMapping("/update/{reviewId}") + @PatchMapping("/{reviewId}") public ResponseEntity updateReview( @PathVariable Long reviewId, @RequestPart(value = "review") ReviewRequestDto reviewRequestDto, @@ -52,7 +45,12 @@ public ResponseEntity updateReview( return ResponseEntity.ok("리뷰가 성공적으로 수정되었습니다."); } - + @Operation(summary = "리뷰 삭제", description = "리뷰를 삭제합니다.") + @DeleteMapping("/{reviewId}") + public ResponseEntity deleteReview(@PathVariable Long reviewId) { + reviewService.deleteReview(reviewId); + return ResponseEntity.ok("리뷰가 성공적으로 삭제되었습니다."); + } @Operation(summary = "리뷰 조회", description = "상품에 대한 리뷰를 조회합니다.") @GetMapping("/{productId}") diff --git a/src/main/java/kw/zeropick/review/service/ReviewService.java b/src/main/java/kw/zeropick/review/service/ReviewService.java index 74b58ec..1d01f35 100644 --- a/src/main/java/kw/zeropick/review/service/ReviewService.java +++ b/src/main/java/kw/zeropick/review/service/ReviewService.java @@ -13,4 +13,5 @@ public interface ReviewService { Page getReviews(Long productId, PositiveTagEnum positiveTag, String sort, Pageable pageable); void createReview(ReviewRequestDto reviewRequestDto, List files); void updateReview(Long reviewId, ReviewRequestDto reviewRequestDto); + void deleteReview(Long reviewId); } diff --git a/src/main/java/kw/zeropick/review/service/ReviewServiceImpl.java b/src/main/java/kw/zeropick/review/service/ReviewServiceImpl.java index a7ec896..3bdd628 100644 --- a/src/main/java/kw/zeropick/review/service/ReviewServiceImpl.java +++ b/src/main/java/kw/zeropick/review/service/ReviewServiceImpl.java @@ -5,6 +5,8 @@ import java.util.List; import java.util.Optional; import java.util.stream.Collectors; + +import kw.zeropick.common.domain.exception.ResourceNotFoundException; import kw.zeropick.product.domain.Product; import kw.zeropick.product.repository.ProductJpaRepository; import kw.zeropick.review.domain.PositiveTagEnum; @@ -203,5 +205,50 @@ public void updateReview(Long reviewId, ReviewRequestDto reviewRequestDto) { productRepository.save(product); } + @Override + @Transactional + public void deleteReview(Long reviewId) { + // 삭제할 리뷰 조회 + Review review = reviewRepository.findById(reviewId) + .orElseThrow(() -> new EntityNotFoundException("해당 리뷰를 찾을 수 없습니다.")); + + Product product = review.getProduct(); + + // 리뷰의 평점을 상품에서 제거 + double newStarRate = ((product.getStarRate() * product.getReviewCount()) - review.getRating()) / (product.getReviewCount() - 1); + product.setStarRate(product.getReviewCount() > 1 ? newStarRate : 0.0); // 리뷰가 하나일 경우 별점 0으로 설정 + product.setReviewCount(product.getReviewCount() - 1); + productRepository.save(product); + + // 태그 매핑 제거 + List mappings = reviewTagMappingRepository.findAllByReview(review); + + reviewTagMappingRepository.deleteAllByReview(review); + + for (ReviewTagMapping mapping : mappings) { + ReviewTag reviewTag = mapping.getReviewTag(); + reviewTag.setTagCount(reviewTag.getTagCount() - 1); + if (reviewTag.getTagCount() <= 0) { + reviewTagRepository.delete(reviewTag); // 태그 카운트가 0이면 삭제 + } else { + reviewTagRepository.save(reviewTag); + } + } + + // 리뷰 삭제 + reviewRepository.delete(review); + + // topTags 업데이트 + List topTags = reviewTagRepository.findAll().stream() + .filter(tag -> tag.getPositiveNegative() && tag.getProductId() == product.getId() && tag.getTagCount() > 0) + .sorted((t1, t2) -> t2.getTagCount().compareTo(t1.getTagCount())) + .limit(3) + .map(ReviewTag::getPositiveTagEnum) + .collect(Collectors.toList()); + + product.setTags(topTags); + productRepository.save(product); + } + } From 5030b7adecd0ee71b11124e4292497a07e9bc46c Mon Sep 17 00:00:00 2001 From: inswal843 Date: Wed, 8 Jan 2025 15:29:01 +0900 Subject: [PATCH 4/9] =?UTF-8?q?Feat:=20=EC=83=81=ED=92=88=20=EC=9D=B8?= =?UTF-8?q?=EA=B8=B0=EB=8F=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/kw/zeropick/product/domain/Product.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/kw/zeropick/product/domain/Product.java b/src/main/java/kw/zeropick/product/domain/Product.java index ed5177c..34862c6 100644 --- a/src/main/java/kw/zeropick/product/domain/Product.java +++ b/src/main/java/kw/zeropick/product/domain/Product.java @@ -60,17 +60,22 @@ public class Product { //대표 식품명 private String foodName; + // 인기순 + private int popularity; public void incrementBookmarkCount() { this.bookmarkCount++; + this.setPopularity(); } public void decrementBookmarkCount() { this.bookmarkCount--; + this.setPopularity(); } public void incrementViewCount() { this.viewCount++; + this.setPopularity(); } public void decrementViewCount() { @@ -78,14 +83,22 @@ public void decrementViewCount() { } public void setStarRate(Double starRate) { - this.starRate = starRate; + this.starRate = Math.round(starRate * 100) / 100.0; + this.setPopularity(); } public void setReviewCount(int reviewCount) { this.reviewCount = reviewCount; + this.setPopularity(); } public void setTags(List tags) { this.tags = tags; } + + public void setPopularity(){ + this.popularity = this.viewCount*150 + this.bookmarkCount*250 + this.reviewCount*250 + Integer.parseInt(String.valueOf(this.starRate*20*350)); + } + + } From ac0b36dc575f5aceb5ecf563c75d4c98d0f068b8 Mon Sep 17 00:00:00 2001 From: inswal843 Date: Wed, 8 Jan 2025 16:19:36 +0900 Subject: [PATCH 5/9] =?UTF-8?q?Feat:=20=EC=83=81=ED=92=88=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EC=A0=95=EB=A0=AC=EA=B8=B0=EB=8A=A5=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 --- .../kw/zeropick/product/domain/QProduct.java | 10 ++ .../kw/zeropick/product/domain/Product.java | 3 +- .../zeropick/product/domain/ProductSort.java | 19 +++ .../dto/request/ProductSearchRequest.java | 2 + .../ProductQueryDslRepositoryImpl.java | 122 ++++++++++-------- 5 files changed, 101 insertions(+), 55 deletions(-) create mode 100644 src/main/java/kw/zeropick/product/domain/ProductSort.java diff --git a/src/main/generated/kw/zeropick/product/domain/QProduct.java b/src/main/generated/kw/zeropick/product/domain/QProduct.java index 4bdef2b..eb003ec 100644 --- a/src/main/generated/kw/zeropick/product/domain/QProduct.java +++ b/src/main/generated/kw/zeropick/product/domain/QProduct.java @@ -22,6 +22,8 @@ public class QProduct extends EntityPathBase { public static final QProduct product = new QProduct("product"); + public final kw.zeropick.common.domain.QBaseEntity _super = new kw.zeropick.common.domain.QBaseEntity(this); + public final StringPath bigCategory = createString("bigCategory"); public final NumberPath bookmarkCount = createNumber("bookmarkCount", Integer.class); @@ -30,6 +32,9 @@ public class QProduct extends EntityPathBase { public final EnumPath category = createEnum("category", Category.class); + //inherited + public final DateTimePath createdAt = _super.createdAt; + public final StringPath foodName = createString("foodName"); public final NumberPath id = createNumber("id", Long.class); @@ -38,6 +43,8 @@ public class QProduct extends EntityPathBase { public final QIngredient ingredient; + public final NumberPath popularity = createNumber("popularity", Integer.class); + public final NumberPath price = createNumber("price", Integer.class); public final StringPath productName = createString("productName"); @@ -50,6 +57,9 @@ public class QProduct extends EntityPathBase { public final ListPath> tags = this.>createList("tags", kw.zeropick.review.domain.PositiveTagEnum.class, EnumPath.class, PathInits.DIRECT2); + //inherited + public final DateTimePath updatedAt = _super.updatedAt; + public final NumberPath viewCount = createNumber("viewCount", Integer.class); public final BooleanPath zeroKcal = createBoolean("zeroKcal"); diff --git a/src/main/java/kw/zeropick/product/domain/Product.java b/src/main/java/kw/zeropick/product/domain/Product.java index 34862c6..fab4dfd 100644 --- a/src/main/java/kw/zeropick/product/domain/Product.java +++ b/src/main/java/kw/zeropick/product/domain/Product.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; import kw.zeropick.common.converter.StringListToStringConverter; +import kw.zeropick.common.domain.BaseEntity; import kw.zeropick.review.domain.PositiveTagEnum; import kw.zeropick.review.domain.Review; import lombok.*; @@ -16,7 +17,7 @@ @Builder @AllArgsConstructor @NoArgsConstructor -public class Product { +public class Product extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "product_id") diff --git a/src/main/java/kw/zeropick/product/domain/ProductSort.java b/src/main/java/kw/zeropick/product/domain/ProductSort.java new file mode 100644 index 0000000..9015ce3 --- /dev/null +++ b/src/main/java/kw/zeropick/product/domain/ProductSort.java @@ -0,0 +1,19 @@ +package kw.zeropick.product.domain; + +public enum ProductSort { + POPULARITY("인기순"), + NEWEST("신상품순"), + MOST_REVIEWED("리뷰 많은 순"), + HIGHEST_RATED("별점 높은 순"), + LOWEST_RATED("별점 낮은 순"); + + private final String description; + + ProductSort(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } +} diff --git a/src/main/java/kw/zeropick/product/dto/request/ProductSearchRequest.java b/src/main/java/kw/zeropick/product/dto/request/ProductSearchRequest.java index ba172ee..8445ccc 100644 --- a/src/main/java/kw/zeropick/product/dto/request/ProductSearchRequest.java +++ b/src/main/java/kw/zeropick/product/dto/request/ProductSearchRequest.java @@ -2,6 +2,7 @@ import java.util.List; import kw.zeropick.product.domain.Category; +import kw.zeropick.product.domain.ProductSort; import kw.zeropick.review.domain.PositiveTagEnum; import lombok.Builder; import lombok.Data; @@ -16,4 +17,5 @@ public class ProductSearchRequest { private Boolean exceptAllulose; private List tags; // 태그 검색 조건 private Category category; // 카테고리 검색 조건 추가 + private ProductSort sort; // 정렬기준 } \ No newline at end of file diff --git a/src/main/java/kw/zeropick/product/repository/ProductQueryDslRepositoryImpl.java b/src/main/java/kw/zeropick/product/repository/ProductQueryDslRepositoryImpl.java index fbaa843..4c78b30 100644 --- a/src/main/java/kw/zeropick/product/repository/ProductQueryDslRepositoryImpl.java +++ b/src/main/java/kw/zeropick/product/repository/ProductQueryDslRepositoryImpl.java @@ -2,6 +2,7 @@ import com.querydsl.core.BooleanBuilder; import com.querydsl.core.QueryResults; +import com.querydsl.core.types.dsl.Expressions; import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; @@ -16,86 +17,99 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; +import org.springframework.util.StringUtils; @RequiredArgsConstructor public class ProductQueryDslRepositoryImpl implements ProductQueryDslRepository { private final JPAQueryFactory queryFactory; - @PersistenceContext - private final EntityManager entityManager; + +// ProductQueryDslRepositoryImpl.java @Override public Page searchProducts(ProductSearchRequest request, Pageable pageable) { - String sql = "SELECT * FROM product WHERE 1=1"; - String countSql = "SELECT COUNT(*) FROM product WHERE 1=1"; + QProduct product = QProduct.product; + + BooleanBuilder builder = new BooleanBuilder(); - // 기본 조건 추가 - if (request.getKeyword() != null) { - sql += " AND (LOWER(product_name) LIKE :keyword OR LOWER(brand) LIKE :keyword)"; - countSql += " AND (LOWER(product_name) LIKE :keyword OR LOWER(brand) LIKE :keyword)"; + // 상품명 또는 브랜드명 검색 + if (StringUtils.hasText(request.getKeyword())) { + builder.and( + product.productName.containsIgnoreCase(request.getKeyword()) + .or(product.brand.containsIgnoreCase(request.getKeyword())) + ); } + + // zerosugar 조건 if (request.getZeroSugar() != null) { - sql += " AND zero_sugar = :zeroSugar"; - countSql += " AND zero_sugar = :zeroSugar"; - } - if (request.getZeroKcal() != null) { - sql += " AND zero_kcal = :zeroKcal"; - countSql += " AND zero_kcal = :zeroKcal"; + builder.and(product.zeroSugar.eq(request.getZeroSugar())); } - // 태그 조건 추가 (JSON_CONTAINS 사용) - if (request.getTags() != null && !request.getTags().isEmpty()) { - for (int i = 0; i < request.getTags().size(); i++) { - sql += " AND JSON_CONTAINS(tags, :tag" + i + ")"; - countSql += " AND JSON_CONTAINS(tags, :tag" + i + ")"; - } + // zerokcal 조건 + if (request.getZeroKcal() != null) { + builder.and(product.zeroKcal.eq(request.getZeroKcal())); } - // 정렬 및 페이징 - sql += " ORDER BY product_id LIMIT :offset, :limit"; - - Query query = entityManager.createNativeQuery(sql, Product.class); - - // 파라미터 바인딩 - if (request.getKeyword() != null) { - query.setParameter("keyword", "%" + request.getKeyword().toLowerCase() + "%"); + // 인공감미료 조건 + if (Boolean.TRUE.equals(request.getExceptErythritol())) { + builder.and(product.ingredient.erythritol.isNull()); } - if (request.getZeroSugar() != null) { - query.setParameter("zeroSugar", request.getZeroSugar()); - } - if (request.getZeroKcal() != null) { - query.setParameter("zeroKcal", request.getZeroKcal()); + if (Boolean.TRUE.equals(request.getExceptAllulose())) { + builder.and(product.ingredient.allulose.isNull()); } + + // 태그 조건 추가 if (request.getTags() != null && !request.getTags().isEmpty()) { - for (int i = 0; i < request.getTags().size(); i++) { - query.setParameter("tag" + i, "\"" + request.getTags().get(i).name() + "\""); + BooleanBuilder tagsCondition = new BooleanBuilder(); + for (PositiveTagEnum tag : request.getTags()) { + tagsCondition.or(Expressions.stringTemplate( + "cast({0} as text)", + product.tags + ).like("%" + tag.name() + "%")); } + builder.and(tagsCondition); } - query.setParameter("offset", pageable.getOffset()); - query.setParameter("limit", pageable.getPageSize()); - - List products = query.getResultList(); - // 총 개수 쿼리 - Query countQuery = entityManager.createNativeQuery(countSql); - if (request.getKeyword() != null) { - countQuery.setParameter("keyword", "%" + request.getKeyword().toLowerCase() + "%"); - } - if (request.getZeroSugar() != null) { - countQuery.setParameter("zeroSugar", request.getZeroSugar()); - } - if (request.getZeroKcal() != null) { - countQuery.setParameter("zeroKcal", request.getZeroKcal()); + // 카테고리 조건 추가 + if (request.getCategory() != null) { + builder.and(product.category.eq(request.getCategory())); } - if (request.getTags() != null && !request.getTags().isEmpty()) { - for (int i = 0; i < request.getTags().size(); i++) { - countQuery.setParameter("tag" + i, "\"" + request.getTags().get(i).name() + "\""); + + // 정렬 기준 추가 + JPAQuery query = queryFactory + .selectFrom(product) + .leftJoin(product.ingredient).fetchJoin() + .where(builder) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()); + + if (request.getSort() != null) { + switch (request.getSort()) { + case POPULARITY: + query.orderBy(product.popularity.desc()); + break; + case NEWEST: + query.orderBy(product.createdAt.desc()); + break; + case MOST_REVIEWED: + query.orderBy(product.reviewCount.desc()); + break; + case HIGHEST_RATED: + query.orderBy(product.starRate.desc()); + break; + case LOWEST_RATED: + query.orderBy(product.starRate.asc()); + break; } } - Long total = ((Number) countQuery.getSingleResult()).longValue(); - + // 쿼리 실행 + QueryResults results = query.fetchResults(); + List products = results.getResults(); + long total = results.getTotal(); return new PageImpl<>(products, pageable, total); } + + } \ No newline at end of file From 7f4c9622d5ac09391541b0de4b64420725255616 Mon Sep 17 00:00:00 2001 From: Suhun0331 Date: Wed, 8 Jan 2025 16:23:21 +0900 Subject: [PATCH 6/9] Feat : home setting --- .../home/controller/HomeController.java | 33 +++++++++++++++++++ .../kw/zeropick/home/service/HomeService.java | 4 +++ .../home/service/HomeServiceImpl.java | 11 +++++++ 3 files changed, 48 insertions(+) create mode 100644 src/main/java/kw/zeropick/home/controller/HomeController.java create mode 100644 src/main/java/kw/zeropick/home/service/HomeService.java create mode 100644 src/main/java/kw/zeropick/home/service/HomeServiceImpl.java diff --git a/src/main/java/kw/zeropick/home/controller/HomeController.java b/src/main/java/kw/zeropick/home/controller/HomeController.java new file mode 100644 index 0000000..3f56e56 --- /dev/null +++ b/src/main/java/kw/zeropick/home/controller/HomeController.java @@ -0,0 +1,33 @@ +package kw.zeropick.home.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.Builder; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + + +@Tag(name = "home", description = "홈 화면 API") +@Builder +@RestController +@RequestMapping("/home") +@RequiredArgsConstructor +public class HomeController { + @Operation(summary = "홈 화면 조회", description = "홈 화면을 조회합니다.") + @PostMapping + public ResponseEntity home(@RequestHeader("Authorization") String token) { + + if (token == null){ + + } + else{ + + } + + return ResponseEntity.ok("리뷰가 성공적으로 등록되었습니다."); + } +} diff --git a/src/main/java/kw/zeropick/home/service/HomeService.java b/src/main/java/kw/zeropick/home/service/HomeService.java new file mode 100644 index 0000000..c769a94 --- /dev/null +++ b/src/main/java/kw/zeropick/home/service/HomeService.java @@ -0,0 +1,4 @@ +package kw.zeropick.home.service; + +public interface HomeService { +} diff --git a/src/main/java/kw/zeropick/home/service/HomeServiceImpl.java b/src/main/java/kw/zeropick/home/service/HomeServiceImpl.java new file mode 100644 index 0000000..34811f2 --- /dev/null +++ b/src/main/java/kw/zeropick/home/service/HomeServiceImpl.java @@ -0,0 +1,11 @@ +package kw.zeropick.home.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +@RequiredArgsConstructor +public class HomeServiceImpl { +} From f17e18846fe1c792ca0a34dafeac244ebc695294 Mon Sep 17 00:00:00 2001 From: Suhun0331 Date: Wed, 8 Jan 2025 17:52:30 +0900 Subject: [PATCH 7/9] =?UTF-8?q?Feat=20:=20=ED=99=88=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=20=EC=A7=84=ED=96=89=EC=A4=91(=EC=99=84=EC=84=B1x)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../home/controller/HomeController.java | 41 +++++++--- .../home/dto/response/HomeResponse.java | 16 ++++ .../dto/response/ProductBestResponse.java | 40 ++++++++++ .../kw/zeropick/home/service/HomeService.java | 5 ++ .../home/service/HomeServiceImpl.java | 79 ++++++++++++++++++- .../repository/BookmarkJpaRepository.java | 1 + .../repository/CompareJpaRepository.java | 2 + .../repository/ProductJpaRepository.java | 6 ++ .../product/service/ProductService.java | 5 ++ .../product/service/ProductServiceImpl.java | 21 +++++ 10 files changed, 202 insertions(+), 14 deletions(-) create mode 100644 src/main/java/kw/zeropick/home/dto/response/HomeResponse.java create mode 100644 src/main/java/kw/zeropick/home/dto/response/ProductBestResponse.java diff --git a/src/main/java/kw/zeropick/home/controller/HomeController.java b/src/main/java/kw/zeropick/home/controller/HomeController.java index 9a2dee7..99c6194 100644 --- a/src/main/java/kw/zeropick/home/controller/HomeController.java +++ b/src/main/java/kw/zeropick/home/controller/HomeController.java @@ -2,13 +2,15 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import kw.zeropick.common.LoginUser; +import kw.zeropick.home.dto.response.HomeResponse; +import kw.zeropick.home.service.HomeService; +import kw.zeropick.payload.ApiResponse; +import kw.zeropick.product.service.ProductService; import lombok.Builder; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; @Tag(name = "home", description = "홈 화면 API") @@ -17,16 +19,29 @@ @RequestMapping("/home") @RequiredArgsConstructor public class HomeController { - @Operation(summary = "홈 화면 조회", description = "홈 화면을 조회합니다.") - @PostMapping - public ResponseEntity home(@RequestHeader("Authorization") String token) { - if (token == null) { + private final HomeService homeService; - } else { +// @Operation(summary = "홈 화면 조회", description = "홈 화면을 조회합니다.") +// @GetMapping +// public ResponseEntity home(@RequestHeader(value = "Authorization", required = false) String token) { +// +// if (token != null) { +// Long memberId = LoginUser.get().getId(); // 회원일 경우 ID 가져오기 +// return ResponseEntity.ok( +// HomeResponse.builder() +// .topPopularityProducts(homeService.getTopPopularityProducts(4)) +//// .recommendedProducts(homeService.getRecommendedProducts(memberId)) +// .build() +// ); +// } else{ +// // 비회원일 경우 +// return ResponseEntity.ok( +// HomeResponse.builder() +// .topPopularityProducts(homeService.getTopPopularityProducts(4)) +// .build() +// ); +// } +// } - } - - return ResponseEntity.ok("리뷰가 성공적으로 등록되었습니다."); - } } \ No newline at end of file diff --git a/src/main/java/kw/zeropick/home/dto/response/HomeResponse.java b/src/main/java/kw/zeropick/home/dto/response/HomeResponse.java new file mode 100644 index 0000000..f12c2c9 --- /dev/null +++ b/src/main/java/kw/zeropick/home/dto/response/HomeResponse.java @@ -0,0 +1,16 @@ +package kw.zeropick.home.dto.response; + +import kw.zeropick.product.dto.ProductDto; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@Builder +public class HomeResponse { + private List topPopularityProducts; // 인기 상품 리스트 + private List recommendedProducts; // 추천 상품 리스트 +} diff --git a/src/main/java/kw/zeropick/home/dto/response/ProductBestResponse.java b/src/main/java/kw/zeropick/home/dto/response/ProductBestResponse.java new file mode 100644 index 0000000..3891c4d --- /dev/null +++ b/src/main/java/kw/zeropick/home/dto/response/ProductBestResponse.java @@ -0,0 +1,40 @@ +package kw.zeropick.home.dto.response; + +import kw.zeropick.product.domain.Category; +import kw.zeropick.review.dto.response.ReviewResponse; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.Setter; + +@Builder +@Data +@AllArgsConstructor +public class ProductBestResponse { + private Long id; + + private String productName; + + private Category category; + + private Boolean zeroSugar; + + private Boolean zeroKcal; + + private int price; + + private Double starRate; + + private String imageUrl; + + private int reviewCount; + + private ReviewResponse reviewResponse; + + // 좋아요 여부 + @Setter + private Boolean bookmarked; + // 비교함 여부 + @Setter + private Boolean compared; +} diff --git a/src/main/java/kw/zeropick/home/service/HomeService.java b/src/main/java/kw/zeropick/home/service/HomeService.java index c769a94..aff6dd8 100644 --- a/src/main/java/kw/zeropick/home/service/HomeService.java +++ b/src/main/java/kw/zeropick/home/service/HomeService.java @@ -1,4 +1,9 @@ package kw.zeropick.home.service; +import kw.zeropick.home.dto.response.ProductBestResponse; + +import java.util.List; + public interface HomeService { + List getTopPopularityProducts(int limit, String token); } diff --git a/src/main/java/kw/zeropick/home/service/HomeServiceImpl.java b/src/main/java/kw/zeropick/home/service/HomeServiceImpl.java index 34811f2..fb5879f 100644 --- a/src/main/java/kw/zeropick/home/service/HomeServiceImpl.java +++ b/src/main/java/kw/zeropick/home/service/HomeServiceImpl.java @@ -1,11 +1,88 @@ package kw.zeropick.home.service; +import kw.zeropick.common.LoginUser; +import kw.zeropick.home.dto.response.ProductBestResponse; +import kw.zeropick.product.domain.Product; +import kw.zeropick.product.domain.ProductSort; +import kw.zeropick.product.dto.ProductDto; +import kw.zeropick.product.dto.request.ProductSearchRequest; +import kw.zeropick.product.service.ProductService; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; +import java.util.stream.Collectors; + @Service @Transactional @RequiredArgsConstructor -public class HomeServiceImpl { +public class HomeServiceImpl implements HomeService{ + + private final ProductService productService; + + private ProductBestResponse toProductBestResponse(Product product) { + Long memberId = null; + try { + memberId = LoginUser.get().getId(); // 로그인 사용자 정보 가져오기 + } catch (Exception e) { + // 비회원인 경우 memberId는 null로 설정 + } + + ProductBestResponse.ProductBestResponseBuilder builder = ProductBestResponse.builder() + .id(product.getId()) + .productName(product.getProductName()) + .category(product.getCategory()) + .zeroSugar(product.getZeroSugar()) + .zeroKcal(product.getZeroKcal()) + .price(product.getPrice()) + .starRate(product.getStarRate()) + .imageUrl(product.getImageUrl()) + .reviewCount(product.getReviewCount()); + + if (memberId != null) { // 회원일 경우 + builder.bookmarked(productService.isBookmarkedByUser(product.getId(), memberId)) + .compared(productService.isComparedByUser(product.getId(), memberId)); + } else { // 비회원일 경우 + builder.bookmarked(null) + .compared(null); + } + + return builder.build(); + } + + @Override + @Transactional + public List getTopPopularityProducts(int limit, String token) { + // 인기 상품 검색 요청 생성 + ProductSearchRequest productSearchRequest = ProductSearchRequest.builder() + .zeroKcal(Boolean.TRUE) + + .sort(ProductSort.POPULARITY) + .build(); + + // 상품 검색 서비스 호출 (limit 개수만 가져옴) + Page productDtos = productService.productSearch(1L, 0, limit, productSearchRequest); + + // ProductDto 리스트를 ProductBestResponse로 매핑 + return productDtos.getContent().stream() + .map(productDto -> ProductBestResponse.builder() + .id(productDto.getId()) + .productName(productDto.getProductName()) + .category(productDto.getCategory()) + .zeroSugar(productDto.getZeroSugar()) + .zeroKcal(productDto.getZeroKcal()) + .price(productDto.getPrice()) + .starRate(productDto.getStarRate()) + .imageUrl(productDto.getImageUrl()) + .reviewCount(productDto.getReviewCount()) + .reviewResponse(null) // 리뷰 관련 로직 필요 시 업데이트 + .bookmarked(productDto.getBookmarked()) + .compared(productDto.getCompared()) + .build() + ) + .toList(); + } + } diff --git a/src/main/java/kw/zeropick/product/repository/BookmarkJpaRepository.java b/src/main/java/kw/zeropick/product/repository/BookmarkJpaRepository.java index 29b7d86..c7cfd82 100644 --- a/src/main/java/kw/zeropick/product/repository/BookmarkJpaRepository.java +++ b/src/main/java/kw/zeropick/product/repository/BookmarkJpaRepository.java @@ -13,5 +13,6 @@ public interface BookmarkJpaRepository extends JpaRepository { Boolean existsByProductAndMember(Product product, Member member); Optional findByProductAndMember(Product product, Member member); Page findAllByMember(Member member, Pageable pageable); + boolean existsByProductIdAndMemberId(Long productId, Long memberId); } diff --git a/src/main/java/kw/zeropick/product/repository/CompareJpaRepository.java b/src/main/java/kw/zeropick/product/repository/CompareJpaRepository.java index ba299c5..6f0c0e6 100644 --- a/src/main/java/kw/zeropick/product/repository/CompareJpaRepository.java +++ b/src/main/java/kw/zeropick/product/repository/CompareJpaRepository.java @@ -11,4 +11,6 @@ public interface CompareJpaRepository extends JpaRepository { Boolean existsByProductAndMember(Product product, Member member); Optional findByProductAndMember(Product product, Member member); List findAllByMemberId(Long memberId); + boolean existsByProductIdAndMemberId(Long productId, Long memberId); + } diff --git a/src/main/java/kw/zeropick/product/repository/ProductJpaRepository.java b/src/main/java/kw/zeropick/product/repository/ProductJpaRepository.java index 4dc5442..bb2361d 100644 --- a/src/main/java/kw/zeropick/product/repository/ProductJpaRepository.java +++ b/src/main/java/kw/zeropick/product/repository/ProductJpaRepository.java @@ -1,7 +1,13 @@ package kw.zeropick.product.repository; import kw.zeropick.product.domain.Product; +import org.springdoc.core.converters.models.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; public interface ProductJpaRepository extends JpaRepository, ProductQueryDslRepository { + @Query(value = "SELECT p FROM Product p ORDER BY p.popularity DESC") + List findTopProductsByPopularity(); // 모든 상품을 가져오되 인기순으로 정렬 } diff --git a/src/main/java/kw/zeropick/product/service/ProductService.java b/src/main/java/kw/zeropick/product/service/ProductService.java index 54c3008..fd8b500 100644 --- a/src/main/java/kw/zeropick/product/service/ProductService.java +++ b/src/main/java/kw/zeropick/product/service/ProductService.java @@ -1,6 +1,8 @@ package kw.zeropick.product.service; import java.util.List; + +import kw.zeropick.product.domain.Product; import kw.zeropick.product.dto.ProductDto; import kw.zeropick.product.dto.request.ProductSearchRequest; import org.springframework.data.domain.Page; @@ -16,4 +18,7 @@ public interface ProductService { public ProductDto productDetail(Long productId); public Page productSearch(Long memberId, int page, int size, ProductSearchRequest productSearchRequest); + boolean isBookmarkedByUser(Long productId, Long memberId); + boolean isComparedByUser(Long productId, Long memberId); + List findTopProductsByPopularity(int limit); } diff --git a/src/main/java/kw/zeropick/product/service/ProductServiceImpl.java b/src/main/java/kw/zeropick/product/service/ProductServiceImpl.java index 2b7da1f..e970cdd 100644 --- a/src/main/java/kw/zeropick/product/service/ProductServiceImpl.java +++ b/src/main/java/kw/zeropick/product/service/ProductServiceImpl.java @@ -221,4 +221,25 @@ private IngredientDto toIngredientDto(Ingredient ingredient) { .build(); } + @Override + @Transactional + public boolean isBookmarkedByUser(Long productId, Long memberId) { + return bookmarkJpaRepository.existsByProductIdAndMemberId(productId, memberId); + } + + @Override + @Transactional + public boolean isComparedByUser(Long productId, Long memberId) { + return compareJpaRepository.existsByProductIdAndMemberId(productId, memberId); + } + + @Override + @Transactional + public List findTopProductsByPopularity(int limit) { + return productJpaRepository.findTopProductsByPopularity() + .stream() + .limit(limit) + .toList(); + } + } From b8d4ba3751a3b4d1d5b668168806c32a310f220b Mon Sep 17 00:00:00 2001 From: inswal843 Date: Wed, 8 Jan 2025 17:52:41 +0900 Subject: [PATCH 8/9] =?UTF-8?q?Feat:=20=ED=99=88=20=EC=B9=B4=ED=85=8C?= =?UTF-8?q?=EA=B3=A0=EB=A6=AC=20Best=EC=83=81=ED=92=88=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../home/controller/HomeController.java | 35 +++++++++++++ .../dto/response/ProductBestResponse.java | 40 +++++++++++++++ .../kw/zeropick/home/service/HomeService.java | 5 ++ .../home/service/HomeServiceImpl.java | 50 ++++++++++++++++++- .../kw/zeropick/product/domain/Product.java | 6 ++- .../review/service/ReviewServiceImpl.java | 8 +++ 6 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 src/main/java/kw/zeropick/home/dto/response/ProductBestResponse.java diff --git a/src/main/java/kw/zeropick/home/controller/HomeController.java b/src/main/java/kw/zeropick/home/controller/HomeController.java index 9a2dee7..46fcbb4 100644 --- a/src/main/java/kw/zeropick/home/controller/HomeController.java +++ b/src/main/java/kw/zeropick/home/controller/HomeController.java @@ -2,12 +2,23 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.List; +import kw.zeropick.common.LoginUser; +import kw.zeropick.home.dto.response.ProductBestResponse; +import kw.zeropick.home.service.HomeService; +import kw.zeropick.payload.ApiResponse; +import kw.zeropick.product.domain.Category; +import kw.zeropick.product.dto.ProductDto; import lombok.Builder; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -17,6 +28,8 @@ @RequestMapping("/home") @RequiredArgsConstructor public class HomeController { + private final HomeService homeService; + @Operation(summary = "홈 화면 조회", description = "홈 화면을 조회합니다.") @PostMapping public ResponseEntity home(@RequestHeader("Authorization") String token) { @@ -29,4 +42,26 @@ public ResponseEntity home(@RequestHeader("Authorization") String token) return ResponseEntity.ok("리뷰가 성공적으로 등록되었습니다."); } + + @Operation(summary = "홈 카테고리 베스트 조회", description = "카테고리 베스트를 조회합니다.") + @GetMapping("/category") + public ResponseEntity homeCategory(@RequestParam Category category) { + Long memberId = LoginUser.get().getId(); + try { + List productBestResponses = homeService.categoryBest(memberId, category); + return ResponseEntity.ok( + ApiResponse.builder() + .check(true) + .information(productBestResponses) + .build() + ); + } catch (Exception e) { + return ResponseEntity.internalServerError().body( + ApiResponse.builder() + .check(false) + .information(e.getMessage()) + .build() + ); + } + } } \ No newline at end of file diff --git a/src/main/java/kw/zeropick/home/dto/response/ProductBestResponse.java b/src/main/java/kw/zeropick/home/dto/response/ProductBestResponse.java new file mode 100644 index 0000000..fe7de5f --- /dev/null +++ b/src/main/java/kw/zeropick/home/dto/response/ProductBestResponse.java @@ -0,0 +1,40 @@ +package kw.zeropick.home.dto.response; + +import kw.zeropick.product.domain.Category; +import kw.zeropick.review.dto.response.ReviewResponse; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.Setter; + +@Builder +@Data +@AllArgsConstructor +public class ProductBestResponse { + private Long id; + + private String productName; + + private Category category; + + private Boolean zeroSugar; + + private Boolean zeroKcal; + + private int price; + + private Double starRate; + + private String imageUrl; + + private int reviewCount; + + private ReviewResponse reviewResponse; + + // 좋아요 여부 + @Setter + private Boolean bookmarked; + // 비교함 여부 + @Setter + private Boolean compared; +} diff --git a/src/main/java/kw/zeropick/home/service/HomeService.java b/src/main/java/kw/zeropick/home/service/HomeService.java index c769a94..670df09 100644 --- a/src/main/java/kw/zeropick/home/service/HomeService.java +++ b/src/main/java/kw/zeropick/home/service/HomeService.java @@ -1,4 +1,9 @@ package kw.zeropick.home.service; +import java.util.List; +import kw.zeropick.home.dto.response.ProductBestResponse; +import kw.zeropick.product.domain.Category; + public interface HomeService { + List categoryBest(Long memberId, Category category); } diff --git a/src/main/java/kw/zeropick/home/service/HomeServiceImpl.java b/src/main/java/kw/zeropick/home/service/HomeServiceImpl.java index 34811f2..d4a318c 100644 --- a/src/main/java/kw/zeropick/home/service/HomeServiceImpl.java +++ b/src/main/java/kw/zeropick/home/service/HomeServiceImpl.java @@ -1,11 +1,59 @@ package kw.zeropick.home.service; +import java.util.List; +import kw.zeropick.home.dto.response.ProductBestResponse; +import kw.zeropick.product.domain.Category; +import kw.zeropick.product.domain.ProductSort; +import kw.zeropick.product.dto.ProductDto; +import kw.zeropick.product.dto.request.ProductSearchRequest; +import kw.zeropick.product.service.ProductService; +import kw.zeropick.review.dto.response.ReviewResponse; +import kw.zeropick.review.service.ReviewService; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @Transactional @RequiredArgsConstructor -public class HomeServiceImpl { +public class HomeServiceImpl implements HomeService{ + private final ProductService productService; + private final ReviewService reviewService; + + @Override + public List categoryBest(Long memberId, Category category) { + ProductSearchRequest productSearchRequest = ProductSearchRequest.builder() + .category(category) + .sort(ProductSort.POPULARITY) + .build(); + + Page productDtos = productService.productSearch(memberId, 0, 3, productSearchRequest); + Pageable pageable = PageRequest.of(0, 1); + + List bestResponses = productDtos.getContent().stream().map(productDto -> { + Page reviews = reviewService.getReviews(productDto.getId(), null, "latest", pageable); + ReviewResponse latestReview = reviews.getContent().isEmpty() ? null : reviews.getContent().get(0); + + return ProductBestResponse.builder() + .id(productDto.getId()) + .productName(productDto.getProductName()) + .category(productDto.getCategory()) + .zeroSugar(productDto.getZeroSugar()) + .zeroKcal(productDto.getZeroKcal()) + .price(productDto.getPrice()) + .starRate(productDto.getStarRate()) + .imageUrl(productDto.getImageUrl()) + .reviewCount(productDto.getReviewCount()) + .reviewResponse(latestReview) + .bookmarked(productDto.getBookmarked()) + .compared(productDto.getCompared()) + .build(); + }).toList(); + + return bestResponses; + } + } diff --git a/src/main/java/kw/zeropick/product/domain/Product.java b/src/main/java/kw/zeropick/product/domain/Product.java index fab4dfd..cb1fe1a 100644 --- a/src/main/java/kw/zeropick/product/domain/Product.java +++ b/src/main/java/kw/zeropick/product/domain/Product.java @@ -95,11 +95,13 @@ public void setTags(List tags) { this.tags = tags; } - public void setPopularity(){ - this.popularity = this.viewCount*150 + this.bookmarkCount*250 + this.reviewCount*250 + Integer.parseInt(String.valueOf(this.starRate*20*350)); + public void setPopularity() { + int starRateScore = this.starRate != null ? (int) Math.round(this.starRate * 20 * 350) : 0; + this.popularity = this.viewCount * 150 + this.bookmarkCount * 250 + this.reviewCount * 250 + starRateScore; } + } diff --git a/src/main/java/kw/zeropick/review/service/ReviewServiceImpl.java b/src/main/java/kw/zeropick/review/service/ReviewServiceImpl.java index c2e63de..5cf11ec 100644 --- a/src/main/java/kw/zeropick/review/service/ReviewServiceImpl.java +++ b/src/main/java/kw/zeropick/review/service/ReviewServiceImpl.java @@ -229,6 +229,14 @@ public void deleteReview(Long reviewId) { Review review = reviewRepository.findById(reviewId) .orElseThrow(() -> new EntityNotFoundException("해당 리뷰를 찾을 수 없습니다.")); + // 이미지 삭제 추가 + List oldImageUrls = review.getImageUrls(); + if(!oldImageUrls.isEmpty()) { + for (String imageUrl : oldImageUrls) { + s3Util.deleteFile(imageUrl); + } + } + Product product = review.getProduct(); // 리뷰의 평점을 상품에서 제거 From 09dbf1e9c3bad0460a3d4c56bc89037392ce1153 Mon Sep 17 00:00:00 2001 From: inswal843 Date: Wed, 8 Jan 2025 18:10:13 +0900 Subject: [PATCH 9/9] =?UTF-8?q?Feat:=20=ED=99=88=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/kw/zeropick/home/controller/HomeController.java | 1 + src/main/java/kw/zeropick/home/service/HomeService.java | 2 ++ src/main/java/kw/zeropick/home/service/HomeServiceImpl.java | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/kw/zeropick/home/controller/HomeController.java b/src/main/java/kw/zeropick/home/controller/HomeController.java index 157c5e4..bb4fd46 100644 --- a/src/main/java/kw/zeropick/home/controller/HomeController.java +++ b/src/main/java/kw/zeropick/home/controller/HomeController.java @@ -8,6 +8,7 @@ import kw.zeropick.home.dto.response.ProductBestResponse; import kw.zeropick.home.service.HomeService; import kw.zeropick.payload.ApiResponse; +import kw.zeropick.product.domain.Category; import kw.zeropick.product.dto.ProductDto; import kw.zeropick.product.service.ProductService; import lombok.Builder; diff --git a/src/main/java/kw/zeropick/home/service/HomeService.java b/src/main/java/kw/zeropick/home/service/HomeService.java index 70290a1..2348c4f 100644 --- a/src/main/java/kw/zeropick/home/service/HomeService.java +++ b/src/main/java/kw/zeropick/home/service/HomeService.java @@ -3,8 +3,10 @@ import java.util.List; import kw.zeropick.home.dto.response.ProductBestResponse; import kw.zeropick.product.domain.Category; +import kw.zeropick.product.domain.Product; public interface HomeService { List categoryBest(Long memberId, Category category); List getTopPopularityProducts(int limit, String token); + ProductBestResponse toProductBestResponse (Product product); } diff --git a/src/main/java/kw/zeropick/home/service/HomeServiceImpl.java b/src/main/java/kw/zeropick/home/service/HomeServiceImpl.java index 4f4d34c..5f01f86 100644 --- a/src/main/java/kw/zeropick/home/service/HomeServiceImpl.java +++ b/src/main/java/kw/zeropick/home/service/HomeServiceImpl.java @@ -62,7 +62,7 @@ public List categoryBest(Long memberId, Category category) @Override @Transactional - private ProductBestResponse toProductBestResponse (Product product){ + public ProductBestResponse toProductBestResponse (Product product){ Long memberId = null; try { memberId = LoginUser.get().getId(); // 로그인 사용자 정보 가져오기