From 41b324d265fb79ca28a64d6313d45a943fbe4fad Mon Sep 17 00:00:00 2001 From: SeYoE Date: Sun, 10 Dec 2023 23:20:38 +0900 Subject: [PATCH 01/21] =?UTF-8?q?Refactor:=20=EC=A2=8B=EC=95=84=EC=9A=94?= =?UTF-8?q?=20=ED=95=99=EC=9B=90=20=EC=B4=9D=20=EA=B5=90=EC=9C=A1=EB=B9=84?= =?UTF-8?q?=20=EA=B3=84=EC=82=B0=20=EB=A1=9C=EC=A7=81=20=EC=9D=B4=EC=A0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../like/service/dto/response/LikeGetResult.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/guzzing/studayserver/domain/like/service/dto/response/LikeGetResult.java b/src/main/java/org/guzzing/studayserver/domain/like/service/dto/response/LikeGetResult.java index 08884ecee..b4240ad02 100644 --- a/src/main/java/org/guzzing/studayserver/domain/like/service/dto/response/LikeGetResult.java +++ b/src/main/java/org/guzzing/studayserver/domain/like/service/dto/response/LikeGetResult.java @@ -7,8 +7,14 @@ public record LikeGetResult( long totalFee ) { - public static LikeGetResult of(final List likeAcademyInfos, final long totalFee) { - return new LikeGetResult(likeAcademyInfos, totalFee); + public static LikeGetResult of(final List likedAcademyFeeInfos) { + return new LikeGetResult(likedAcademyFeeInfos, getTotalFee(likedAcademyFeeInfos)); + } + + private static long getTotalFee(final List likeAcademyFeeInfos) { + return likeAcademyFeeInfos.stream() + .mapToLong(LikedAcademyFeeInfo::expectedFee) + .sum(); } } From 8cf28293a91768bb85d2c7d50e50d741f42452d6 Mon Sep 17 00:00:00 2001 From: SeYoE Date: Sun, 10 Dec 2023 23:23:25 +0900 Subject: [PATCH 02/21] =?UTF-8?q?Refactor:=20=EC=A2=8B=EC=95=84=EC=9A=94?= =?UTF-8?q?=20CQRS=20=ED=8C=A8=ED=84=B4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../like/service/LikeCommandService.java | 35 +++++++++++++++ .../domain/like/service/LikeReadService.java | 45 +++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 src/main/java/org/guzzing/studayserver/domain/like/service/LikeCommandService.java create mode 100644 src/main/java/org/guzzing/studayserver/domain/like/service/LikeReadService.java diff --git a/src/main/java/org/guzzing/studayserver/domain/like/service/LikeCommandService.java b/src/main/java/org/guzzing/studayserver/domain/like/service/LikeCommandService.java new file mode 100644 index 000000000..0f4bffcf8 --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/like/service/LikeCommandService.java @@ -0,0 +1,35 @@ +package org.guzzing.studayserver.domain.like.service; + +import org.guzzing.studayserver.domain.like.model.Like; +import org.guzzing.studayserver.domain.like.repository.LikeRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +public class LikeCommandService { + + private final LikeRepository likeRepository; + + public LikeCommandService(final LikeRepository likeRepository) { + this.likeRepository = likeRepository; + } + + public Like saveLike(final long memberId, final long academyId) { + final Like like = Like.of(memberId, academyId); + return likeRepository.save(like); + } + + public void deleteLike(final long likeId) { + likeRepository.deleteById(likeId); + } + + public void deleteLikesOfMember(final long memberId) { + likeRepository.deleteByMemberId(memberId); + } + + public void deleteLikesOfAcademyAndMember(final long academyId, final long memberId) { + likeRepository.deleteByAcademyIdAndMemberId(academyId, memberId); + } + +} diff --git a/src/main/java/org/guzzing/studayserver/domain/like/service/LikeReadService.java b/src/main/java/org/guzzing/studayserver/domain/like/service/LikeReadService.java new file mode 100644 index 000000000..a224d43fc --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/like/service/LikeReadService.java @@ -0,0 +1,45 @@ +package org.guzzing.studayserver.domain.like.service; + +import java.util.List; +import org.guzzing.studayserver.domain.like.model.Like; +import org.guzzing.studayserver.domain.like.repository.LikeRepository; +import org.guzzing.studayserver.domain.like.service.dto.request.LikePostParam; +import org.guzzing.studayserver.global.exception.LikeException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +public class LikeReadService { + + private final LikeRepository likeRepository; + + public LikeReadService(final LikeRepository likeRepository) { + this.likeRepository = likeRepository; + } + + public boolean isLikedAcademy(final long academyId, final long memberId) { + return likeRepository.existsByMemberIdAndAcademyId(memberId, academyId); + } + + public List findAllLikesOfMember(final long memberId) { + return likeRepository.findByMemberId(memberId); + } + + protected void validateLikeLimit(final LikePostParam param) { + final long likeCount = likeRepository.countByMemberId(param.memberId()); + + if (likeCount >= 10) { + throw new LikeException("좋아요 개수는 10개를 넘을 수 없습니다."); + } + } + + protected void validateExistsLike(final LikePostParam param) { + final boolean existsLike = likeRepository.existsByMemberIdAndAcademyId(param.memberId(), param.academyId()); + + if (existsLike) { + throw new LikeException("이미 좋아요한 학원입니다."); + } + } + +} From d76312a0ae7260719df8c1069ce7093fab21329d Mon Sep 17 00:00:00 2001 From: SeYoE Date: Sun, 10 Dec 2023 23:24:25 +0900 Subject: [PATCH 03/21] =?UTF-8?q?Refactor:=20=EC=A2=8B=EC=95=84=EC=9A=94?= =?UTF-8?q?=20=ED=8D=BC=EC=82=AC=EB=93=9C=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/academy/facade/AcademyFacade.java | 10 +- .../like/controller/LikeRestController.java | 16 +-- .../domain/like/service/LikeFacade.java | 99 +++++++++++++++ .../domain/like/service/LikeService.java | 117 ------------------ .../domain/member/service/MemberFacade.java | 10 +- .../controller/LikeRestControllerTest.java | 10 +- ...keServiceTest.java => LikeFacadeTest.java} | 25 ++-- 7 files changed, 133 insertions(+), 154 deletions(-) create mode 100644 src/main/java/org/guzzing/studayserver/domain/like/service/LikeFacade.java delete mode 100644 src/main/java/org/guzzing/studayserver/domain/like/service/LikeService.java rename src/test/java/org/guzzing/studayserver/domain/like/service/{LikeServiceTest.java => LikeFacadeTest.java} (83%) diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacade.java b/src/main/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacade.java index a90891bfa..1e46d0cd2 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacade.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacade.java @@ -8,7 +8,7 @@ import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesByLocationWithScrollResults; import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyGetResult; import org.guzzing.studayserver.domain.academy.util.GeometryUtil; -import org.guzzing.studayserver.domain.like.service.LikeService; +import org.guzzing.studayserver.domain.like.service.LikeFacade; import org.guzzing.studayserver.domain.region.service.RegionService; import org.guzzing.studayserver.domain.region.service.dto.location.RegionResult; import org.springframework.stereotype.Service; @@ -19,12 +19,12 @@ public class AcademyFacade { private final RegionService regionService; private final AcademyService academyService; - private final LikeService likeService; + private final LikeFacade likeFacade; - public AcademyFacade(RegionService regionService, AcademyService academyService, LikeService likeService) { + public AcademyFacade(RegionService regionService, AcademyService academyService, LikeFacade likeFacade) { this.regionService = regionService; this.academyService = academyService; - this.likeService = likeService; + this.likeFacade = likeFacade; } @Transactional(readOnly = true) @@ -45,7 +45,7 @@ public AcademiesByLocationWithScrollFacadeResult findByLocationWithScroll(Academ @Transactional(readOnly = true) public AcademyDetailFacadeResult getDetailAcademy(AcademyDetailFacadeParam param) { AcademyGetResult academyGetResult = academyService.getAcademy(param.academyId()); - boolean liked = likeService.isLiked(param.academyId(), param.memberId()); + boolean liked = likeFacade.isLiked(param.academyId(), param.memberId()); return AcademyDetailFacadeResult.of(academyGetResult, liked); } diff --git a/src/main/java/org/guzzing/studayserver/domain/like/controller/LikeRestController.java b/src/main/java/org/guzzing/studayserver/domain/like/controller/LikeRestController.java index 289e92c66..24ec9d0f5 100644 --- a/src/main/java/org/guzzing/studayserver/domain/like/controller/LikeRestController.java +++ b/src/main/java/org/guzzing/studayserver/domain/like/controller/LikeRestController.java @@ -8,7 +8,7 @@ import org.guzzing.studayserver.domain.like.controller.dto.request.LikePostRequest; import org.guzzing.studayserver.domain.like.controller.dto.response.LikeGetResponses; import org.guzzing.studayserver.domain.like.controller.dto.response.LikePostResponse; -import org.guzzing.studayserver.domain.like.service.LikeService; +import org.guzzing.studayserver.domain.like.service.LikeFacade; import org.guzzing.studayserver.domain.like.service.dto.response.LikeGetResult; import org.guzzing.studayserver.domain.like.service.dto.response.LikePostResult; import org.springframework.http.ResponseEntity; @@ -26,10 +26,10 @@ @RequestMapping(path = "/likes") public class LikeRestController { - private final LikeService likeService; + private final LikeFacade likeFacade; - public LikeRestController(final LikeService likeService) { - this.likeService = likeService; + public LikeRestController(final LikeFacade likeFacade) { + this.likeFacade = likeFacade; } @PostMapping(consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) @@ -37,7 +37,7 @@ public ResponseEntity createLike( @Validated @RequestBody final LikePostRequest request, @MemberId final Long memberId ) { - final LikePostResult result = likeService.createLikeOfAcademy(LikePostRequest.to(request, memberId)); + final LikePostResult result = likeFacade.createLikeOfAcademy(LikePostRequest.to(request, memberId)); return ResponseEntity .status(CREATED) @@ -49,7 +49,7 @@ public ResponseEntity removeLike( @PathVariable final Long likeId, @MemberId final Long memberId ) { - likeService.removeLike(likeId, memberId); + likeFacade.removeLike(likeId, memberId); return ResponseEntity .noContent() @@ -61,7 +61,7 @@ public ResponseEntity removeLikeOfAcademy( @RequestParam final Long academyId, @MemberId final Long memberId ) { - likeService.deleteLikeOfAcademy(academyId, memberId); + likeFacade.deleteLikeOfAcademy(academyId, memberId); return ResponseEntity .noContent() @@ -72,7 +72,7 @@ public ResponseEntity removeLikeOfAcademy( public ResponseEntity getAllLikes( @MemberId final Long memberId ) { - final LikeGetResult allLikedAcademyInfo = likeService.findAllLikesOfMember(memberId); + final LikeGetResult allLikedAcademyInfo = likeFacade.getAllLikesOfMember(memberId); final LikeGetResponses response = LikeGetResponses.from(allLikedAcademyInfo); diff --git a/src/main/java/org/guzzing/studayserver/domain/like/service/LikeFacade.java b/src/main/java/org/guzzing/studayserver/domain/like/service/LikeFacade.java new file mode 100644 index 000000000..f8a7ffcc7 --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/like/service/LikeFacade.java @@ -0,0 +1,99 @@ +package org.guzzing.studayserver.domain.like.service; + +import java.util.List; +import org.guzzing.studayserver.domain.academy.service.AcademyAccessService; +import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyFeeInfo; +import org.guzzing.studayserver.domain.like.model.Like; +import org.guzzing.studayserver.domain.like.service.dto.request.LikePostParam; +import org.guzzing.studayserver.domain.like.service.dto.response.LikeGetResult; +import org.guzzing.studayserver.domain.like.service.dto.response.LikePostResult; +import org.guzzing.studayserver.domain.like.service.dto.response.LikedAcademyFeeInfo; +import org.guzzing.studayserver.domain.member.service.MemberAccessService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class LikeFacade { + + private final LikeReadService likeReadService; + private final LikeCommandService likeCommandService; + private final MemberAccessService memberAccessService; + private final AcademyAccessService academyAccessService; + + public LikeFacade( + final LikeReadService likeReadService, + final LikeCommandService likeCommandService, + final MemberAccessService memberAccessService, + final AcademyAccessService academyAccessService + ) { + this.likeReadService = likeReadService; + this.likeCommandService = likeCommandService; + this.memberAccessService = memberAccessService; + this.academyAccessService = academyAccessService; + } + + @Transactional + public LikePostResult createLikeOfAcademy(final LikePostParam param) { + memberAccessService.validateMember(param.memberId()); + academyAccessService.validateAcademy(param.academyId()); + + validateLikeCreation(param); + + final Like savedLike = likeCommandService.saveLike(param.memberId(), param.academyId()); + + return LikePostResult.from(savedLike); + } + + @Transactional + public void removeLike(final long likeId, final long memberId) { + memberAccessService.validateMember(memberId); + + likeCommandService.deleteLike(likeId); + } + + @Transactional + public void removeMemberLikes(final long memberId) { + likeCommandService.deleteLikesOfMember(memberId); + } + + @Transactional + public void deleteLikeOfAcademy(final long academyId, final long memberId) { + memberAccessService.validateMember(memberId); + academyAccessService.validateAcademy(academyId); + + likeCommandService.deleteLikesOfAcademyAndMember(academyId, memberId); + } + + @Transactional(readOnly = true) + public boolean isLiked(final long academyId, final long memberId) { + memberAccessService.validateMember(memberId); + academyAccessService.validateAcademy(academyId); + + return likeReadService.isLikedAcademy(academyId, memberId); + } + + @Transactional(readOnly = true) + public LikeGetResult getAllLikesOfMember(final long memberId) { + memberAccessService.validateMember(memberId); + + final List likedAcademyFeeInfos = likeReadService.findAllLikesOfMember(memberId).stream() + .map(like -> { + final AcademyFeeInfo academyFeeInfo = academyAccessService.findAcademyFeeInfo(like.getAcademyId()); + + return new LikedAcademyFeeInfo( + like.getId(), + like.getAcademyId(), + academyFeeInfo.academyName(), + academyFeeInfo.expectedFee()); + }) + .toList(); + + return LikeGetResult.of(likedAcademyFeeInfos); + } + + private void validateLikeCreation(final LikePostParam param) { + likeReadService.validateLikeLimit(param); + likeReadService.validateExistsLike(param); + } + +} diff --git a/src/main/java/org/guzzing/studayserver/domain/like/service/LikeService.java b/src/main/java/org/guzzing/studayserver/domain/like/service/LikeService.java deleted file mode 100644 index 75e091256..000000000 --- a/src/main/java/org/guzzing/studayserver/domain/like/service/LikeService.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.guzzing.studayserver.domain.like.service; - -import java.util.List; - -import org.guzzing.studayserver.domain.academy.service.AcademyAccessService; -import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyFeeInfo; -import org.guzzing.studayserver.domain.like.model.Like; -import org.guzzing.studayserver.domain.like.repository.LikeRepository; -import org.guzzing.studayserver.domain.like.service.dto.request.LikePostParam; -import org.guzzing.studayserver.domain.like.service.dto.response.LikeGetResult; -import org.guzzing.studayserver.domain.like.service.dto.response.LikePostResult; -import org.guzzing.studayserver.domain.like.service.dto.response.LikedAcademyFeeInfo; -import org.guzzing.studayserver.domain.member.annotation.ValidMember; -import org.guzzing.studayserver.domain.member.annotation.ValidatedMemberId; -import org.guzzing.studayserver.domain.member.service.MemberAccessService; -import org.guzzing.studayserver.global.exception.LikeException; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(readOnly = true) -public class LikeService { - - private final LikeRepository likeRepository; - private final AcademyAccessService academyAccessService; - private final MemberAccessService memberAccessService; - - public LikeService( - final LikeRepository likeRepository, - final AcademyAccessService academyAccessService, - final MemberAccessService memberAccessService - ) { - this.likeRepository = likeRepository; - this.academyAccessService = academyAccessService; - this.memberAccessService = memberAccessService; - } - - @Transactional - public LikePostResult createLikeOfAcademy(final LikePostParam param) { - memberAccessService.validateMember(param.memberId()); - academyAccessService.validateAcademy(param.academyId()); - - validateLikeLimit(param); - validateExistsLike(param); - - final Like savedLike = likeRepository.save( - Like.of(param.memberId(), param.academyId())); - - return LikePostResult.from(savedLike); - } - - @Transactional - public void removeLike(final Long likeId, final Long memberId) { - memberAccessService.validateMember(memberId); - - likeRepository.deleteById(likeId); - } - - @Transactional - public void removeLike(final long memberId) { - likeRepository.deleteByMemberId(memberId); - } - - @ValidMember - @Transactional - public void deleteLikeOfAcademy(final Long academyId, @ValidatedMemberId final Long memberId) { - academyAccessService.validateAcademy(academyId); - - likeRepository.deleteByAcademyIdAndMemberId(academyId, memberId); - } - - @ValidMember - public boolean isLiked(final Long academyId, @ValidatedMemberId final Long memberId) { - return likeRepository.existsByMemberIdAndAcademyId(memberId, academyId); - } - - public LikeGetResult findAllLikesOfMember(Long memberId) { - memberAccessService.validateMember(memberId); - - final List likes = likeRepository.findByMemberId(memberId); - - final List likeAcademyFeeInfos = likes.stream() - .map(like -> { - AcademyFeeInfo academyFeeInfo = academyAccessService.findAcademyFeeInfo(like.getAcademyId()); - - return new LikedAcademyFeeInfo( - like.getId(), - like.getAcademyId(), - academyFeeInfo.academyName(), - academyFeeInfo.expectedFee()); - }) - .toList(); - - final long totalFee = likeAcademyFeeInfos.stream() - .mapToLong(LikedAcademyFeeInfo::expectedFee) - .sum(); - - return LikeGetResult.of(likeAcademyFeeInfos, totalFee); - } - - private void validateLikeLimit(LikePostParam param) { - final long likeCount = likeRepository.countByMemberId(param.memberId()); - - if (likeCount >= 10) { - throw new LikeException("좋아요 개수는 10개를 넘을 수 없습니다."); - } - } - - private void validateExistsLike(LikePostParam param) { - boolean existsLike = likeRepository.existsByMemberIdAndAcademyId(param.memberId(), param.academyId()); - - if (existsLike) { - throw new LikeException("이미 좋아요한 학원입니다."); - } - } - -} diff --git a/src/main/java/org/guzzing/studayserver/domain/member/service/MemberFacade.java b/src/main/java/org/guzzing/studayserver/domain/member/service/MemberFacade.java index 4a1d55a21..67c33fcaa 100644 --- a/src/main/java/org/guzzing/studayserver/domain/member/service/MemberFacade.java +++ b/src/main/java/org/guzzing/studayserver/domain/member/service/MemberFacade.java @@ -6,7 +6,7 @@ import org.guzzing.studayserver.domain.child.service.ChildService; import org.guzzing.studayserver.domain.child.service.result.ChildrenFindResult.ChildFindResult; import org.guzzing.studayserver.domain.dashboard.service.DashboardService; -import org.guzzing.studayserver.domain.like.service.LikeService; +import org.guzzing.studayserver.domain.like.service.LikeCommandService; import org.guzzing.studayserver.domain.review.service.ReviewService; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -19,7 +19,7 @@ public class MemberFacade { private final ChildService childService; private final AcademyCalendarService calendarService; private final DashboardService dashboardService; - private final LikeService likeService; + private final LikeCommandService likeCommandService; private final ReviewService reviewService; public MemberFacade( @@ -27,14 +27,14 @@ public MemberFacade( final ChildService childService, final AcademyCalendarService calendarService, final DashboardService dashboardService, - final LikeService likeService, + final LikeCommandService likeCommandService, final ReviewService reviewService ) { this.memberService = memberService; this.childService = childService; this.calendarService = calendarService; this.dashboardService = dashboardService; - this.likeService = likeService; + this.likeCommandService = likeCommandService; this.reviewService = reviewService; } @@ -46,7 +46,7 @@ public void removeMember(final long memberId) { .toList(); reviewService.removeReview(memberId); - likeService.removeLike(memberId); + likeCommandService.deleteLikesOfMember(memberId); calendarService.removeCalendar(childIds); dashboardService.removeDashboard(childIds); childService.removeChild(memberId); diff --git a/src/test/java/org/guzzing/studayserver/domain/like/controller/LikeRestControllerTest.java b/src/test/java/org/guzzing/studayserver/domain/like/controller/LikeRestControllerTest.java index 8fda2d797..e1e6534f1 100644 --- a/src/test/java/org/guzzing/studayserver/domain/like/controller/LikeRestControllerTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/like/controller/LikeRestControllerTest.java @@ -29,7 +29,7 @@ import org.guzzing.studayserver.domain.academy.service.AcademyAccessService; import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyFeeInfo; import org.guzzing.studayserver.domain.like.controller.dto.request.LikePostRequest; -import org.guzzing.studayserver.domain.like.service.LikeService; +import org.guzzing.studayserver.domain.like.service.LikeFacade; import org.guzzing.studayserver.domain.like.service.dto.request.LikePostParam; import org.guzzing.studayserver.domain.like.service.dto.response.LikePostResult; import org.guzzing.studayserver.domain.member.annotation.ValidMemberAspect; @@ -66,7 +66,7 @@ class LikeRestControllerTest { private TestConfig testConfig; @Autowired - private LikeService likeService; + private LikeFacade likeFacade; @MockBean private AcademyAccessService academyAccessService; @@ -134,7 +134,7 @@ void createLike_MemberIdAndAcademyId_RegisterLike() throws Exception { @WithMockCustomOAuth2LoginUser void removeLike_LikeId_Remove() throws Exception { // Given - LikePostResult postResult = likeService.createLikeOfAcademy(param); + LikePostResult postResult = likeFacade.createLikeOfAcademy(param); // When ResultActions perform = mockMvc.perform(delete("/likes/{likeId}", postResult.likeId()) @@ -162,7 +162,7 @@ void removeLike_LikeId_Remove() throws Exception { @WithMockCustomOAuth2LoginUser void removeLikeOfAcademy_AcademyId_Delete() throws Exception { // Given - LikePostResult postResult = likeService.createLikeOfAcademy(param); + LikePostResult postResult = likeFacade.createLikeOfAcademy(param); // When ResultActions perform = mockMvc.perform(delete("/likes") @@ -203,7 +203,7 @@ void getAllLikes_MemberId() throws Exception { given(academyAccessService.findAcademyFeeInfo(any())) .willReturn(new AcademyFeeInfo("학원명", 100L)); - likeService.createLikeOfAcademy(param); + likeFacade.createLikeOfAcademy(param); // When ResultActions perform = mockMvc.perform(get("/likes") diff --git a/src/test/java/org/guzzing/studayserver/domain/like/service/LikeServiceTest.java b/src/test/java/org/guzzing/studayserver/domain/like/service/LikeFacadeTest.java similarity index 83% rename from src/test/java/org/guzzing/studayserver/domain/like/service/LikeServiceTest.java rename to src/test/java/org/guzzing/studayserver/domain/like/service/LikeFacadeTest.java index fc8e469ea..fbe43dd98 100644 --- a/src/test/java/org/guzzing/studayserver/domain/like/service/LikeServiceTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/like/service/LikeFacadeTest.java @@ -14,7 +14,6 @@ import org.guzzing.studayserver.domain.like.service.dto.request.LikePostParam; import org.guzzing.studayserver.domain.like.service.dto.response.LikeGetResult; import org.guzzing.studayserver.domain.like.service.dto.response.LikePostResult; -import org.guzzing.studayserver.domain.member.annotation.ValidMemberAspect; import org.guzzing.studayserver.domain.member.service.MemberAccessService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -26,10 +25,10 @@ @SpringBootTest @Transactional -class LikeServiceTest { +class LikeFacadeTest { @Autowired - private LikeService likeService; + private LikeFacade likeFacade; @Autowired private LikeRepository likeRepository; @@ -38,8 +37,6 @@ class LikeServiceTest { private AcademyAccessService academyAccessService; @MockBean private MemberAccessService memberAccessService; - @MockBean - private ValidMemberAspect validMemberAspect; private final Long memberId = 1L; private final Long academyId = 1L; @@ -55,7 +52,7 @@ void setUp() { @DisplayName("학원에 대해서 좋아요를 등록한다.") void createLikeOfAcademy_WithMemberId() { // Given & When - LikePostResult result = likeService.createLikeOfAcademy(param); + LikePostResult result = likeFacade.createLikeOfAcademy(param); // Then assertThat(result.memberId()).isEqualTo(memberId); @@ -66,10 +63,10 @@ void createLikeOfAcademy_WithMemberId() { @DisplayName("학원에 대해 등록한 좋아요를 제거한다.") void removeLikeOfAcademy_LikeId_Remove() { // Given - LikePostResult savedLike = likeService.createLikeOfAcademy(param); + LikePostResult savedLike = likeFacade.createLikeOfAcademy(param); // When - likeService.removeLike(savedLike.likeId(), memberId); + likeFacade.removeLike(savedLike.likeId(), memberId); // Then boolean result = likeRepository.existsById(savedLike.likeId()); @@ -81,10 +78,10 @@ void removeLikeOfAcademy_LikeId_Remove() { @DisplayName("학원 아이디로 등록한 좋아요를 제거한다.") void deleteLikeOfAcademy_AcademyId_Delete() { // Given - LikePostResult postResult = likeService.createLikeOfAcademy(param); + LikePostResult postResult = likeFacade.createLikeOfAcademy(param); // When - likeService.deleteLikeOfAcademy(postResult.academyId(), postResult.memberId()); + likeFacade.deleteLikeOfAcademy(postResult.academyId(), postResult.memberId()); // Then List likes = likeRepository.findByMemberId(postResult.memberId()); @@ -103,10 +100,10 @@ void findAllLikesOfMember_MemberId_AcademyInfo() { given(academyAccessService.findAcademyFeeInfo(any())) .willReturn(new AcademyFeeInfo("학원명", 100L)); - LikePostResult savedLike = likeService.createLikeOfAcademy(param); + LikePostResult savedLike = likeFacade.createLikeOfAcademy(param); // When - LikeGetResult result = likeService.findAllLikesOfMember(savedLike.memberId()); + LikeGetResult result = likeFacade.getAllLikesOfMember(savedLike.memberId()); // Then assertThat(result.likeAcademyInfos()).isNotEmpty(); @@ -123,7 +120,7 @@ void isLiked_MemberAndAcademy_ReturnTrue() { likeRepository.save(like); // When - final boolean result = likeService.isLiked(memberId, academyId); + final boolean result = likeFacade.isLiked(memberId, academyId); // Then assertThat(result).isTrue(); @@ -139,7 +136,7 @@ void isLiked_MemberAndAcademy_ReturnFalse() { likeRepository.save(like); // When - final boolean result = likeService.isLiked(memberId, 2L); + final boolean result = likeFacade.isLiked(memberId, 2L); // Then assertThat(result).isFalse(); From b7c8d06203b33653ba05a53ad6fb0ab841facdc7 Mon Sep 17 00:00:00 2001 From: SeYoE Date: Sun, 10 Dec 2023 23:24:47 +0900 Subject: [PATCH 04/21] =?UTF-8?q?Docs:=20=EC=A2=8B=EC=95=84=EC=9A=94=20API?= =?UTF-8?q?=20=EC=A3=BC=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../like/controller/LikeRestController.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/main/java/org/guzzing/studayserver/domain/like/controller/LikeRestController.java b/src/main/java/org/guzzing/studayserver/domain/like/controller/LikeRestController.java index 24ec9d0f5..d0d954a88 100644 --- a/src/main/java/org/guzzing/studayserver/domain/like/controller/LikeRestController.java +++ b/src/main/java/org/guzzing/studayserver/domain/like/controller/LikeRestController.java @@ -32,6 +32,13 @@ public LikeRestController(final LikeFacade likeFacade) { this.likeFacade = likeFacade; } + /** + * 좋아요 등록 + * + * @param request + * @param memberId + * @return LikePostResponse + */ @PostMapping(consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) public ResponseEntity createLike( @Validated @RequestBody final LikePostRequest request, @@ -44,6 +51,13 @@ public ResponseEntity createLike( .body(LikePostResponse.from(result)); } + /** + * 좋아요 단건 삭제 + * + * @param likeId + * @param memberId + * @return void + */ @DeleteMapping(path = "/{likeId}") public ResponseEntity removeLike( @PathVariable final Long likeId, @@ -56,6 +70,13 @@ public ResponseEntity removeLike( .build(); } + /** + * 멤버의 좋아요 삭제 - 회원 탈퇴 시 사용 + * + * @param academyId + * @param memberId + * @return void + */ @DeleteMapping public ResponseEntity removeLikeOfAcademy( @RequestParam final Long academyId, From 23e5905bc30764f78087ac108cf2003ee95997fd Mon Sep 17 00:00:00 2001 From: SeYoE Date: Sun, 10 Dec 2023 23:26:52 +0900 Subject: [PATCH 05/21] =?UTF-8?q?Remove:=20=EB=B6=88=ED=95=84=EC=9A=94=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../guzzing/studayserver/domain/like/service/LikeFacade.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/org/guzzing/studayserver/domain/like/service/LikeFacade.java b/src/main/java/org/guzzing/studayserver/domain/like/service/LikeFacade.java index f8a7ffcc7..856a63cd7 100644 --- a/src/main/java/org/guzzing/studayserver/domain/like/service/LikeFacade.java +++ b/src/main/java/org/guzzing/studayserver/domain/like/service/LikeFacade.java @@ -51,11 +51,6 @@ public void removeLike(final long likeId, final long memberId) { likeCommandService.deleteLike(likeId); } - @Transactional - public void removeMemberLikes(final long memberId) { - likeCommandService.deleteLikesOfMember(memberId); - } - @Transactional public void deleteLikeOfAcademy(final long academyId, final long memberId) { memberAccessService.validateMember(memberId); From 4f14f994f3414904721640619d732794d79a033d Mon Sep 17 00:00:00 2001 From: SeYoE Date: Mon, 11 Dec 2023 03:15:13 +0900 Subject: [PATCH 06/21] =?UTF-8?q?Test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DashboardRestControllerTest.java | 28 +++++++++---------- .../dashboard/facade/DashboardFacadeTest.java | 2 +- .../service/DashboardServiceTest.java | 2 +- .../controller/ReviewRestControllerTest.java | 14 +++++----- .../fixture/dashboard}/DashboardFixture.java | 2 +- .../fixture/member/MemberFixture.java | 6 +++- 6 files changed, 29 insertions(+), 25 deletions(-) rename src/test/java/org/guzzing/studayserver/{domain/dashboard/fixture => testutil/fixture/dashboard}/DashboardFixture.java (99%) diff --git a/src/test/java/org/guzzing/studayserver/domain/dashboard/controller/DashboardRestControllerTest.java b/src/test/java/org/guzzing/studayserver/domain/dashboard/controller/DashboardRestControllerTest.java index 607327b2d..cf94a7442 100644 --- a/src/test/java/org/guzzing/studayserver/domain/dashboard/controller/DashboardRestControllerTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/dashboard/controller/DashboardRestControllerTest.java @@ -2,9 +2,9 @@ import static com.epages.restdocs.apispec.MockMvcRestDocumentationWrapper.document; import static com.epages.restdocs.apispec.ResourceDocumentation.resource; -import static org.guzzing.studayserver.domain.dashboard.fixture.DashboardFixture.childId; -import static org.guzzing.studayserver.testutil.fixture.TestConfig.AUTHORIZATION_HEADER; -import static org.guzzing.studayserver.testutil.fixture.TestConfig.BEARER; +import static com.nimbusds.oauth2.sdk.token.AccessTokenType.BEARER; +import static org.guzzing.studayserver.testutil.JwtTestConfig.AUTHORIZATION_HEADER; +import static org.guzzing.studayserver.testutil.fixture.dashboard.DashboardFixture.childId; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.BDDMockito.given; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @@ -34,11 +34,11 @@ import org.guzzing.studayserver.domain.child.service.ChildAccessService; import org.guzzing.studayserver.domain.dashboard.controller.dto.request.DashboardPostRequest; import org.guzzing.studayserver.domain.dashboard.controller.dto.request.DashboardPutRequest; -import org.guzzing.studayserver.domain.dashboard.fixture.DashboardFixture; +import org.guzzing.studayserver.testutil.JwtTestConfig; +import org.guzzing.studayserver.testutil.fixture.dashboard.DashboardFixture; import org.guzzing.studayserver.domain.dashboard.model.Dashboard; import org.guzzing.studayserver.domain.member.service.MemberAccessService; import org.guzzing.studayserver.testutil.WithMockCustomOAuth2LoginUser; -import org.guzzing.studayserver.testutil.fixture.TestConfig; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -66,7 +66,7 @@ class DashboardRestControllerTest { @Autowired private ObjectMapper objectMapper; @Autowired - private TestConfig testConfig; + private JwtTestConfig jwtTestConfig; @MockBean private MemberAccessService memberAccessService; @@ -84,7 +84,7 @@ void registerDashboard_ReturnCreated() throws Exception { // When final ResultActions perform = mockMvc.perform(post("/dashboards") - .header(AUTHORIZATION_HEADER, TestConfig.BEARER + testConfig.getJwt()) + .header(AUTHORIZATION_HEADER, jwtTestConfig.getJwt()) .content(objectMapper.writeValueAsBytes(request)) .accept(APPLICATION_JSON_VALUE) .contentType(APPLICATION_JSON_VALUE)); @@ -158,7 +158,7 @@ void updateDashboard_EditDashboard() throws Exception { // When final ResultActions perform = mockMvc.perform(put("/dashboards/{dashboardId}", dashboard.getId()) - .header(AUTHORIZATION_HEADER, TestConfig.BEARER + testConfig.getJwt()) + .header(AUTHORIZATION_HEADER, jwtTestConfig.getJwt()) .content(objectMapper.writeValueAsBytes(request)) .accept(APPLICATION_JSON_VALUE) .contentType(APPLICATION_JSON_VALUE)); @@ -240,7 +240,7 @@ void getDashboard() throws Exception { // When final ResultActions perform = mockMvc.perform(get("/dashboards/{dashboardId}", dashboard.getId()) - .header(AUTHORIZATION_HEADER, BEARER + testConfig.getJwt()) + .header(AUTHORIZATION_HEADER, jwtTestConfig.getJwt()) .accept(APPLICATION_JSON_VALUE) .contentType(APPLICATION_JSON_VALUE)); @@ -336,7 +336,7 @@ void getDashboards_ByActiveOnlyBoolean_AllDashboardOfChild() throws Exception { // When final ResultActions perform = mockMvc.perform(get("/dashboards") - .header(AUTHORIZATION_HEADER, BEARER + testConfig.getJwt()) + .header(String.valueOf(AUTHORIZATION_HEADER), BEARER) .param("childId", String.valueOf(childId)) .param("active-only", String.valueOf(activeOnly)) .accept(APPLICATION_JSON_VALUE) @@ -367,7 +367,7 @@ void getDashboards_ByActiveOnlyBoolean_AllDashboardOfChild() throws Exception { .tag(TAG) .summary("아이 대시보드 전체 조회") .requestHeaders( - headerWithName(AUTHORIZATION_HEADER).description("JWT 토큰") + headerWithName(String.valueOf(AUTHORIZATION_HEADER)).description("JWT 토큰") ) .queryParameters( parameterWithName("childId").description("아이 아이디"), @@ -462,7 +462,7 @@ void removeDashboard_InActiveDashboard_Success() throws Exception { // When final ResultActions perform = mockMvc.perform(patch("/dashboards/{dashboardId}", dashboard.getId()) - .header(AUTHORIZATION_HEADER, BEARER + testConfig.getJwt()) + .header(String.valueOf(AUTHORIZATION_HEADER), BEARER) .accept(APPLICATION_JSON_VALUE) .contentType(APPLICATION_JSON_VALUE)); @@ -496,7 +496,7 @@ void revertToggleActive_Dashboard() throws Exception { // When final ResultActions perform = mockMvc.perform(patch("/dashboards/{dashboardId}/toggle", dashboard.getId()) - .header(AUTHORIZATION_HEADER, BEARER + testConfig.getJwt()) + .header(String.valueOf(AUTHORIZATION_HEADER), BEARER) .accept(APPLICATION_JSON_VALUE) .contentType(APPLICATION_JSON_VALUE)); @@ -513,7 +513,7 @@ void revertToggleActive_Dashboard() throws Exception { .tag(TAG) .summary("대시보드 활성화 반전") .requestHeaders( - headerWithName(AUTHORIZATION_HEADER).description("JWT 토큰") + headerWithName(String.valueOf(AUTHORIZATION_HEADER)).description("JWT 토큰") ) .pathParameters( parameterWithName("dashboardId").description("대시보드 아이디") diff --git a/src/test/java/org/guzzing/studayserver/domain/dashboard/facade/DashboardFacadeTest.java b/src/test/java/org/guzzing/studayserver/domain/dashboard/facade/DashboardFacadeTest.java index 1e0653764..3222b40bd 100644 --- a/src/test/java/org/guzzing/studayserver/domain/dashboard/facade/DashboardFacadeTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/dashboard/facade/DashboardFacadeTest.java @@ -13,7 +13,7 @@ import org.guzzing.studayserver.domain.dashboard.facade.dto.DashboardPatchResult; import org.guzzing.studayserver.domain.dashboard.facade.dto.DashboardPostResult; import org.guzzing.studayserver.domain.dashboard.facade.dto.DashboardPutResult; -import org.guzzing.studayserver.domain.dashboard.fixture.DashboardFixture; +import org.guzzing.studayserver.testutil.fixture.dashboard.DashboardFixture; import org.guzzing.studayserver.domain.dashboard.model.Dashboard; import org.guzzing.studayserver.domain.dashboard.service.dto.request.DashboardPostParam; import org.guzzing.studayserver.domain.dashboard.service.dto.request.DashboardPutParam; diff --git a/src/test/java/org/guzzing/studayserver/domain/dashboard/service/DashboardServiceTest.java b/src/test/java/org/guzzing/studayserver/domain/dashboard/service/DashboardServiceTest.java index 0e02a60ac..7c77ac827 100644 --- a/src/test/java/org/guzzing/studayserver/domain/dashboard/service/DashboardServiceTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/dashboard/service/DashboardServiceTest.java @@ -6,7 +6,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.List; -import org.guzzing.studayserver.domain.dashboard.fixture.DashboardFixture; +import org.guzzing.studayserver.testutil.fixture.dashboard.DashboardFixture; import org.guzzing.studayserver.domain.dashboard.model.Dashboard; import org.guzzing.studayserver.domain.dashboard.service.dto.request.DashboardPostParam; import org.guzzing.studayserver.domain.dashboard.service.dto.request.DashboardPutParam; diff --git a/src/test/java/org/guzzing/studayserver/domain/review/controller/ReviewRestControllerTest.java b/src/test/java/org/guzzing/studayserver/domain/review/controller/ReviewRestControllerTest.java index 23e549a0c..0f8045a00 100644 --- a/src/test/java/org/guzzing/studayserver/domain/review/controller/ReviewRestControllerTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/review/controller/ReviewRestControllerTest.java @@ -2,8 +2,8 @@ import static com.epages.restdocs.apispec.MockMvcRestDocumentationWrapper.document; import static com.epages.restdocs.apispec.ResourceDocumentation.resource; -import static org.guzzing.studayserver.testutil.fixture.TestConfig.AUTHORIZATION_HEADER; -import static org.guzzing.studayserver.testutil.fixture.TestConfig.BEARER; +import static com.nimbusds.oauth2.sdk.token.AccessTokenType.BEARER; +import static org.guzzing.studayserver.testutil.JwtTestConfig.AUTHORIZATION_HEADER; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; @@ -28,8 +28,8 @@ import org.guzzing.studayserver.domain.review.controller.dto.request.ReviewPostRequest; import org.guzzing.studayserver.domain.review.fixture.ReviewFixture; import org.guzzing.studayserver.domain.review.repository.ReviewRepository; +import org.guzzing.studayserver.testutil.JwtTestConfig; import org.guzzing.studayserver.testutil.WithMockCustomOAuth2LoginUser; -import org.guzzing.studayserver.testutil.fixture.TestConfig; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -52,10 +52,10 @@ class ReviewRestControllerTest { @Autowired private MockMvc mockMvc; - @Autowired - private TestConfig testConfig; @Autowired private ObjectMapper objectMapper; + @Autowired + private JwtTestConfig jwtTestConfig; @MockBean private MemberAccessService memberAccessService; @@ -82,7 +82,7 @@ void registerReview_Success() throws Exception { // When ResultActions perform = mockMvc.perform(post("/reviews") - .header(AUTHORIZATION_HEADER, BEARER + testConfig.getJwt()) + .header(AUTHORIZATION_HEADER, jwtTestConfig.getJwt()) .content(jsonBody) .accept(APPLICATION_JSON_VALUE) .contentType(APPLICATION_JSON_VALUE)); @@ -133,7 +133,7 @@ void getReviewable_NotExistsReview_Reviewable() throws Exception { // When ResultActions perform = mockMvc.perform(get("/reviews/reviewable") .param("academyId", String.valueOf(academyId)) - .header(AUTHORIZATION_HEADER, BEARER + testConfig.getJwt()) + .header(AUTHORIZATION_HEADER, jwtTestConfig.getJwt()) .accept(APPLICATION_JSON_VALUE) .contentType(APPLICATION_JSON_VALUE)); diff --git a/src/test/java/org/guzzing/studayserver/domain/dashboard/fixture/DashboardFixture.java b/src/test/java/org/guzzing/studayserver/testutil/fixture/dashboard/DashboardFixture.java similarity index 99% rename from src/test/java/org/guzzing/studayserver/domain/dashboard/fixture/DashboardFixture.java rename to src/test/java/org/guzzing/studayserver/testutil/fixture/dashboard/DashboardFixture.java index 0216362a0..f52c5f314 100644 --- a/src/test/java/org/guzzing/studayserver/domain/dashboard/fixture/DashboardFixture.java +++ b/src/test/java/org/guzzing/studayserver/testutil/fixture/dashboard/DashboardFixture.java @@ -1,4 +1,4 @@ -package org.guzzing.studayserver.domain.dashboard.fixture; +package org.guzzing.studayserver.testutil.fixture.dashboard; import static java.time.DayOfWeek.FRIDAY; import static java.time.DayOfWeek.MONDAY; diff --git a/src/test/java/org/guzzing/studayserver/testutil/fixture/member/MemberFixture.java b/src/test/java/org/guzzing/studayserver/testutil/fixture/member/MemberFixture.java index 2bbaec658..e2803d7dd 100644 --- a/src/test/java/org/guzzing/studayserver/testutil/fixture/member/MemberFixture.java +++ b/src/test/java/org/guzzing/studayserver/testutil/fixture/member/MemberFixture.java @@ -4,10 +4,14 @@ import org.guzzing.studayserver.domain.member.model.NickName; import org.guzzing.studayserver.domain.member.model.vo.MemberProvider; import org.guzzing.studayserver.domain.member.model.vo.RoleType; +import org.guzzing.studayserver.domain.member.repository.MemberRepository; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; public class MemberFixture { - public static Member member() { + public static Member makeMemberEntity() { return Member.of(new NickName("나는왕이다"), "12345678", MemberProvider.KAKAO, RoleType.USER); } From bb54094d5132e668c2f86114ccc786fe2fb754d6 Mon Sep 17 00:00:00 2001 From: SeYoE Date: Mon, 11 Dec 2023 03:19:51 +0900 Subject: [PATCH 07/21] =?UTF-8?q?Refactor:=20Like=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20=EC=A7=81=EC=A0=91=EC=B0=B8=EC=A1=B0=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../academy/service/AcademyService.java | 6 ++ .../studayserver/domain/like/model/Like.java | 37 +++++-- .../like/repository/LikeJpaRepository.java | 10 +- .../like/repository/LikeRepository.java | 16 +-- .../like/service/LikeCommandService.java | 14 +-- .../domain/like/service/LikeFacade.java | 68 +++++++----- .../domain/like/service/LikeReadService.java | 19 ++-- .../academy/facade/AcademyFacadeTest.java | 2 +- .../controller/LikeRestControllerTest.java | 102 +++++++++--------- .../domain/like/service/LikeFacadeTest.java | 85 +++++++-------- 10 files changed, 196 insertions(+), 163 deletions(-) diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java index de54f716e..a1e1c70b9 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java @@ -4,6 +4,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.guzzing.studayserver.domain.academy.model.Academy; import org.guzzing.studayserver.domain.academy.model.Lesson; import org.guzzing.studayserver.domain.academy.repository.academy.AcademyRepository; import org.guzzing.studayserver.domain.academy.repository.academycategory.AcademyCategoryRepository; @@ -46,6 +47,11 @@ public AcademyService(AcademyRepository academyRepository, LessonRepository less this.academyCategoryRepository = academyCategoryRepository; } + @Transactional(readOnly = true) + public Academy getAcademy(final long academyId) { + return academyRepository.getById(academyId); + } + @Transactional(readOnly = true) public AcademyGetResult getAcademy(Long academyId) { return AcademyGetResult.from( diff --git a/src/main/java/org/guzzing/studayserver/domain/like/model/Like.java b/src/main/java/org/guzzing/studayserver/domain/like/model/Like.java index 17d149e3b..c9423bb6e 100644 --- a/src/main/java/org/guzzing/studayserver/domain/like/model/Like.java +++ b/src/main/java/org/guzzing/studayserver/domain/like/model/Like.java @@ -1,39 +1,56 @@ package org.guzzing.studayserver.domain.like.model; +import static jakarta.persistence.FetchType.LAZY; import static lombok.AccessLevel.PROTECTED; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; import lombok.Getter; import lombok.NoArgsConstructor; +import org.guzzing.studayserver.domain.academy.model.Academy; +import org.guzzing.studayserver.domain.member.model.Member; @Getter @NoArgsConstructor(access = PROTECTED) @Entity -@Table(name = "likes") +@Table(name = "likes", uniqueConstraints = @UniqueConstraint(columnNames = {"member_id", "academy_id"})) public class Like { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(name = "member_id") - private Long memberId; + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "member_id", nullable = false) + private Member member; - @Column(name = "academy_id") - private Long academyId; + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "academy_id", nullable = false) + private Academy academy; - protected Like(final Long memberId, final Long academyId) { - this.memberId = memberId; - this.academyId = academyId; + protected Like(final Member member, final Academy academy) { + this.member = member; + this.academy = academy; } - public static Like of(final Long memberId, final Long academyId) { - return new Like(memberId, academyId); + public static Like of(final Member member, final Academy academy) { + return new Like(member, academy); + } + + public long getMemberId() { + return this.member.getId(); + } + + public long getAcademyId() { + return this.academy.getId(); } } diff --git a/src/main/java/org/guzzing/studayserver/domain/like/repository/LikeJpaRepository.java b/src/main/java/org/guzzing/studayserver/domain/like/repository/LikeJpaRepository.java index 53c0fa7e3..091833c3c 100644 --- a/src/main/java/org/guzzing/studayserver/domain/like/repository/LikeJpaRepository.java +++ b/src/main/java/org/guzzing/studayserver/domain/like/repository/LikeJpaRepository.java @@ -1,17 +1,19 @@ package org.guzzing.studayserver.domain.like.repository; import java.util.List; +import org.guzzing.studayserver.domain.academy.model.Academy; import org.guzzing.studayserver.domain.like.model.Like; +import org.guzzing.studayserver.domain.member.model.Member; import org.springframework.data.jpa.repository.JpaRepository; public interface LikeJpaRepository extends JpaRepository, LikeRepository { - List findByMemberId(final Long memberId); + List findByMember(final Member member); - long countByMemberId(final Long memberId); + long countByMember(final Member member); - boolean existsByMemberIdAndAcademyId(final Long memberId, final Long academyId); + boolean existsByMemberAndAcademy(final Member member, final Academy academy); - void deleteByAcademyIdAndMemberId(final long academyId, final long memberId); + void deleteByMemberAndAcademy(final Member member, final Academy academy); } diff --git a/src/main/java/org/guzzing/studayserver/domain/like/repository/LikeRepository.java b/src/main/java/org/guzzing/studayserver/domain/like/repository/LikeRepository.java index 656d9e08e..47fe9ef68 100644 --- a/src/main/java/org/guzzing/studayserver/domain/like/repository/LikeRepository.java +++ b/src/main/java/org/guzzing/studayserver/domain/like/repository/LikeRepository.java @@ -1,24 +1,26 @@ package org.guzzing.studayserver.domain.like.repository; import java.util.List; +import org.guzzing.studayserver.domain.academy.model.Academy; import org.guzzing.studayserver.domain.like.model.Like; +import org.guzzing.studayserver.domain.member.model.Member; public interface LikeRepository { Like save(final Like like); - void deleteById(final Long likeId); + void deleteById(final long likeId); - void deleteByMemberId(final long memberId); + void deleteByMember(final Member member); - boolean existsById(final Long id); + boolean existsById(final long id); - List findByMemberId(final Long memberId); + List findByMember(final Member member); - long countByMemberId(final Long memberId); + long countByMember(final Member member); - boolean existsByMemberIdAndAcademyId(final Long memberId, final Long academyId); + boolean existsByMemberAndAcademy(final Member member, final Academy academy); - void deleteByAcademyIdAndMemberId(final long academyId, final long memberId); + void deleteByMemberAndAcademy(final Member member, final Academy academy); } diff --git a/src/main/java/org/guzzing/studayserver/domain/like/service/LikeCommandService.java b/src/main/java/org/guzzing/studayserver/domain/like/service/LikeCommandService.java index 0f4bffcf8..4be4ec522 100644 --- a/src/main/java/org/guzzing/studayserver/domain/like/service/LikeCommandService.java +++ b/src/main/java/org/guzzing/studayserver/domain/like/service/LikeCommandService.java @@ -1,7 +1,9 @@ package org.guzzing.studayserver.domain.like.service; +import org.guzzing.studayserver.domain.academy.model.Academy; import org.guzzing.studayserver.domain.like.model.Like; import org.guzzing.studayserver.domain.like.repository.LikeRepository; +import org.guzzing.studayserver.domain.member.model.Member; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -15,8 +17,8 @@ public LikeCommandService(final LikeRepository likeRepository) { this.likeRepository = likeRepository; } - public Like saveLike(final long memberId, final long academyId) { - final Like like = Like.of(memberId, academyId); + public Like saveLike(final Member member, final Academy academy) { + final Like like = Like.of(member, academy); return likeRepository.save(like); } @@ -24,12 +26,12 @@ public void deleteLike(final long likeId) { likeRepository.deleteById(likeId); } - public void deleteLikesOfMember(final long memberId) { - likeRepository.deleteByMemberId(memberId); + public void deleteLikesOfMember(final Member member) { + likeRepository.deleteByMember(member); } - public void deleteLikesOfAcademyAndMember(final long academyId, final long memberId) { - likeRepository.deleteByAcademyIdAndMemberId(academyId, memberId); + public void deleteLikesOfAcademyAndMember(final Member member, final Academy academy) { + likeRepository.deleteByMemberAndAcademy(member, academy); } } diff --git a/src/main/java/org/guzzing/studayserver/domain/like/service/LikeFacade.java b/src/main/java/org/guzzing/studayserver/domain/like/service/LikeFacade.java index 856a63cd7..ec2404ad5 100644 --- a/src/main/java/org/guzzing/studayserver/domain/like/service/LikeFacade.java +++ b/src/main/java/org/guzzing/studayserver/domain/like/service/LikeFacade.java @@ -1,14 +1,16 @@ package org.guzzing.studayserver.domain.like.service; import java.util.List; -import org.guzzing.studayserver.domain.academy.service.AcademyAccessService; +import org.guzzing.studayserver.domain.academy.model.Academy; +import org.guzzing.studayserver.domain.academy.service.AcademyService; import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyFeeInfo; import org.guzzing.studayserver.domain.like.model.Like; import org.guzzing.studayserver.domain.like.service.dto.request.LikePostParam; import org.guzzing.studayserver.domain.like.service.dto.response.LikeGetResult; import org.guzzing.studayserver.domain.like.service.dto.response.LikePostResult; import org.guzzing.studayserver.domain.like.service.dto.response.LikedAcademyFeeInfo; -import org.guzzing.studayserver.domain.member.service.MemberAccessService; +import org.guzzing.studayserver.domain.member.model.Member; +import org.guzzing.studayserver.domain.member.service.MemberService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -17,67 +19,68 @@ public class LikeFacade { private final LikeReadService likeReadService; private final LikeCommandService likeCommandService; - private final MemberAccessService memberAccessService; - private final AcademyAccessService academyAccessService; + private final MemberService memberService; + private final AcademyService academyService; public LikeFacade( final LikeReadService likeReadService, final LikeCommandService likeCommandService, - final MemberAccessService memberAccessService, - final AcademyAccessService academyAccessService + final MemberService memberService, + final AcademyService academyService ) { this.likeReadService = likeReadService; this.likeCommandService = likeCommandService; - this.memberAccessService = memberAccessService; - this.academyAccessService = academyAccessService; + this.memberService = memberService; + this.academyService = academyService; } @Transactional public LikePostResult createLikeOfAcademy(final LikePostParam param) { - memberAccessService.validateMember(param.memberId()); - academyAccessService.validateAcademy(param.academyId()); + final Member member = getValidMember(param.memberId()); + final Academy academy = getValidAcademy(param.academyId(), member); - validateLikeCreation(param); - - final Like savedLike = likeCommandService.saveLike(param.memberId(), param.academyId()); + final Like savedLike = likeCommandService.saveLike(member, academy); return LikePostResult.from(savedLike); } @Transactional public void removeLike(final long likeId, final long memberId) { - memberAccessService.validateMember(memberId); + getValidMember(memberId); likeCommandService.deleteLike(likeId); } @Transactional - public void deleteLikeOfAcademy(final long academyId, final long memberId) { - memberAccessService.validateMember(memberId); - academyAccessService.validateAcademy(academyId); + public void deleteLikeOfAcademy(final long memberId, final long academyId) { + final Member member = getValidMember(memberId); + final Academy academy = academyService.getAcademy(academyId); - likeCommandService.deleteLikesOfAcademyAndMember(academyId, memberId); + likeCommandService.deleteLikesOfAcademyAndMember(member, academy); } @Transactional(readOnly = true) - public boolean isLiked(final long academyId, final long memberId) { - memberAccessService.validateMember(memberId); - academyAccessService.validateAcademy(academyId); + public boolean isLiked(final long memberId, final long academyId) { + final Member member = memberService.getMember(memberId); + final Academy academy = academyService.getAcademy(academyId); - return likeReadService.isLikedAcademy(academyId, memberId); + return likeReadService.isLikedAcademy(member, academy); } @Transactional(readOnly = true) public LikeGetResult getAllLikesOfMember(final long memberId) { - memberAccessService.validateMember(memberId); + final Member member = getValidMember(memberId); - final List likedAcademyFeeInfos = likeReadService.findAllLikesOfMember(memberId).stream() + final List likedAcademyFeeInfos = likeReadService.findAllLikesOfMember(member) + .stream() .map(like -> { - final AcademyFeeInfo academyFeeInfo = academyAccessService.findAcademyFeeInfo(like.getAcademyId()); + final long academyId = like.getAcademyId(); + + final AcademyFeeInfo academyFeeInfo = academyService.findAcademyFeeInfo(academyId); return new LikedAcademyFeeInfo( like.getId(), - like.getAcademyId(), + academyId, academyFeeInfo.academyName(), academyFeeInfo.expectedFee()); }) @@ -86,9 +89,16 @@ public LikeGetResult getAllLikesOfMember(final long memberId) { return LikeGetResult.of(likedAcademyFeeInfos); } - private void validateLikeCreation(final LikePostParam param) { - likeReadService.validateLikeLimit(param); - likeReadService.validateExistsLike(param); + private Member getValidMember(final long memberId) { + final Member member = memberService.getMember(memberId); + likeReadService.validateLikeLimit(member); + return member; + } + + private Academy getValidAcademy(final long academyId, final Member member) { + final Academy academy = academyService.getAcademy(academyId); + likeReadService.validateExistsLike(member, academy); + return academy; } } diff --git a/src/main/java/org/guzzing/studayserver/domain/like/service/LikeReadService.java b/src/main/java/org/guzzing/studayserver/domain/like/service/LikeReadService.java index a224d43fc..a22e5c52f 100644 --- a/src/main/java/org/guzzing/studayserver/domain/like/service/LikeReadService.java +++ b/src/main/java/org/guzzing/studayserver/domain/like/service/LikeReadService.java @@ -1,9 +1,10 @@ package org.guzzing.studayserver.domain.like.service; import java.util.List; +import org.guzzing.studayserver.domain.academy.model.Academy; import org.guzzing.studayserver.domain.like.model.Like; import org.guzzing.studayserver.domain.like.repository.LikeRepository; -import org.guzzing.studayserver.domain.like.service.dto.request.LikePostParam; +import org.guzzing.studayserver.domain.member.model.Member; import org.guzzing.studayserver.global.exception.LikeException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -18,24 +19,24 @@ public LikeReadService(final LikeRepository likeRepository) { this.likeRepository = likeRepository; } - public boolean isLikedAcademy(final long academyId, final long memberId) { - return likeRepository.existsByMemberIdAndAcademyId(memberId, academyId); + public boolean isLikedAcademy(final Member member, final Academy academy) { + return likeRepository.existsByMemberAndAcademy(member, academy); } - public List findAllLikesOfMember(final long memberId) { - return likeRepository.findByMemberId(memberId); + public List findAllLikesOfMember(final Member member) { + return likeRepository.findByMember(member); } - protected void validateLikeLimit(final LikePostParam param) { - final long likeCount = likeRepository.countByMemberId(param.memberId()); + protected void validateLikeLimit(final Member member) { + final long likeCount = likeRepository.countByMember(member); if (likeCount >= 10) { throw new LikeException("좋아요 개수는 10개를 넘을 수 없습니다."); } } - protected void validateExistsLike(final LikePostParam param) { - final boolean existsLike = likeRepository.existsByMemberIdAndAcademyId(param.memberId(), param.academyId()); + protected void validateExistsLike(final Member member, final Academy academy) { + final boolean existsLike = likeRepository.existsByMemberAndAcademy(member, academy); if (existsLike) { throw new LikeException("이미 좋아요한 학원입니다."); diff --git a/src/test/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacadeTest.java b/src/test/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacadeTest.java index 5d64b3fd0..e5a7df6c3 100644 --- a/src/test/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacadeTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacadeTest.java @@ -81,7 +81,7 @@ void setUp() { savedReviewCountAboutSungnam = reviewCountRepository.save( AcademyFixture.reviewCountDefault(savedAcademyAboutSungnam)); - likeRepository.save(Like.of(savedMember.getId(),savedAcademyAboutSungnam.getId())); + likeRepository.save(Like.of(savedMember, savedAcademyAboutSungnam)); } @Test diff --git a/src/test/java/org/guzzing/studayserver/domain/like/controller/LikeRestControllerTest.java b/src/test/java/org/guzzing/studayserver/domain/like/controller/LikeRestControllerTest.java index e1e6534f1..4f1e13d35 100644 --- a/src/test/java/org/guzzing/studayserver/domain/like/controller/LikeRestControllerTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/like/controller/LikeRestControllerTest.java @@ -2,10 +2,7 @@ import static com.epages.restdocs.apispec.MockMvcRestDocumentationWrapper.document; import static com.epages.restdocs.apispec.ResourceDocumentation.resource; -import static org.guzzing.studayserver.testutil.fixture.TestConfig.AUTHORIZATION_HEADER; -import static org.guzzing.studayserver.testutil.fixture.TestConfig.BEARER; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; +import static org.guzzing.studayserver.testutil.JwtTestConfig.AUTHORIZATION_HEADER; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; @@ -26,30 +23,34 @@ import com.epages.restdocs.apispec.ResourceSnippetParameters; import com.fasterxml.jackson.databind.ObjectMapper; -import org.guzzing.studayserver.domain.academy.service.AcademyAccessService; -import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyFeeInfo; +import org.guzzing.studayserver.domain.academy.model.Academy; +import org.guzzing.studayserver.domain.academy.repository.academy.AcademyRepository; import org.guzzing.studayserver.domain.like.controller.dto.request.LikePostRequest; -import org.guzzing.studayserver.domain.like.service.LikeFacade; -import org.guzzing.studayserver.domain.like.service.dto.request.LikePostParam; -import org.guzzing.studayserver.domain.like.service.dto.response.LikePostResult; -import org.guzzing.studayserver.domain.member.annotation.ValidMemberAspect; -import org.guzzing.studayserver.domain.member.service.MemberAccessService; +import org.guzzing.studayserver.domain.like.model.Like; +import org.guzzing.studayserver.domain.like.repository.LikeRepository; +import org.guzzing.studayserver.domain.member.model.Member; +import org.guzzing.studayserver.domain.member.repository.MemberRepository; +import org.guzzing.studayserver.testutil.JwtTestConfig; import org.guzzing.studayserver.testutil.WithMockCustomOAuth2LoginUser; -import org.guzzing.studayserver.testutil.fixture.TestConfig; +import org.guzzing.studayserver.testutil.fixture.academy.AcademyFixture; +import org.guzzing.studayserver.testutil.fixture.member.MemberFixture; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; +import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; import org.springframework.transaction.annotation.Transactional; @AutoConfigureRestDocs @AutoConfigureMockMvc +@TestMethodOrder(value = OrderAnnotation.class) @SpringBootTest @Transactional class LikeRestControllerTest { @@ -61,41 +62,40 @@ class LikeRestControllerTest { @Autowired private ObjectMapper objectMapper; - @Autowired - private TestConfig testConfig; + private JwtTestConfig jwtTestConfig; @Autowired - private LikeFacade likeFacade; - - @MockBean - private AcademyAccessService academyAccessService; - @MockBean - private MemberAccessService memberAccessService; - @MockBean - private ValidMemberAspect validMemberAspect; + private LikeRepository likeRepository; + @Autowired + private MemberRepository memberRepository; + @Autowired + private AcademyRepository academyRepository; - private final Long academyId = 1L; - private LikePostParam param; + private Member savedMember; + private Academy savedAcademy; + private Like like; @BeforeEach void setUp() { - Long memberId = 1L; - LikePostRequest request = new LikePostRequest(academyId); - param = LikePostRequest.to(request, memberId); + savedMember = memberRepository.save(MemberFixture.makeMemberEntity()); + savedAcademy = academyRepository.save(AcademyFixture.academySungnam()); + like = Like.of(savedMember, savedAcademy); } @Test + @Order(1) @DisplayName("헤더에 JWT 로 들어오는 멤버 아이디와 바디로 전달되는 학원 아이디를 이용해서 좋아요를 등록한다.") - @WithMockCustomOAuth2LoginUser + @WithMockCustomOAuth2LoginUser(memberId = 1) void createLike_MemberIdAndAcademyId_RegisterLike() throws Exception { // Given - LikePostRequest request = new LikePostRequest(academyId); + LikePostRequest request = new LikePostRequest(like.getAcademyId()); String jsonBody = objectMapper.writeValueAsString(request); // When ResultActions perform = mockMvc.perform(post("/likes") - .header(AUTHORIZATION_HEADER, BEARER + testConfig.getJwt()) + .header(AUTHORIZATION_HEADER, jwtTestConfig.getJwt()) + .param("memberId", String.valueOf(savedMember.getId())) .content(jsonBody) .accept(APPLICATION_JSON_VALUE) .contentType(APPLICATION_JSON_VALUE)); @@ -105,8 +105,8 @@ void createLike_MemberIdAndAcademyId_RegisterLike() throws Exception { .andExpect(status().isCreated()) .andExpect(content().contentTypeCompatibleWith(APPLICATION_JSON_VALUE)) .andExpect(jsonPath("$.likeId").isNumber()) - .andExpect(jsonPath("$.memberId").isNumber()) - .andExpect(jsonPath("$.academyId").value(1L)) + .andExpect(jsonPath("$.memberId").value(like.getMemberId())) + .andExpect(jsonPath("$.academyId").value(like.getAcademyId())) .andDo(document("post-like", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), @@ -130,15 +130,17 @@ void createLike_MemberIdAndAcademyId_RegisterLike() throws Exception { } @Test + @Order(2) @DisplayName("등록한 좋아요를 제거한다.") - @WithMockCustomOAuth2LoginUser + @WithMockCustomOAuth2LoginUser(memberId = 2) void removeLike_LikeId_Remove() throws Exception { // Given - LikePostResult postResult = likeFacade.createLikeOfAcademy(param); + Like savedLike = likeRepository.save(like); // When - ResultActions perform = mockMvc.perform(delete("/likes/{likeId}", postResult.likeId()) - .header(AUTHORIZATION_HEADER, BEARER + testConfig.getJwt())); + ResultActions perform = mockMvc.perform(delete("/likes/{likeId}", savedLike.getId()) + .header(AUTHORIZATION_HEADER, jwtTestConfig.getJwt()) + .param("memberId", String.valueOf(savedMember.getId()))); // Then perform.andDo(print()) @@ -158,16 +160,17 @@ void removeLike_LikeId_Remove() throws Exception { } @Test + @Order(value = 3) @DisplayName("학원 아이디로 좋아요를 삭제한다.") - @WithMockCustomOAuth2LoginUser + @WithMockCustomOAuth2LoginUser(memberId = 3) void removeLikeOfAcademy_AcademyId_Delete() throws Exception { // Given - LikePostResult postResult = likeFacade.createLikeOfAcademy(param); + likeRepository.save(like); // When ResultActions perform = mockMvc.perform(delete("/likes") - .header(AUTHORIZATION_HEADER, BEARER) - .queryParam("academyId", String.valueOf(postResult.academyId()))); + .header(AUTHORIZATION_HEADER, jwtTestConfig.getJwt()) + .queryParam("academyId", String.valueOf(savedMember.getId()))); // Then perform.andDo(print()) @@ -175,12 +178,6 @@ void removeLikeOfAcademy_AcademyId_Delete() throws Exception { .andDo(document("delete-like-academyId", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), -// requestHeaders( -// headerWithName(AUTHORIZATION_HEADER).description("JWT 토큰 (Bearer)") -// ), -// queryParameters( -// parameterWithName("academyId").description("학원 아이디") -// ) resource(ResourceSnippetParameters.builder() .tag(TAG) .summary("학원 아이디로 좋아요 제거") @@ -196,18 +193,17 @@ void removeLikeOfAcademy_AcademyId_Delete() throws Exception { } @Test + @Order(value = 4) @DisplayName("좋아요한 학원 비용 정보를 응답받는다.") - @WithMockCustomOAuth2LoginUser + @WithMockCustomOAuth2LoginUser(memberId = 4) void getAllLikes_MemberId() throws Exception { // Given - given(academyAccessService.findAcademyFeeInfo(any())) - .willReturn(new AcademyFeeInfo("학원명", 100L)); - - likeFacade.createLikeOfAcademy(param); + likeRepository.save(like); // When ResultActions perform = mockMvc.perform(get("/likes") - .header(AUTHORIZATION_HEADER, BEARER + testConfig.getJwt()) + .header(AUTHORIZATION_HEADER, jwtTestConfig.getJwt()) + .param("memberId", String.valueOf(savedMember.getId())) .accept(APPLICATION_JSON_VALUE) .contentType(APPLICATION_JSON_VALUE)); diff --git a/src/test/java/org/guzzing/studayserver/domain/like/service/LikeFacadeTest.java b/src/test/java/org/guzzing/studayserver/domain/like/service/LikeFacadeTest.java index fbe43dd98..e28889ad1 100644 --- a/src/test/java/org/guzzing/studayserver/domain/like/service/LikeFacadeTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/like/service/LikeFacadeTest.java @@ -1,26 +1,27 @@ package org.guzzing.studayserver.domain.like.service; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; +import jakarta.persistence.EntityNotFoundException; import java.util.List; import java.util.Objects; -import org.guzzing.studayserver.domain.academy.service.AcademyAccessService; -import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyFeeInfo; +import org.guzzing.studayserver.domain.academy.model.Academy; +import org.guzzing.studayserver.domain.academy.repository.academy.AcademyRepository; import org.guzzing.studayserver.domain.like.controller.dto.request.LikePostRequest; import org.guzzing.studayserver.domain.like.model.Like; import org.guzzing.studayserver.domain.like.repository.LikeRepository; import org.guzzing.studayserver.domain.like.service.dto.request.LikePostParam; import org.guzzing.studayserver.domain.like.service.dto.response.LikeGetResult; import org.guzzing.studayserver.domain.like.service.dto.response.LikePostResult; -import org.guzzing.studayserver.domain.member.service.MemberAccessService; +import org.guzzing.studayserver.domain.member.model.Member; +import org.guzzing.studayserver.domain.member.repository.MemberRepository; +import org.guzzing.studayserver.testutil.fixture.academy.AcademyFixture; +import org.guzzing.studayserver.testutil.fixture.member.MemberFixture; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.transaction.annotation.Transactional; @SpringBootTest @@ -32,44 +33,46 @@ class LikeFacadeTest { @Autowired private LikeRepository likeRepository; + @Autowired + private MemberRepository memberRepository; + @Autowired + private AcademyRepository academyRepository; - @MockBean - private AcademyAccessService academyAccessService; - @MockBean - private MemberAccessService memberAccessService; - - private final Long memberId = 1L; - private final Long academyId = 1L; - private LikePostParam param; + private Member savedMember; + private Academy savedAcademy; + private Like like; @BeforeEach void setUp() { - LikePostRequest request = new LikePostRequest(academyId); - param = LikePostRequest.to(request, memberId); + savedMember = memberRepository.save(MemberFixture.makeMemberEntity()); + savedAcademy = academyRepository.save(AcademyFixture.academySungnam()); + like = Like.of(savedMember, savedAcademy); } @Test @DisplayName("학원에 대해서 좋아요를 등록한다.") void createLikeOfAcademy_WithMemberId() { // Given & When + LikePostRequest request = new LikePostRequest(savedAcademy.getId()); + LikePostParam param = LikePostRequest.to(request, savedMember.getId()); LikePostResult result = likeFacade.createLikeOfAcademy(param); // Then - assertThat(result.memberId()).isEqualTo(memberId); - assertThat(result.academyId()).isEqualTo(academyId); + assertThat(result.memberId()).isEqualTo(savedMember.getId()); + assertThat(result.academyId()).isEqualTo(savedAcademy.getId()); } @Test @DisplayName("학원에 대해 등록한 좋아요를 제거한다.") void removeLikeOfAcademy_LikeId_Remove() { // Given - LikePostResult savedLike = likeFacade.createLikeOfAcademy(param); + Like savedLike = likeRepository.save(like); // When - likeFacade.removeLike(savedLike.likeId(), memberId); + likeFacade.removeLike(savedLike.getId(), savedLike.getMemberId()); // Then - boolean result = likeRepository.existsById(savedLike.likeId()); + boolean result = likeRepository.existsById(savedLike.getId()); assertThat(result).isFalse(); } @@ -78,16 +81,19 @@ void removeLikeOfAcademy_LikeId_Remove() { @DisplayName("학원 아이디로 등록한 좋아요를 제거한다.") void deleteLikeOfAcademy_AcademyId_Delete() { // Given - LikePostResult postResult = likeFacade.createLikeOfAcademy(param); + Like savedLike = likeRepository.save(like); // When - likeFacade.deleteLikeOfAcademy(postResult.academyId(), postResult.memberId()); + likeFacade.deleteLikeOfAcademy(savedLike.getMemberId(), savedLike.getAcademyId()); // Then - List likes = likeRepository.findByMemberId(postResult.memberId()); - List result = likes.stream() + Member member = memberRepository.findById(savedLike.getMemberId()) + .orElseThrow(EntityNotFoundException::new); + + List result = likeRepository.findByMember(member) + .stream() .map(Like::getAcademyId) - .filter(id -> Objects.equals(id, postResult.academyId())) + .filter(id -> Objects.equals(id, savedLike.getAcademyId())) .toList(); assertThat(result).isEmpty(); @@ -97,46 +103,37 @@ void deleteLikeOfAcademy_AcademyId_Delete() { @DisplayName("내가 좋아요한 모든 학원 비용 정보를 조회한다.") void findAllLikesOfMember_MemberId_AcademyInfo() { // Given - given(academyAccessService.findAcademyFeeInfo(any())) - .willReturn(new AcademyFeeInfo("학원명", 100L)); - - LikePostResult savedLike = likeFacade.createLikeOfAcademy(param); + Like savedLike = likeRepository.save(like); // When - LikeGetResult result = likeFacade.getAllLikesOfMember(savedLike.memberId()); + LikeGetResult result = likeFacade.getAllLikesOfMember(savedLike.getMemberId()); // Then assertThat(result.likeAcademyInfos()).isNotEmpty(); - assertThat(result.totalFee()).isEqualTo(100); + assertThat(result.totalFee()).isZero(); } @Test - @DisplayName("멤버가 해당 학원에 대해서 좋아요를 했는지 여부를 반환한다.") + @DisplayName("멤버가 해당 학원에 대해서 좋아요를 했으면 True 를 반환한다.") void isLiked_MemberAndAcademy_ReturnTrue() { // Given - final Long memberId = 1L; - final Long academyId = 1L; - final Like like = Like.of(memberId, academyId); - likeRepository.save(like); + Like savedLike = likeRepository.save(like); // When - final boolean result = likeFacade.isLiked(memberId, academyId); + final boolean result = likeFacade.isLiked(savedLike.getMemberId(), savedLike.getAcademyId()); // Then assertThat(result).isTrue(); } @Test - @DisplayName("멤버가 해당 학원에 대해서 좋아요를 했는지 여부를 반환한다.") + @DisplayName("멤버가 해당 학원에 대해 좋아요를 하지 않았으면 False 를 반환한다.") void isLiked_MemberAndAcademy_ReturnFalse() { // Given - final Long memberId = 1L; - final Long academyId = 1L; - final Like like = Like.of(memberId, academyId); - likeRepository.save(like); + Academy otherAcademy = academyRepository.save(AcademyFixture.twoCategoriesAcademy()); // When - final boolean result = likeFacade.isLiked(memberId, 2L); + final boolean result = likeFacade.isLiked(savedMember.getId(), otherAcademy.getId()); // Then assertThat(result).isFalse(); From ff4f43cbeae6628d50641f83e5202cab694d960f Mon Sep 17 00:00:00 2001 From: SeYoE Date: Mon, 11 Dec 2023 03:21:06 +0900 Subject: [PATCH 08/21] =?UTF-8?q?Refactor:=20=EA=B5=90=EC=9C=A1=EB=B9=84?= =?UTF-8?q?=20NPE=20=EB=B0=A9=EC=96=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/academy/repository/dto/AcademyFee.java | 2 +- .../domain/academy/service/AcademyService.java | 6 ++++++ .../academy/service/dto/result/AcademyFeeInfo.java | 2 +- .../like/service/dto/request/LikePostParam.java | 4 ++-- .../like/service/dto/response/LikeGetResult.java | 13 ++++++++++--- .../service/dto/response/LikedAcademyFeeInfo.java | 2 +- 6 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/repository/dto/AcademyFee.java b/src/main/java/org/guzzing/studayserver/domain/academy/repository/dto/AcademyFee.java index 2155f86df..2df42f7c6 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/repository/dto/AcademyFee.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/repository/dto/AcademyFee.java @@ -2,7 +2,7 @@ public interface AcademyFee { - long getMaxEducationFee(); + Long getMaxEducationFee(); String getAcademyName(); diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java index a1e1c70b9..be02a66ca 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java @@ -20,6 +20,7 @@ import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesByNameResults; import org.guzzing.studayserver.domain.academy.service.dto.result.AcademiesFilterWithScrollResults; import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyAndLessonDetailResult; +import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyFeeInfo; import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyGetResult; import org.guzzing.studayserver.domain.academy.service.dto.result.LessonInfoToCreateDashboardResults; import org.guzzing.studayserver.domain.academy.util.GeometryUtil; @@ -52,6 +53,11 @@ public Academy getAcademy(final long academyId) { return academyRepository.getById(academyId); } + @Transactional(readOnly = true) + public AcademyFeeInfo findAcademyFeeInfo(final long academyId) { + return AcademyFeeInfo.from(academyRepository.findAcademyFeeInfo(academyId)); + } + @Transactional(readOnly = true) public AcademyGetResult getAcademy(Long academyId) { return AcademyGetResult.from( diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademyFeeInfo.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademyFeeInfo.java index 0210741e1..97dcc9b4c 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademyFeeInfo.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademyFeeInfo.java @@ -4,7 +4,7 @@ public record AcademyFeeInfo( String academyName, - long expectedFee + Long expectedFee ) { public static AcademyFeeInfo from(AcademyFee academyFee) { diff --git a/src/main/java/org/guzzing/studayserver/domain/like/service/dto/request/LikePostParam.java b/src/main/java/org/guzzing/studayserver/domain/like/service/dto/request/LikePostParam.java index d89e4ddb1..6824da68e 100644 --- a/src/main/java/org/guzzing/studayserver/domain/like/service/dto/request/LikePostParam.java +++ b/src/main/java/org/guzzing/studayserver/domain/like/service/dto/request/LikePostParam.java @@ -1,8 +1,8 @@ package org.guzzing.studayserver.domain.like.service.dto.request; public record LikePostParam( - Long memberId, - Long academyId + long memberId, + long academyId ) { } diff --git a/src/main/java/org/guzzing/studayserver/domain/like/service/dto/response/LikeGetResult.java b/src/main/java/org/guzzing/studayserver/domain/like/service/dto/response/LikeGetResult.java index b4240ad02..20686f6ab 100644 --- a/src/main/java/org/guzzing/studayserver/domain/like/service/dto/response/LikeGetResult.java +++ b/src/main/java/org/guzzing/studayserver/domain/like/service/dto/response/LikeGetResult.java @@ -7,14 +7,21 @@ public record LikeGetResult( long totalFee ) { + private static final long DEFAULT_TOTAL_FEE = 0L; + public static LikeGetResult of(final List likedAcademyFeeInfos) { return new LikeGetResult(likedAcademyFeeInfos, getTotalFee(likedAcademyFeeInfos)); } private static long getTotalFee(final List likeAcademyFeeInfos) { - return likeAcademyFeeInfos.stream() - .mapToLong(LikedAcademyFeeInfo::expectedFee) - .sum(); + try { + return likeAcademyFeeInfos.stream() + .filter(likedAcademyFeeInfo -> likedAcademyFeeInfo.expectedFee() != null) + .mapToLong(LikedAcademyFeeInfo::expectedFee) + .sum(); + } catch (NullPointerException e) { + return DEFAULT_TOTAL_FEE; + } } } diff --git a/src/main/java/org/guzzing/studayserver/domain/like/service/dto/response/LikedAcademyFeeInfo.java b/src/main/java/org/guzzing/studayserver/domain/like/service/dto/response/LikedAcademyFeeInfo.java index c79147160..6dfca4b7b 100644 --- a/src/main/java/org/guzzing/studayserver/domain/like/service/dto/response/LikedAcademyFeeInfo.java +++ b/src/main/java/org/guzzing/studayserver/domain/like/service/dto/response/LikedAcademyFeeInfo.java @@ -4,7 +4,7 @@ public record LikedAcademyFeeInfo( long likeId, long academyId, String academyName, - long expectedFee + Long expectedFee ) { } From 70f461e01a55526a3ffff9c712606dd881215197 Mon Sep 17 00:00:00 2001 From: SeYoE Date: Mon, 11 Dec 2023 03:22:08 +0900 Subject: [PATCH 09/21] =?UTF-8?q?Refactor:=20=ED=8C=8C=EB=9D=BC=EB=AF=B8?= =?UTF-8?q?=ED=84=B0=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../studayserver/domain/academy/facade/AcademyFacade.java | 2 +- .../studayserver/domain/like/controller/LikeRestController.java | 2 +- .../studayserver/domain/member/service/MemberService.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacade.java b/src/main/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacade.java index 1e46d0cd2..dd5a2b2ae 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacade.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacade.java @@ -45,7 +45,7 @@ public AcademiesByLocationWithScrollFacadeResult findByLocationWithScroll(Academ @Transactional(readOnly = true) public AcademyDetailFacadeResult getDetailAcademy(AcademyDetailFacadeParam param) { AcademyGetResult academyGetResult = academyService.getAcademy(param.academyId()); - boolean liked = likeFacade.isLiked(param.academyId(), param.memberId()); + boolean liked = likeFacade.isLiked(param.memberId(), param.academyId()); return AcademyDetailFacadeResult.of(academyGetResult, liked); } diff --git a/src/main/java/org/guzzing/studayserver/domain/like/controller/LikeRestController.java b/src/main/java/org/guzzing/studayserver/domain/like/controller/LikeRestController.java index d0d954a88..04ea9c22f 100644 --- a/src/main/java/org/guzzing/studayserver/domain/like/controller/LikeRestController.java +++ b/src/main/java/org/guzzing/studayserver/domain/like/controller/LikeRestController.java @@ -82,7 +82,7 @@ public ResponseEntity removeLikeOfAcademy( @RequestParam final Long academyId, @MemberId final Long memberId ) { - likeFacade.deleteLikeOfAcademy(academyId, memberId); + likeFacade.deleteLikeOfAcademy(memberId, academyId); return ResponseEntity .noContent() diff --git a/src/main/java/org/guzzing/studayserver/domain/member/service/MemberService.java b/src/main/java/org/guzzing/studayserver/domain/member/service/MemberService.java index 07e13361c..6212ee19c 100644 --- a/src/main/java/org/guzzing/studayserver/domain/member/service/MemberService.java +++ b/src/main/java/org/guzzing/studayserver/domain/member/service/MemberService.java @@ -54,7 +54,7 @@ public MemberInformationResult getById(Long memberId) { return new MemberInformationResult(member.getNickName(), member.getEmail(), childInformationResults); } - private Member getMember(Long memberId) { + public Member getMember(final long memberId) { return memberRepository.findById(memberId) .orElseThrow(() -> new IllegalStateException("존재하지 않는 아이디입니다.")); } From 542765203818d4bf1a69bb71a4d514a964c1e667 Mon Sep 17 00:00:00 2001 From: SeYoE Date: Mon, 11 Dec 2023 03:22:38 +0900 Subject: [PATCH 10/21] =?UTF-8?q?Test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=94=BD=EC=8A=A4=EC=B2=98=20=EB=B3=80=EA=B2=BD=20=EB=8C=80?= =?UTF-8?q?=EC=9D=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/academy/facade/AcademyFacadeTest.java | 6 +++--- .../domain/academy/service/AcademyServiceTest.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacadeTest.java b/src/test/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacadeTest.java index e5a7df6c3..2d28724d8 100644 --- a/src/test/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacadeTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacadeTest.java @@ -31,7 +31,7 @@ @Transactional @SpringBootTest(webEnvironment = NONE) @Import(TestDatabaseConfig.class) -public class AcademyFacadeTest { +class AcademyFacadeTest { @Autowired private AcademyFacade academyFacade; @@ -63,7 +63,7 @@ public class AcademyFacadeTest { @BeforeEach void setUp() { - Member member = MemberFixture.member(); + Member member = MemberFixture.makeMemberEntity(); savedMember = memberRepository.save(member); Academy academyAboutSungnam = AcademyFixture.academySungnam(); @@ -99,7 +99,7 @@ void getDetailAcademy() { //Then assertAll("Academy Details", () -> assertThat(detailAcademy.academyName()).isEqualTo(savedAcademyAboutSungnam.getAcademyName()), - () -> assertThat(detailAcademy.isLiked()).isEqualTo(true), + () -> assertThat(detailAcademy.isLiked()).isTrue(), () -> assertThat(detailAcademy.contact()).isEqualTo(savedAcademyAboutSungnam.getContact()), () -> assertThat(detailAcademy.expectedFee()).isEqualTo(savedAcademyAboutSungnam.getMaxEducationFee()), () -> assertThat(detailAcademy.fullAddress()).isEqualTo(savedAcademyAboutSungnam.getFullAddress()), diff --git a/src/test/java/org/guzzing/studayserver/domain/academy/service/AcademyServiceTest.java b/src/test/java/org/guzzing/studayserver/domain/academy/service/AcademyServiceTest.java index 455350794..173c8bc7a 100644 --- a/src/test/java/org/guzzing/studayserver/domain/academy/service/AcademyServiceTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/academy/service/AcademyServiceTest.java @@ -79,7 +79,7 @@ class AcademyServiceTest { @BeforeEach void setUp() { - Member member = MemberFixture.member(); + Member member = MemberFixture.makeMemberEntity(); savedMember = memberRepository.save(member); Academy academyAboutSungnam = AcademyFixture.academySungnam(); From 37a65bed24a5dbb2fd4f1fc22124138772db2949 Mon Sep 17 00:00:00 2001 From: SeYoE Date: Mon, 11 Dec 2023 03:22:49 +0900 Subject: [PATCH 11/21] =?UTF-8?q?Test:=20JWT=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{fixture/TestConfig.java => JwtTestConfig.java} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename src/test/java/org/guzzing/studayserver/testutil/{fixture/TestConfig.java => JwtTestConfig.java} (81%) diff --git a/src/test/java/org/guzzing/studayserver/testutil/fixture/TestConfig.java b/src/test/java/org/guzzing/studayserver/testutil/JwtTestConfig.java similarity index 81% rename from src/test/java/org/guzzing/studayserver/testutil/fixture/TestConfig.java rename to src/test/java/org/guzzing/studayserver/testutil/JwtTestConfig.java index 364854fd3..e978918d4 100644 --- a/src/test/java/org/guzzing/studayserver/testutil/fixture/TestConfig.java +++ b/src/test/java/org/guzzing/studayserver/testutil/JwtTestConfig.java @@ -1,11 +1,11 @@ -package org.guzzing.studayserver.testutil.fixture; +package org.guzzing.studayserver.testutil; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration @ConfigurationProperties(prefix = "test") -public class TestConfig { +public class JwtTestConfig { public static final String AUTHORIZATION_HEADER = "Authorization"; public static final String BEARER = "Bearer "; @@ -13,7 +13,7 @@ public class TestConfig { private String jwt; public String getJwt() { - return jwt; + return BEARER + jwt; } public void setJwt(String jwt) { From 2736679a5f058b7ddaeceffcac6d160147c12f3b Mon Sep 17 00:00:00 2001 From: SeYoE Date: Mon, 11 Dec 2023 03:23:12 +0900 Subject: [PATCH 12/21] =?UTF-8?q?Refactor:=20=ED=9A=8C=EC=9B=90=20?= =?UTF-8?q?=ED=83=88=ED=87=B4=20=EA=B4=80=EB=A0=A8=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/model/Member.java | 21 +++++++++++++++++++ .../domain/member/service/MemberFacade.java | 7 +++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/guzzing/studayserver/domain/member/model/Member.java b/src/main/java/org/guzzing/studayserver/domain/member/model/Member.java index ef25074c4..f74b5406d 100644 --- a/src/main/java/org/guzzing/studayserver/domain/member/model/Member.java +++ b/src/main/java/org/guzzing/studayserver/domain/member/model/Member.java @@ -15,6 +15,7 @@ import jakarta.persistence.UniqueConstraint; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; import lombok.Getter; import org.guzzing.studayserver.domain.child.model.Child; @@ -117,4 +118,24 @@ public List getChildren() { public String getNickname() { return nickName.getValue(); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Member member = (Member) o; + return Objects.equals(id, member.id) && Objects.equals(nickName, member.nickName) + && Objects.equals(email, member.email) && Objects.equals(socialId, member.socialId) + && memberProvider == member.memberProvider && roleType == member.roleType && Objects.equals( + children, member.children); + } + + @Override + public int hashCode() { + return Objects.hash(id, nickName, email, socialId, memberProvider, roleType, children); + } } diff --git a/src/main/java/org/guzzing/studayserver/domain/member/service/MemberFacade.java b/src/main/java/org/guzzing/studayserver/domain/member/service/MemberFacade.java index 67c33fcaa..5e3625fb6 100644 --- a/src/main/java/org/guzzing/studayserver/domain/member/service/MemberFacade.java +++ b/src/main/java/org/guzzing/studayserver/domain/member/service/MemberFacade.java @@ -7,6 +7,7 @@ import org.guzzing.studayserver.domain.child.service.result.ChildrenFindResult.ChildFindResult; import org.guzzing.studayserver.domain.dashboard.service.DashboardService; import org.guzzing.studayserver.domain.like.service.LikeCommandService; +import org.guzzing.studayserver.domain.member.model.Member; import org.guzzing.studayserver.domain.review.service.ReviewService; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -40,13 +41,15 @@ public MemberFacade( @Transactional public void removeMember(final long memberId) { - List childIds = childService.findByMemberId(memberId).children() + final Member member = memberService.getMember(memberId); + + final List childIds = childService.findByMemberId(memberId).children() .stream() .map(ChildFindResult::childId) .toList(); reviewService.removeReview(memberId); - likeCommandService.deleteLikesOfMember(memberId); + likeCommandService.deleteLikesOfMember(member); calendarService.removeCalendar(childIds); dashboardService.removeDashboard(childIds); childService.removeChild(memberId); From 7ba1f97c67fb5ecb5b05ebfa08d81bf7ee2d95e8 Mon Sep 17 00:00:00 2001 From: SeYoE Date: Mon, 11 Dec 2023 03:23:49 +0900 Subject: [PATCH 13/21] =?UTF-8?q?Style:=20=EC=BD=94=EB=93=9C=20=EB=A6=AC?= =?UTF-8?q?=ED=8F=AC=EB=A7=A4=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../academy/controller/AcademyController.java | 3 ++- .../dto/response/AcademyGetResponse.java | 2 -- .../domain/academy/facade/AcademyFacade.java | 3 ++- .../facade/dto/AcademyDetailFacadeResult.java | 3 +-- .../academy/AcademyQueryRepositoryImpl.java | 5 +---- .../dto/AcademiesByLocationWithScroll.java | 8 ++++--- .../dto/AcademyByLocationWithScroll.java | 3 +-- .../academy/service/AcademyService.java | 8 +++---- .../AcademiesByLocationWithScrollResults.java | 21 +++++++++---------- .../studayserver/domain/like/model/Like.java | 2 -- .../academy/facade/AcademyFacadeTest.java | 11 +++++----- .../DashboardRestControllerTest.java | 4 ++-- .../dashboard/facade/DashboardFacadeTest.java | 2 +- .../service/DashboardServiceTest.java | 2 +- .../controller/ReviewRestControllerTest.java | 1 - .../fixture/academy/AcademyFixture.java | 6 +++--- .../fixture/member/MemberFixture.java | 4 ---- 17 files changed, 39 insertions(+), 49 deletions(-) diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/controller/AcademyController.java b/src/main/java/org/guzzing/studayserver/domain/academy/controller/AcademyController.java index 00fbff400..536709884 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/controller/AcademyController.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/controller/AcademyController.java @@ -46,7 +46,8 @@ public ResponseEntity getAcademy( @PathVariable Long academyId, @MemberId Long memberId ) { - AcademyDetailFacadeResult detailAcademy = academyFacade.getDetailAcademy(AcademyDetailFacadeParam.of(memberId, academyId)); + AcademyDetailFacadeResult detailAcademy = academyFacade.getDetailAcademy( + AcademyDetailFacadeParam.of(memberId, academyId)); return ResponseEntity.status(HttpStatus.OK) .body(AcademyGetResponse.from(detailAcademy)); diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademyGetResponse.java b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademyGetResponse.java index 6bec68cea..604dd6815 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademyGetResponse.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/controller/dto/response/AcademyGetResponse.java @@ -1,9 +1,7 @@ package org.guzzing.studayserver.domain.academy.controller.dto.response; import java.util.List; - import org.guzzing.studayserver.domain.academy.facade.dto.AcademyDetailFacadeResult; -import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyGetResult; public record AcademyGetResponse( String academyName, diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacade.java b/src/main/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacade.java index dd5a2b2ae..9bf9ea52c 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacade.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacade.java @@ -28,7 +28,8 @@ public AcademyFacade(RegionService regionService, AcademyService academyService, } @Transactional(readOnly = true) - public AcademiesByLocationWithScrollFacadeResult findByLocationWithScroll(AcademiesByLocationWithScrollFacadeParam param) { + public AcademiesByLocationWithScrollFacadeResult findByLocationWithScroll( + AcademiesByLocationWithScrollFacadeParam param) { AcademiesByLocationWithScrollResults academiesByLocationWithScroll = academyService.findAcademiesByLocationWithScroll( AcademiesByLocationWithScrollFacadeParam.to(param)); diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/facade/dto/AcademyDetailFacadeResult.java b/src/main/java/org/guzzing/studayserver/domain/academy/facade/dto/AcademyDetailFacadeResult.java index 6b1168780..a8d6d1aeb 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/facade/dto/AcademyDetailFacadeResult.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/facade/dto/AcademyDetailFacadeResult.java @@ -1,11 +1,10 @@ package org.guzzing.studayserver.domain.academy.facade.dto; +import java.util.List; import org.guzzing.studayserver.domain.academy.service.dto.result.AcademyGetResult; import org.guzzing.studayserver.domain.academy.service.dto.result.LessonGetResults; import org.guzzing.studayserver.domain.academy.service.dto.result.ReviewPercentGetResult; -import java.util.List; - public record AcademyDetailFacadeResult( String academyName, String contact, diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyQueryRepositoryImpl.java b/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyQueryRepositoryImpl.java index 6a8160860..7f1992180 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyQueryRepositoryImpl.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/repository/academy/AcademyQueryRepositoryImpl.java @@ -2,9 +2,7 @@ import jakarta.persistence.EntityManager; import jakarta.persistence.Query; - import java.util.List; - import org.guzzing.studayserver.domain.academy.repository.dto.AcademiesByFilterWithScroll; import org.guzzing.studayserver.domain.academy.repository.dto.AcademiesByLocationWithScroll; import org.guzzing.studayserver.domain.academy.repository.dto.AcademyByFilterWithScroll; @@ -67,7 +65,7 @@ public AcademiesByLocationWithScroll findAcademiesByLocation( .addScalar("longitude", StandardBasicTypes.DOUBLE) .addScalar("shuttleAvailable", StandardBasicTypes.STRING) .addScalar("isLiked", StandardBasicTypes.BOOLEAN) - .addScalar("categoryId",StandardBasicTypes.LONG) + .addScalar("categoryId", StandardBasicTypes.LONG) .setResultTransformer((tuple, aliases) -> new AcademyByLocationWithScroll( (Long) tuple[0], (String) tuple[1], @@ -81,7 +79,6 @@ public AcademiesByLocationWithScroll findAcademiesByLocation( )) .getResultList(); - return AcademiesByLocationWithScroll.of( academiesByLocation, isHasNest(academiesByLocation.size(), pageSize) diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/repository/dto/AcademiesByLocationWithScroll.java b/src/main/java/org/guzzing/studayserver/domain/academy/repository/dto/AcademiesByLocationWithScroll.java index e83c672ce..1fa6b3c98 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/repository/dto/AcademiesByLocationWithScroll.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/repository/dto/AcademiesByLocationWithScroll.java @@ -3,11 +3,10 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; public record AcademiesByLocationWithScroll( - Map> academiesByLocation, + Map> academiesByLocation, boolean hasNext ) { @@ -18,7 +17,8 @@ public static AcademiesByLocationWithScroll of( Map> academyIdWithCategories = new ConcurrentHashMap<>(); academiesByLocation.forEach(academyByLocationWithScroll -> { - academyIdWithCategories.computeIfAbsent(AcademyByLocation.of(academyByLocationWithScroll), k -> new ArrayList<>()) + academyIdWithCategories.computeIfAbsent(AcademyByLocation.of(academyByLocationWithScroll), + k -> new ArrayList<>()) .add(academyByLocationWithScroll.categoryId()); }); @@ -27,6 +27,7 @@ public static AcademiesByLocationWithScroll of( hasNext ); } + public record AcademyByLocation( Long academyId, String academyName, @@ -37,6 +38,7 @@ public record AcademyByLocation( String shuttleAvailable, boolean isLiked ) { + public static AcademyByLocation of(AcademyByLocationWithScroll academyByLocationWithScroll) { return new AcademyByLocation( academyByLocationWithScroll.academyId(), diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/repository/dto/AcademyByLocationWithScroll.java b/src/main/java/org/guzzing/studayserver/domain/academy/repository/dto/AcademyByLocationWithScroll.java index fc948a9df..5db346689 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/repository/dto/AcademyByLocationWithScroll.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/repository/dto/AcademyByLocationWithScroll.java @@ -1,7 +1,5 @@ package org.guzzing.studayserver.domain.academy.repository.dto; -import java.util.Objects; - public record AcademyByLocationWithScroll( Long academyId, String academyName, @@ -13,4 +11,5 @@ public record AcademyByLocationWithScroll( boolean isLiked, Long categoryId ) { + } diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java index be02a66ca..8480fcae4 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java @@ -3,7 +3,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; - import org.guzzing.studayserver.domain.academy.model.Academy; import org.guzzing.studayserver.domain.academy.model.Lesson; import org.guzzing.studayserver.domain.academy.repository.academy.AcademyRepository; @@ -40,8 +39,8 @@ public class AcademyService { private final AcademyCategoryRepository academyCategoryRepository; public AcademyService(AcademyRepository academyRepository, LessonRepository lessonRepository, - ReviewCountRepository reviewCountRepository, - AcademyCategoryRepository academyCategoryRepository) { + ReviewCountRepository reviewCountRepository, + AcademyCategoryRepository academyCategoryRepository) { this.academyRepository = academyRepository; this.lessonRepository = lessonRepository; this.reviewCountRepository = reviewCountRepository; @@ -68,7 +67,8 @@ public AcademyGetResult getAcademy(Long academyId) { } @Transactional(readOnly = true) - public AcademiesByLocationWithScrollResults findAcademiesByLocationWithScroll(AcademiesByLocationWithScrollParam param) { + public AcademiesByLocationWithScrollResults findAcademiesByLocationWithScroll( + AcademiesByLocationWithScrollParam param) { String diagonal = GeometryUtil.makeDiagonal(param.baseLatitude(), param.baseLongitude(), DISTANCE); AcademiesByLocationWithScroll academiesByLocation = academyRepository.findAcademiesByLocation( diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByLocationWithScrollResults.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByLocationWithScrollResults.java index 05b9981ac..678a0ad14 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByLocationWithScrollResults.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/dto/result/AcademiesByLocationWithScrollResults.java @@ -1,9 +1,7 @@ package org.guzzing.studayserver.domain.academy.service.dto.result; import java.util.List; -import java.util.Map; import org.guzzing.studayserver.domain.academy.repository.dto.AcademiesByLocationWithScroll; -import org.guzzing.studayserver.domain.academy.repository.dto.AcademyByLocationWithScroll; import org.guzzing.studayserver.domain.academy.util.CategoryInfo; public record AcademiesByLocationWithScrollResults( @@ -17,13 +15,13 @@ public static AcademiesByLocationWithScrollResults to( academiesByLocationWithScroll .academiesByLocation() .keySet() - .stream() - .map(academyByLocation-> - AcademiesByLocationResultWithScroll.from( - academyByLocation, - academiesByLocationWithScroll.academiesByLocation(). - get(academyByLocation))) - .toList(), + .stream() + .map(academyByLocation -> + AcademiesByLocationResultWithScroll.from( + academyByLocation, + academiesByLocationWithScroll.academiesByLocation(). + get(academyByLocation))) + .toList(), academiesByLocationWithScroll.hasNext()); } @@ -39,8 +37,9 @@ public record AcademiesByLocationResultWithScroll( boolean isLiked ) { - public static AcademiesByLocationResultWithScroll from(AcademiesByLocationWithScroll.AcademyByLocation academyByLocationWithScroll, - List categories) { + public static AcademiesByLocationResultWithScroll from( + AcademiesByLocationWithScroll.AcademyByLocation academyByLocationWithScroll, + List categories) { return new AcademiesByLocationResultWithScroll( academyByLocationWithScroll.academyId(), academyByLocationWithScroll.academyName(), diff --git a/src/main/java/org/guzzing/studayserver/domain/like/model/Like.java b/src/main/java/org/guzzing/studayserver/domain/like/model/Like.java index c9423bb6e..4c9f7258e 100644 --- a/src/main/java/org/guzzing/studayserver/domain/like/model/Like.java +++ b/src/main/java/org/guzzing/studayserver/domain/like/model/Like.java @@ -3,9 +3,7 @@ import static jakarta.persistence.FetchType.LAZY; import static lombok.AccessLevel.PROTECTED; -import jakarta.persistence.Column; import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; diff --git a/src/test/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacadeTest.java b/src/test/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacadeTest.java index 2d28724d8..b8e9aedd2 100644 --- a/src/test/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacadeTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/academy/facade/AcademyFacadeTest.java @@ -1,5 +1,9 @@ package org.guzzing.studayserver.domain.academy.facade; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE; + import jakarta.transaction.Transactional; import org.guzzing.studayserver.domain.academy.facade.dto.AcademyDetailFacadeParam; import org.guzzing.studayserver.domain.academy.facade.dto.AcademyDetailFacadeResult; @@ -24,10 +28,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Import; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE; - @Transactional @SpringBootTest(webEnvironment = NONE) @Import(TestDatabaseConfig.class) @@ -103,7 +103,8 @@ void getDetailAcademy() { () -> assertThat(detailAcademy.contact()).isEqualTo(savedAcademyAboutSungnam.getContact()), () -> assertThat(detailAcademy.expectedFee()).isEqualTo(savedAcademyAboutSungnam.getMaxEducationFee()), () -> assertThat(detailAcademy.fullAddress()).isEqualTo(savedAcademyAboutSungnam.getFullAddress()), - () -> assertThat(detailAcademy.shuttleAvailability()).isEqualTo(savedAcademyAboutSungnam.getShuttleAvailability()) + () -> assertThat(detailAcademy.shuttleAvailability()).isEqualTo( + savedAcademyAboutSungnam.getShuttleAvailability()) ); } diff --git a/src/test/java/org/guzzing/studayserver/domain/dashboard/controller/DashboardRestControllerTest.java b/src/test/java/org/guzzing/studayserver/domain/dashboard/controller/DashboardRestControllerTest.java index cf94a7442..895b5852a 100644 --- a/src/test/java/org/guzzing/studayserver/domain/dashboard/controller/DashboardRestControllerTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/dashboard/controller/DashboardRestControllerTest.java @@ -34,11 +34,11 @@ import org.guzzing.studayserver.domain.child.service.ChildAccessService; import org.guzzing.studayserver.domain.dashboard.controller.dto.request.DashboardPostRequest; import org.guzzing.studayserver.domain.dashboard.controller.dto.request.DashboardPutRequest; -import org.guzzing.studayserver.testutil.JwtTestConfig; -import org.guzzing.studayserver.testutil.fixture.dashboard.DashboardFixture; import org.guzzing.studayserver.domain.dashboard.model.Dashboard; import org.guzzing.studayserver.domain.member.service.MemberAccessService; +import org.guzzing.studayserver.testutil.JwtTestConfig; import org.guzzing.studayserver.testutil.WithMockCustomOAuth2LoginUser; +import org.guzzing.studayserver.testutil.fixture.dashboard.DashboardFixture; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/src/test/java/org/guzzing/studayserver/domain/dashboard/facade/DashboardFacadeTest.java b/src/test/java/org/guzzing/studayserver/domain/dashboard/facade/DashboardFacadeTest.java index 3222b40bd..339bf1540 100644 --- a/src/test/java/org/guzzing/studayserver/domain/dashboard/facade/DashboardFacadeTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/dashboard/facade/DashboardFacadeTest.java @@ -13,12 +13,12 @@ import org.guzzing.studayserver.domain.dashboard.facade.dto.DashboardPatchResult; import org.guzzing.studayserver.domain.dashboard.facade.dto.DashboardPostResult; import org.guzzing.studayserver.domain.dashboard.facade.dto.DashboardPutResult; -import org.guzzing.studayserver.testutil.fixture.dashboard.DashboardFixture; import org.guzzing.studayserver.domain.dashboard.model.Dashboard; import org.guzzing.studayserver.domain.dashboard.service.dto.request.DashboardPostParam; import org.guzzing.studayserver.domain.dashboard.service.dto.request.DashboardPutParam; import org.guzzing.studayserver.domain.member.service.MemberAccessService; import org.guzzing.studayserver.global.exception.DashboardException; +import org.guzzing.studayserver.testutil.fixture.dashboard.DashboardFixture; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/src/test/java/org/guzzing/studayserver/domain/dashboard/service/DashboardServiceTest.java b/src/test/java/org/guzzing/studayserver/domain/dashboard/service/DashboardServiceTest.java index 7c77ac827..13d8b6fa9 100644 --- a/src/test/java/org/guzzing/studayserver/domain/dashboard/service/DashboardServiceTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/dashboard/service/DashboardServiceTest.java @@ -6,12 +6,12 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.List; -import org.guzzing.studayserver.testutil.fixture.dashboard.DashboardFixture; import org.guzzing.studayserver.domain.dashboard.model.Dashboard; import org.guzzing.studayserver.domain.dashboard.service.dto.request.DashboardPostParam; import org.guzzing.studayserver.domain.dashboard.service.dto.request.DashboardPutParam; import org.guzzing.studayserver.domain.dashboard.service.dto.response.DashboardResult; import org.guzzing.studayserver.global.exception.DashboardException; +import org.guzzing.studayserver.testutil.fixture.dashboard.DashboardFixture; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/src/test/java/org/guzzing/studayserver/domain/review/controller/ReviewRestControllerTest.java b/src/test/java/org/guzzing/studayserver/domain/review/controller/ReviewRestControllerTest.java index 0f8045a00..06bacb84e 100644 --- a/src/test/java/org/guzzing/studayserver/domain/review/controller/ReviewRestControllerTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/review/controller/ReviewRestControllerTest.java @@ -2,7 +2,6 @@ import static com.epages.restdocs.apispec.MockMvcRestDocumentationWrapper.document; import static com.epages.restdocs.apispec.ResourceDocumentation.resource; -import static com.nimbusds.oauth2.sdk.token.AccessTokenType.BEARER; import static org.guzzing.studayserver.testutil.JwtTestConfig.AUTHORIZATION_HEADER; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; diff --git a/src/test/java/org/guzzing/studayserver/testutil/fixture/academy/AcademyFixture.java b/src/test/java/org/guzzing/studayserver/testutil/fixture/academy/AcademyFixture.java index 7b054bbcc..d51784377 100644 --- a/src/test/java/org/guzzing/studayserver/testutil/fixture/academy/AcademyFixture.java +++ b/src/test/java/org/guzzing/studayserver/testutil/fixture/academy/AcademyFixture.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; - import org.guzzing.studayserver.domain.academy.facade.dto.AcademyDetailFacadeParam; import org.guzzing.studayserver.domain.academy.model.Academy; import org.guzzing.studayserver.domain.academy.model.AcademyCategory; @@ -114,8 +113,9 @@ public static ReviewCount reviewCountDefault(Academy academy) { return ReviewCount.makeDefaultReviewCount(academy); } - public static AcademiesByLocationWithScrollParam academiesByLocationWithScrollParam(double latitude, double longitude) { - return AcademiesByLocationWithScrollParam.of(latitude, longitude, 1L,0 ); + public static AcademiesByLocationWithScrollParam academiesByLocationWithScrollParam(double latitude, + double longitude) { + return AcademiesByLocationWithScrollParam.of(latitude, longitude, 1L, 0); } public static AcademyFilterWithScrollParam academyFilterWithScrollParam( diff --git a/src/test/java/org/guzzing/studayserver/testutil/fixture/member/MemberFixture.java b/src/test/java/org/guzzing/studayserver/testutil/fixture/member/MemberFixture.java index e2803d7dd..6eac25eba 100644 --- a/src/test/java/org/guzzing/studayserver/testutil/fixture/member/MemberFixture.java +++ b/src/test/java/org/guzzing/studayserver/testutil/fixture/member/MemberFixture.java @@ -4,10 +4,6 @@ import org.guzzing.studayserver.domain.member.model.NickName; import org.guzzing.studayserver.domain.member.model.vo.MemberProvider; import org.guzzing.studayserver.domain.member.model.vo.RoleType; -import org.guzzing.studayserver.domain.member.repository.MemberRepository; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; public class MemberFixture { From 92da0b893119ea210e1f790b3af2936d20aaced2 Mon Sep 17 00:00:00 2001 From: SeYoE Date: Tue, 12 Dec 2023 18:15:59 +0900 Subject: [PATCH 14/21] =?UTF-8?q?Refactor:=20Service=20CQRS=20=ED=8C=A8?= =?UTF-8?q?=ED=84=B4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../review/service/ReviewCommandService.java | 37 +++++++++++++++++++ .../review/service/ReviewReadService.java | 21 +++++++++++ 2 files changed, 58 insertions(+) create mode 100644 src/main/java/org/guzzing/studayserver/domain/review/service/ReviewCommandService.java create mode 100644 src/main/java/org/guzzing/studayserver/domain/review/service/ReviewReadService.java diff --git a/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewCommandService.java b/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewCommandService.java new file mode 100644 index 000000000..6c64d92bf --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewCommandService.java @@ -0,0 +1,37 @@ +package org.guzzing.studayserver.domain.review.service; + +import org.guzzing.studayserver.domain.review.event.NewReviewEvent; +import org.guzzing.studayserver.domain.review.model.Review; +import org.guzzing.studayserver.domain.review.repository.ReviewRepository; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +public class ReviewCommandService { + + private final ReviewRepository reviewRepository; + private final ApplicationEventPublisher eventPublisher; + + public ReviewCommandService( + final ReviewRepository reviewRepository, + final ApplicationEventPublisher eventPublisher + ) { + this.reviewRepository = reviewRepository; + this.eventPublisher = eventPublisher; + } + + public Review saveReview(final Review review) { + final Review savedReview = reviewRepository.save(review); + + eventPublisher.publishEvent(NewReviewEvent.of(savedReview)); + + return savedReview; + } + + public void deleteReviewOfMember(final long memberId) { + reviewRepository.deleteByMemberId(memberId); + } + +} diff --git a/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewReadService.java b/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewReadService.java new file mode 100644 index 000000000..0ee640226 --- /dev/null +++ b/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewReadService.java @@ -0,0 +1,21 @@ +package org.guzzing.studayserver.domain.review.service; + +import org.guzzing.studayserver.domain.review.repository.ReviewRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +public class ReviewReadService { + + private final ReviewRepository reviewRepository; + + public ReviewReadService(final ReviewRepository reviewRepository) { + this.reviewRepository = reviewRepository; + } + + public boolean existsReview(final long memberId, final long academyId) { + return reviewRepository.existsByMemberIdAndAcademyId(memberId, academyId); + } + +} From 98b2469b504be81d46641bc677ddf3b934807af9 Mon Sep 17 00:00:00 2001 From: SeYoE Date: Tue, 12 Dec 2023 18:16:11 +0900 Subject: [PATCH 15/21] =?UTF-8?q?Refactor:=20Facade=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/service/MemberFacade.java | 10 +++--- .../controller/ReviewRestController.java | 12 +++---- .../{ReviewService.java => ReviewFacade.java} | 35 +++++++------------ ...ServiceTest.java => ReviewFacadeTest.java} | 18 +++++----- 4 files changed, 32 insertions(+), 43 deletions(-) rename src/main/java/org/guzzing/studayserver/domain/review/service/{ReviewService.java => ReviewFacade.java} (65%) rename src/test/java/org/guzzing/studayserver/domain/review/service/{ReviewServiceTest.java => ReviewFacadeTest.java} (89%) diff --git a/src/main/java/org/guzzing/studayserver/domain/member/service/MemberFacade.java b/src/main/java/org/guzzing/studayserver/domain/member/service/MemberFacade.java index 5e3625fb6..b9f9ae888 100644 --- a/src/main/java/org/guzzing/studayserver/domain/member/service/MemberFacade.java +++ b/src/main/java/org/guzzing/studayserver/domain/member/service/MemberFacade.java @@ -8,7 +8,7 @@ import org.guzzing.studayserver.domain.dashboard.service.DashboardService; import org.guzzing.studayserver.domain.like.service.LikeCommandService; import org.guzzing.studayserver.domain.member.model.Member; -import org.guzzing.studayserver.domain.review.service.ReviewService; +import org.guzzing.studayserver.domain.review.service.ReviewFacade; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -21,7 +21,7 @@ public class MemberFacade { private final AcademyCalendarService calendarService; private final DashboardService dashboardService; private final LikeCommandService likeCommandService; - private final ReviewService reviewService; + private final ReviewFacade reviewFacade; public MemberFacade( final MemberService memberService, @@ -29,14 +29,14 @@ public MemberFacade( final AcademyCalendarService calendarService, final DashboardService dashboardService, final LikeCommandService likeCommandService, - final ReviewService reviewService + final ReviewFacade reviewFacade ) { this.memberService = memberService; this.childService = childService; this.calendarService = calendarService; this.dashboardService = dashboardService; this.likeCommandService = likeCommandService; - this.reviewService = reviewService; + this.reviewFacade = reviewFacade; } @Transactional @@ -48,7 +48,7 @@ public void removeMember(final long memberId) { .map(ChildFindResult::childId) .toList(); - reviewService.removeReview(memberId); + reviewFacade.removeReview(memberId); likeCommandService.deleteLikesOfMember(member); calendarService.removeCalendar(childIds); dashboardService.removeDashboard(childIds); diff --git a/src/main/java/org/guzzing/studayserver/domain/review/controller/ReviewRestController.java b/src/main/java/org/guzzing/studayserver/domain/review/controller/ReviewRestController.java index 4a2715391..4952a849b 100644 --- a/src/main/java/org/guzzing/studayserver/domain/review/controller/ReviewRestController.java +++ b/src/main/java/org/guzzing/studayserver/domain/review/controller/ReviewRestController.java @@ -8,7 +8,7 @@ import org.guzzing.studayserver.domain.review.controller.dto.request.ReviewPostRequest; import org.guzzing.studayserver.domain.review.controller.dto.response.ReviewPostResponse; import org.guzzing.studayserver.domain.review.controller.dto.response.ReviewableResponse; -import org.guzzing.studayserver.domain.review.service.ReviewService; +import org.guzzing.studayserver.domain.review.service.ReviewFacade; import org.guzzing.studayserver.domain.review.service.dto.request.ReviewPostParam; import org.guzzing.studayserver.domain.review.service.dto.response.ReviewPostResult; import org.guzzing.studayserver.domain.review.service.dto.response.ReviewableResult; @@ -25,10 +25,10 @@ @RequestMapping(path = "/reviews") public class ReviewRestController { - private final ReviewService reviewService; + private final ReviewFacade reviewFacade; - public ReviewRestController(ReviewService reviewService) { - this.reviewService = reviewService; + public ReviewRestController(ReviewFacade reviewFacade) { + this.reviewFacade = reviewFacade; } @PostMapping(consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) @@ -37,7 +37,7 @@ public ResponseEntity registerReview( @Validated @RequestBody ReviewPostRequest request ) { ReviewPostParam param = ReviewPostRequest.to(memberId, request); - ReviewPostResult result = reviewService.createReviewOfAcademy(param); + ReviewPostResult result = reviewFacade.createReviewOfAcademy(param); ReviewPostResponse response = ReviewPostResponse.from(result); return ResponseEntity @@ -50,7 +50,7 @@ public ResponseEntity getReviewable( @MemberId Long memberId, @RequestParam Long academyId ) { - ReviewableResult result = reviewService.getReviewableToAcademy(memberId, academyId); + ReviewableResult result = reviewFacade.getReviewableToAcademy(memberId, academyId); ReviewableResponse response = ReviewableResponse.from(result); return ResponseEntity diff --git a/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewService.java b/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewFacade.java similarity index 65% rename from src/main/java/org/guzzing/studayserver/domain/review/service/ReviewService.java rename to src/main/java/org/guzzing/studayserver/domain/review/service/ReviewFacade.java index 391bdcbf9..4fba3f931 100644 --- a/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewService.java +++ b/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewFacade.java @@ -2,47 +2,39 @@ import org.guzzing.studayserver.domain.academy.service.AcademyAccessService; import org.guzzing.studayserver.domain.member.service.MemberAccessService; -import org.guzzing.studayserver.domain.review.event.NewReviewEvent; import org.guzzing.studayserver.domain.review.model.Review; import org.guzzing.studayserver.domain.review.model.ReviewType; -import org.guzzing.studayserver.domain.review.repository.ReviewRepository; import org.guzzing.studayserver.domain.review.service.dto.request.ReviewPostParam; import org.guzzing.studayserver.domain.review.service.dto.response.ReviewPostResult; import org.guzzing.studayserver.domain.review.service.dto.response.ReviewableResult; import org.guzzing.studayserver.global.exception.ReviewException; -import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; @Service -@Transactional(readOnly = true) -public class ReviewService { +public class ReviewFacade { - private final ApplicationEventPublisher eventPublisher; - private final ReviewRepository reviewRepository; + private final ReviewCommandService reviewCommandService; + private final ReviewReadService reviewReadService; private final AcademyAccessService academyAccessService; private final MemberAccessService memberAccessService; - public ReviewService( - final ApplicationEventPublisher eventPublisher, - final ReviewRepository reviewRepository, + public ReviewFacade( + final ReviewCommandService reviewCommandService, + final ReviewReadService reviewReadService, final AcademyAccessService academyAccessService, final MemberAccessService memberAccessService ) { - this.eventPublisher = eventPublisher; - this.reviewRepository = reviewRepository; + this.reviewCommandService = reviewCommandService; + this.reviewReadService = reviewReadService; this.academyAccessService = academyAccessService; this.memberAccessService = memberAccessService; } - @Transactional public ReviewPostResult createReviewOfAcademy(final ReviewPostParam param) { memberAccessService.validateMember(param.memberId()); academyAccessService.validateAcademy(param.academyId()); - final ReviewableResult reviewableResult = getReviewableToAcademy( - param.memberId(), - param.academyId()); + final ReviewableResult reviewableResult = getReviewableToAcademy(param.memberId(), param.academyId()); if (!reviewableResult.reviewable()) { throw new ReviewException("이미 리뷰를 남겼습니다."); @@ -53,23 +45,20 @@ public ReviewPostResult createReviewOfAcademy(final ReviewPostParam param) { param.academyId(), ReviewType.getSelectedReviewMap(param)); - final Review savedReview = reviewRepository.save(review); - - eventPublisher.publishEvent(NewReviewEvent.of(savedReview)); + final Review savedReview = reviewCommandService.saveReview(review); return ReviewPostResult.from(savedReview); } - @Transactional public void removeReview(final long memberId) { - reviewRepository.deleteByMemberId(memberId); + reviewCommandService.deleteReviewOfMember(memberId); } public ReviewableResult getReviewableToAcademy(final Long memberId, final Long academyId) { memberAccessService.validateMember(memberId); academyAccessService.validateAcademy(academyId); - final boolean existsReview = reviewRepository.existsByMemberIdAndAcademyId(memberId, academyId); + boolean existsReview = reviewReadService.existsReview(memberId, academyId); return ReviewableResult.of(memberId, academyId, !existsReview); } diff --git a/src/test/java/org/guzzing/studayserver/domain/review/service/ReviewServiceTest.java b/src/test/java/org/guzzing/studayserver/domain/review/service/ReviewFacadeTest.java similarity index 89% rename from src/test/java/org/guzzing/studayserver/domain/review/service/ReviewServiceTest.java rename to src/test/java/org/guzzing/studayserver/domain/review/service/ReviewFacadeTest.java index 3f2e5b5c3..f63d274ce 100644 --- a/src/test/java/org/guzzing/studayserver/domain/review/service/ReviewServiceTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/review/service/ReviewFacadeTest.java @@ -30,10 +30,10 @@ import org.springframework.transaction.annotation.Transactional; @SpringBootTest -class ReviewServiceTest { +class ReviewFacadeTest { @Autowired - private ReviewService reviewService; + private ReviewFacade reviewFacade; @MockBean private AcademyAccessService academyAccessService; @@ -70,7 +70,7 @@ void createReviewOfAcademy_NotReviewYet_RegisterReview() { // When int beforeKindnessCount = reviewCountRepository.getByAcademyId(param.academyId()).getKindnessCount(); - ReviewPostResult result = reviewService.createReviewOfAcademy(param); + ReviewPostResult result = reviewFacade.createReviewOfAcademy(param); int afterKindnessCount = reviewCountRepository.getByAcademyId(param.academyId()).getKindnessCount(); // Then @@ -92,10 +92,10 @@ void createReviewOfAcademy_Reviewed_Fail() { boolean isValid = true; ReviewPostParam param = ReviewFixture.makeReviewPostParam(isValid); - reviewService.createReviewOfAcademy(param); + reviewFacade.createReviewOfAcademy(param); // When & Then - assertThatThrownBy(() -> reviewService.createReviewOfAcademy(param)) + assertThatThrownBy(() -> reviewFacade.createReviewOfAcademy(param)) .isInstanceOf(ReviewException.class) .hasMessage("이미 리뷰를 남겼습니다."); } @@ -109,7 +109,7 @@ void createReviewOfAcademy_GreaterThanThreeReivewTypes_Fail() { ReviewPostParam param = ReviewFixture.makeReviewPostParam(isValid); // When & Then - assertThatThrownBy(() -> reviewService.createReviewOfAcademy(param)) + assertThatThrownBy(() -> reviewFacade.createReviewOfAcademy(param)) .isInstanceOf(ReviewException.class) .hasMessage("리뷰는 3개 까지 가능합니다."); } @@ -123,7 +123,7 @@ void isReviewableToAcademy_NotExistsReview_Reviewable() { final Long academyId = 100L; // When - ReviewableResult result = reviewService.getReviewableToAcademy(memberId, academyId); + ReviewableResult result = reviewFacade.getReviewableToAcademy(memberId, academyId); // Then assertThat(result.reviewable()).isTrue(); @@ -137,10 +137,10 @@ void isReviewableToAcademy_ExistsReview_NotReviewable() { boolean isValid = true; ReviewPostParam param = ReviewFixture.makeReviewPostParam(isValid); - reviewService.createReviewOfAcademy(param); + reviewFacade.createReviewOfAcademy(param); // When & Then - ReviewableResult result = reviewService.getReviewableToAcademy(param.memberId(), param.academyId()); + ReviewableResult result = reviewFacade.getReviewableToAcademy(param.memberId(), param.academyId()); assertThat(result.reviewable()).isFalse(); } From b604454ec54b6e36a2cb090b3ac2c1026323c5a8 Mon Sep 17 00:00:00 2001 From: SeYoE Date: Wed, 13 Dec 2023 16:35:25 +0900 Subject: [PATCH 16/21] =?UTF-8?q?Remove:=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=EB=84=88=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../academy/listener/NewReviewListener.java | 30 ------------------ .../domain/academy/model/ReviewCount.java | 31 ++++++++++--------- .../domain/review/event/NewReviewEvent.java | 26 ---------------- .../review/service/ReviewCommandService.java | 12 ++----- 4 files changed, 19 insertions(+), 80 deletions(-) delete mode 100644 src/main/java/org/guzzing/studayserver/domain/academy/listener/NewReviewListener.java delete mode 100644 src/main/java/org/guzzing/studayserver/domain/review/event/NewReviewEvent.java diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/listener/NewReviewListener.java b/src/main/java/org/guzzing/studayserver/domain/academy/listener/NewReviewListener.java deleted file mode 100644 index 7c57a7d2e..000000000 --- a/src/main/java/org/guzzing/studayserver/domain/academy/listener/NewReviewListener.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.guzzing.studayserver.domain.academy.listener; - -import static org.springframework.transaction.event.TransactionPhase.BEFORE_COMMIT; - -import java.util.Map; -import org.guzzing.studayserver.domain.academy.repository.review.ReviewCountRepository; -import org.guzzing.studayserver.domain.review.event.NewReviewEvent; -import org.springframework.stereotype.Component; -import org.springframework.transaction.event.TransactionalEventListener; - -@Component -public class NewReviewListener { - - private final ReviewCountRepository reviewCountRepository; - - public NewReviewListener(final ReviewCountRepository reviewCountRepository) { - this.reviewCountRepository = reviewCountRepository; - } - - @TransactionalEventListener(phase = BEFORE_COMMIT) - public void updateReviewCount(final NewReviewEvent event) { - final long academyId = event.getAcademyId(); - final Map reviews = event.getReviewType(); - final Map newReview = NewReviewType.newReviewCountOf(reviews); - - reviewCountRepository.getByAcademyId(academyId) - .updateSelectedReviewCount(newReview); - } - -} diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/model/ReviewCount.java b/src/main/java/org/guzzing/studayserver/domain/academy/model/ReviewCount.java index fc209457e..820c3b2bb 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/model/ReviewCount.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/model/ReviewCount.java @@ -1,11 +1,11 @@ package org.guzzing.studayserver.domain.academy.model; -import static org.guzzing.studayserver.domain.academy.listener.NewReviewType.CHEAP_FEE; -import static org.guzzing.studayserver.domain.academy.listener.NewReviewType.GOOD_FACILITY; -import static org.guzzing.studayserver.domain.academy.listener.NewReviewType.GOOD_MANAGEMENT; -import static org.guzzing.studayserver.domain.academy.listener.NewReviewType.KINDNESS; -import static org.guzzing.studayserver.domain.academy.listener.NewReviewType.LOVELY_TEACHING; -import static org.guzzing.studayserver.domain.academy.listener.NewReviewType.SHUTTLE_AVAILABILITY; +import static org.guzzing.studayserver.domain.review.model.ReviewType.CHEAP_FEE; +import static org.guzzing.studayserver.domain.review.model.ReviewType.GOOD_FACILITY; +import static org.guzzing.studayserver.domain.review.model.ReviewType.GOOD_MANAGEMENT; +import static org.guzzing.studayserver.domain.review.model.ReviewType.KINDNESS; +import static org.guzzing.studayserver.domain.review.model.ReviewType.LOVELY_TEACHING; +import static org.guzzing.studayserver.domain.review.model.ReviewType.SHUTTLE_AVAILABILITY; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -17,7 +17,8 @@ import jakarta.persistence.Table; import java.util.Map; import lombok.Getter; -import org.guzzing.studayserver.domain.academy.listener.NewReviewType; +import org.guzzing.studayserver.domain.review.model.Review; +import org.guzzing.studayserver.domain.review.model.ReviewType; @Getter @Entity @@ -84,12 +85,14 @@ public static ReviewCount makeDefaultReviewCount(Academy academy) { academy); } - public void updateSelectedReviewCount(final Map newReview) { - this.kindnessCount += newReview.get(KINDNESS); - this.goodFacilityCount += newReview.get(GOOD_FACILITY); - this.cheapFeeCount += newReview.get(CHEAP_FEE); - this.goodManagementCount += newReview.get(GOOD_MANAGEMENT); - this.lovelyTeachingCount += newReview.get(LOVELY_TEACHING); - this.shuttleAvailabilityCount += newReview.get(SHUTTLE_AVAILABILITY); + public void updateSelectedReviewCount(final Map newReview) { + final Map reviewCountMap = ReviewType.convertToReviewTypeCountMap(newReview); + + this.kindnessCount += reviewCountMap.get(KINDNESS); + this.goodFacilityCount += reviewCountMap.get(GOOD_FACILITY); + this.cheapFeeCount += reviewCountMap.get(CHEAP_FEE); + this.goodManagementCount += reviewCountMap.get(GOOD_MANAGEMENT); + this.lovelyTeachingCount += reviewCountMap.get(LOVELY_TEACHING); + this.shuttleAvailabilityCount += reviewCountMap.get(SHUTTLE_AVAILABILITY); } } diff --git a/src/main/java/org/guzzing/studayserver/domain/review/event/NewReviewEvent.java b/src/main/java/org/guzzing/studayserver/domain/review/event/NewReviewEvent.java deleted file mode 100644 index 763ec6148..000000000 --- a/src/main/java/org/guzzing/studayserver/domain/review/event/NewReviewEvent.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.guzzing.studayserver.domain.review.event; - -import java.util.Map; -import org.guzzing.studayserver.domain.review.model.Review; - -public class NewReviewEvent { - - private final Review review; - - private NewReviewEvent(final Review review) { - this.review = review; - } - - public static NewReviewEvent of(final Review review) { - return new NewReviewEvent(review); - } - - public long getAcademyId() { - return this.review.getAcademyId(); - } - - public Map getReviewType() { - return this.review.getReviewType(); - } - -} diff --git a/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewCommandService.java b/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewCommandService.java index 6c64d92bf..125178a79 100644 --- a/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewCommandService.java +++ b/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewCommandService.java @@ -3,7 +3,6 @@ import org.guzzing.studayserver.domain.review.event.NewReviewEvent; import org.guzzing.studayserver.domain.review.model.Review; import org.guzzing.studayserver.domain.review.repository.ReviewRepository; -import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -12,22 +11,15 @@ public class ReviewCommandService { private final ReviewRepository reviewRepository; - private final ApplicationEventPublisher eventPublisher; public ReviewCommandService( - final ReviewRepository reviewRepository, - final ApplicationEventPublisher eventPublisher + final ReviewRepository reviewRepository ) { this.reviewRepository = reviewRepository; - this.eventPublisher = eventPublisher; } public Review saveReview(final Review review) { - final Review savedReview = reviewRepository.save(review); - - eventPublisher.publishEvent(NewReviewEvent.of(savedReview)); - - return savedReview; + return reviewRepository.save(review); } public void deleteReviewOfMember(final long memberId) { From ef2ea9fa37a2de6a6788ffc419a902ed87b4424d Mon Sep 17 00:00:00 2001 From: SeYoE Date: Wed, 13 Dec 2023 16:35:49 +0900 Subject: [PATCH 17/21] =?UTF-8?q?Refactor:=20=EC=A4=91=EB=B3=B5=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=ED=83=80=EC=9E=85=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../academy/listener/NewReviewType.java | 22 ------------------- .../domain/review/model/ReviewType.java | 15 ++++++++++--- 2 files changed, 12 insertions(+), 25 deletions(-) delete mode 100644 src/main/java/org/guzzing/studayserver/domain/academy/listener/NewReviewType.java diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/listener/NewReviewType.java b/src/main/java/org/guzzing/studayserver/domain/academy/listener/NewReviewType.java deleted file mode 100644 index d3726c44f..000000000 --- a/src/main/java/org/guzzing/studayserver/domain/academy/listener/NewReviewType.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.guzzing.studayserver.domain.academy.listener; - -import java.util.Arrays; -import java.util.Map; -import java.util.stream.Collectors; - -public enum NewReviewType { - KINDNESS, - GOOD_FACILITY, - CHEAP_FEE, - GOOD_MANAGEMENT, - LOVELY_TEACHING, - SHUTTLE_AVAILABILITY; - - public static Map newReviewCountOf(final Map map) { - return Arrays.stream(NewReviewType.values()) - .collect(Collectors.toMap( - reviewType -> reviewType, - reviewType -> map.get(reviewType.name()) ? 1 : 0 - )); - } -} diff --git a/src/main/java/org/guzzing/studayserver/domain/review/model/ReviewType.java b/src/main/java/org/guzzing/studayserver/domain/review/model/ReviewType.java index cf3058231..c9da4a3e4 100644 --- a/src/main/java/org/guzzing/studayserver/domain/review/model/ReviewType.java +++ b/src/main/java/org/guzzing/studayserver/domain/review/model/ReviewType.java @@ -4,8 +4,9 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; +import javax.lang.model.type.IntersectionType; +import javax.swing.text.StyledEditorKit.BoldAction; import org.guzzing.studayserver.domain.review.service.dto.request.ReviewPostParam; -import org.guzzing.studayserver.global.exception.ReviewException; public enum ReviewType { KINDNESS, @@ -32,7 +33,7 @@ public static Map getSelectedReviewMap(final ReviewPostPara return selectedReviewMap; } - public static Map convertReviewListToReviewMap(final Map map) { + public static Map convertToReviewTypeMap(final Map map) { return Arrays.stream(ReviewType.values()) .collect(Collectors.toMap( reviewType -> reviewType, @@ -40,13 +41,21 @@ public static Map convertReviewListToReviewMap(final Map convertToReviewTypeCountMap(final Map map) { + return Arrays.stream(ReviewType.values()) + .collect(Collectors.toMap( + reviewType -> reviewType, + reviewType -> Boolean.TRUE.equals(map.get(reviewType)) ? 1 : 0 + )); + } + private static void validateThreeReviewLimit(final Map map) { long count = map.values().stream() .filter(value -> value) .count(); if (count > MAX_REVIEW_COUNT) { - throw new ReviewException("리뷰는 3개 까지 가능합니다."); + throw new IllegalArgumentException("리뷰는 3개 까지 가능합니다."); } } From 82a605d078f09c474dd6d2d1247be053bd6d4402 Mon Sep 17 00:00:00 2001 From: SeYoE Date: Wed, 13 Dec 2023 16:36:51 +0900 Subject: [PATCH 18/21] =?UTF-8?q?Refactor:=20=EA=B0=84=EC=A0=91=EC=B0=B8?= =?UTF-8?q?=EC=A1=B0=EB=A5=BC=20=EC=A7=81=EC=A0=91=EC=B0=B8=EC=A1=B0?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../review/ReviewCountJpaRepository.java | 1 + .../academy/service/AcademyService.java | 6 ++ .../domain/member/service/MemberFacade.java | 5 +- .../domain/review/model/Review.java | 39 ++++++--- .../repository/ReviewJpaRepository.java | 6 +- .../review/repository/ReviewRepository.java | 8 +- .../review/service/ReviewCommandService.java | 6 +- .../domain/review/service/ReviewFacade.java | 63 ++++++++------- .../review/service/ReviewReadService.java | 6 +- .../service/dto/request/ReviewPostParam.java | 4 +- .../dto/response/ReviewPostResult.java | 8 +- .../dto/response/ReviewableResult.java | 6 +- .../controller/ReviewRestControllerTest.java | 55 +++++++------ .../domain/review/fixture/ReviewFixture.java | 53 +++++------- .../review/service/ReviewFacadeTest.java | 80 +++++++------------ 15 files changed, 178 insertions(+), 168 deletions(-) diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/repository/review/ReviewCountJpaRepository.java b/src/main/java/org/guzzing/studayserver/domain/academy/repository/review/ReviewCountJpaRepository.java index 883c29402..f3cc27029 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/repository/review/ReviewCountJpaRepository.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/repository/review/ReviewCountJpaRepository.java @@ -4,6 +4,7 @@ import org.guzzing.studayserver.domain.academy.model.ReviewCount; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; public interface ReviewCountJpaRepository extends JpaRepository, ReviewCountRepository { diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java b/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java index 8480fcae4..1c0881069 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/service/AcademyService.java @@ -5,6 +5,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.guzzing.studayserver.domain.academy.model.Academy; import org.guzzing.studayserver.domain.academy.model.Lesson; +import org.guzzing.studayserver.domain.academy.model.ReviewCount; import org.guzzing.studayserver.domain.academy.repository.academy.AcademyRepository; import org.guzzing.studayserver.domain.academy.repository.academycategory.AcademyCategoryRepository; import org.guzzing.studayserver.domain.academy.repository.dto.AcademiesByFilterWithScroll; @@ -52,6 +53,11 @@ public Academy getAcademy(final long academyId) { return academyRepository.getById(academyId); } + @Transactional(readOnly = true) + public ReviewCount getReviewCountOfAcademy(final long academyId) { + return reviewCountRepository.getByAcademyId(academyId); + } + @Transactional(readOnly = true) public AcademyFeeInfo findAcademyFeeInfo(final long academyId) { return AcademyFeeInfo.from(academyRepository.findAcademyFeeInfo(academyId)); diff --git a/src/main/java/org/guzzing/studayserver/domain/member/service/MemberFacade.java b/src/main/java/org/guzzing/studayserver/domain/member/service/MemberFacade.java index b9f9ae888..c6d86f2cc 100644 --- a/src/main/java/org/guzzing/studayserver/domain/member/service/MemberFacade.java +++ b/src/main/java/org/guzzing/studayserver/domain/member/service/MemberFacade.java @@ -43,12 +43,13 @@ public MemberFacade( public void removeMember(final long memberId) { final Member member = memberService.getMember(memberId); - final List childIds = childService.findByMemberId(memberId).children() + final List childIds = childService.findByMemberId(member.getId()) + .children() .stream() .map(ChildFindResult::childId) .toList(); - reviewFacade.removeReview(memberId); + reviewFacade.removeReview(member); likeCommandService.deleteLikesOfMember(member); calendarService.removeCalendar(childIds); dashboardService.removeDashboard(childIds); diff --git a/src/main/java/org/guzzing/studayserver/domain/review/model/Review.java b/src/main/java/org/guzzing/studayserver/domain/review/model/Review.java index e55324677..5c6ada8a8 100644 --- a/src/main/java/org/guzzing/studayserver/domain/review/model/Review.java +++ b/src/main/java/org/guzzing/studayserver/domain/review/model/Review.java @@ -1,11 +1,16 @@ package org.guzzing.studayserver.domain.review.model; +import static jakarta.persistence.FetchType.LAZY; + import io.hypersistence.utils.hibernate.type.json.JsonType; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import java.util.Map; import java.util.Map.Entry; @@ -13,6 +18,8 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; +import org.guzzing.studayserver.domain.academy.model.Academy; +import org.guzzing.studayserver.domain.member.model.Member; import org.hibernate.annotations.Type; @Getter @@ -25,29 +32,31 @@ public class Review { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(name = "member_id", nullable = false) - private Long memberId; + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "member_id") + private Member member; - @Column(name = "academy_id", nullable = false) - private Long academyId; + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "academy_id") + private Academy academy; @Type(JsonType.class) @Column(name = "reviewed_type", nullable = false, columnDefinition = "LONGTEXT") private Map reviewType; public Review( - final Long memberId, - final Long academyId, + final Member member, + final Academy academy, final Map reviewType ) { - this.memberId = memberId; - this.academyId = academyId; + this.member = member; + this.academy = academy; this.reviewType = reviewType; } public static Review of( - final Long memberId, - final Long academyId, + final Member member, + final Academy academy, final Map reviewType ) { final Map selectedRevieType = reviewType.entrySet() @@ -57,7 +66,15 @@ public static Review of( Entry::getValue )); - return new Review(memberId, academyId, selectedRevieType); + return new Review(member, academy, selectedRevieType); + } + + public long getMemberId() { + return this.member.getId(); + } + + public long getAcademyId() { + return this.academy.getId(); } } diff --git a/src/main/java/org/guzzing/studayserver/domain/review/repository/ReviewJpaRepository.java b/src/main/java/org/guzzing/studayserver/domain/review/repository/ReviewJpaRepository.java index 5ec4398d9..597c44711 100644 --- a/src/main/java/org/guzzing/studayserver/domain/review/repository/ReviewJpaRepository.java +++ b/src/main/java/org/guzzing/studayserver/domain/review/repository/ReviewJpaRepository.java @@ -1,12 +1,14 @@ package org.guzzing.studayserver.domain.review.repository; +import org.guzzing.studayserver.domain.academy.model.Academy; +import org.guzzing.studayserver.domain.member.model.Member; import org.guzzing.studayserver.domain.review.model.Review; import org.springframework.data.jpa.repository.JpaRepository; public interface ReviewJpaRepository extends JpaRepository, ReviewRepository { - boolean existsByMemberIdAndAcademyId(final Long memberId, final Long academyId); + boolean existsByMemberAndAcademy(final Member member, final Academy academy); - void deleteByMemberId(final long memberId); + void deleteByMember(final Member member); } diff --git a/src/main/java/org/guzzing/studayserver/domain/review/repository/ReviewRepository.java b/src/main/java/org/guzzing/studayserver/domain/review/repository/ReviewRepository.java index 5c8aa9447..0e5678fdf 100644 --- a/src/main/java/org/guzzing/studayserver/domain/review/repository/ReviewRepository.java +++ b/src/main/java/org/guzzing/studayserver/domain/review/repository/ReviewRepository.java @@ -1,15 +1,15 @@ package org.guzzing.studayserver.domain.review.repository; +import org.guzzing.studayserver.domain.academy.model.Academy; +import org.guzzing.studayserver.domain.member.model.Member; import org.guzzing.studayserver.domain.review.model.Review; public interface ReviewRepository { Review save(final Review review); - boolean existsByMemberIdAndAcademyId(final Long memberId, final Long academyId); + boolean existsByMemberAndAcademy(final Member member, final Academy academy); - void deleteByMemberId(final long memberId); - - void deleteAll(); + void deleteByMember(final Member member); } diff --git a/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewCommandService.java b/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewCommandService.java index 125178a79..9147b659a 100644 --- a/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewCommandService.java +++ b/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewCommandService.java @@ -1,6 +1,6 @@ package org.guzzing.studayserver.domain.review.service; -import org.guzzing.studayserver.domain.review.event.NewReviewEvent; +import org.guzzing.studayserver.domain.member.model.Member; import org.guzzing.studayserver.domain.review.model.Review; import org.guzzing.studayserver.domain.review.repository.ReviewRepository; import org.springframework.stereotype.Service; @@ -22,8 +22,8 @@ public Review saveReview(final Review review) { return reviewRepository.save(review); } - public void deleteReviewOfMember(final long memberId) { - reviewRepository.deleteByMemberId(memberId); + public void deleteReviewOfMember(final Member member) { + reviewRepository.deleteByMember(member); } } diff --git a/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewFacade.java b/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewFacade.java index 4fba3f931..6f1ed3348 100644 --- a/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewFacade.java +++ b/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewFacade.java @@ -1,13 +1,16 @@ package org.guzzing.studayserver.domain.review.service; -import org.guzzing.studayserver.domain.academy.service.AcademyAccessService; -import org.guzzing.studayserver.domain.member.service.MemberAccessService; +import jakarta.persistence.EntityExistsException; +import java.util.Map; +import org.guzzing.studayserver.domain.academy.model.Academy; +import org.guzzing.studayserver.domain.academy.service.AcademyService; +import org.guzzing.studayserver.domain.member.model.Member; +import org.guzzing.studayserver.domain.member.service.MemberService; import org.guzzing.studayserver.domain.review.model.Review; import org.guzzing.studayserver.domain.review.model.ReviewType; import org.guzzing.studayserver.domain.review.service.dto.request.ReviewPostParam; import org.guzzing.studayserver.domain.review.service.dto.response.ReviewPostResult; import org.guzzing.studayserver.domain.review.service.dto.response.ReviewableResult; -import org.guzzing.studayserver.global.exception.ReviewException; import org.springframework.stereotype.Service; @Service @@ -15,52 +18,56 @@ public class ReviewFacade { private final ReviewCommandService reviewCommandService; private final ReviewReadService reviewReadService; - private final AcademyAccessService academyAccessService; - private final MemberAccessService memberAccessService; + private final MemberService memberService; + private final AcademyService academyService; public ReviewFacade( final ReviewCommandService reviewCommandService, final ReviewReadService reviewReadService, - final AcademyAccessService academyAccessService, - final MemberAccessService memberAccessService + final MemberService memberService, + final AcademyService academyService ) { this.reviewCommandService = reviewCommandService; this.reviewReadService = reviewReadService; - this.academyAccessService = academyAccessService; - this.memberAccessService = memberAccessService; + this.memberService = memberService; + this.academyService = academyService; } public ReviewPostResult createReviewOfAcademy(final ReviewPostParam param) { - memberAccessService.validateMember(param.memberId()); - academyAccessService.validateAcademy(param.academyId()); + final Member member = memberService.getMember(param.memberId()); + final Academy academy = academyService.getAcademy(param.academyId()); - final ReviewableResult reviewableResult = getReviewableToAcademy(param.memberId(), param.academyId()); + checkReviewExists(member, academy); - if (!reviewableResult.reviewable()) { - throw new ReviewException("이미 리뷰를 남겼습니다."); - } - - final Review review = Review.of( - param.memberId(), - param.academyId(), - ReviewType.getSelectedReviewMap(param)); + final Map selectedReviewMap = ReviewType.getSelectedReviewMap(param); - final Review savedReview = reviewCommandService.saveReview(review); + final Review savedReview = reviewCommandService.saveReview( + Review.of(member, academy, selectedReviewMap)); + academyService.getReviewCountOfAcademy(academy.getId()) + .updateSelectedReviewCount(selectedReviewMap); return ReviewPostResult.from(savedReview); } - public void removeReview(final long memberId) { - reviewCommandService.deleteReviewOfMember(memberId); + public void removeReview(final Member member) { + reviewCommandService.deleteReviewOfMember(member); } - public ReviewableResult getReviewableToAcademy(final Long memberId, final Long academyId) { - memberAccessService.validateMember(memberId); - academyAccessService.validateAcademy(academyId); + public ReviewableResult getReviewableToAcademy(final long memberId, final long academyId) { + final Member member = memberService.getMember(memberId); + final Academy academy = academyService.getAcademy(academyId); + + final boolean existsReview = reviewReadService.existsReview(member, academy); - boolean existsReview = reviewReadService.existsReview(memberId, academyId); + return ReviewableResult.of(member.getId(), academy.getId(), !existsReview); + } + + private void checkReviewExists(Member member, Academy academy) { + final boolean existsReview = reviewReadService.existsReview(member, academy); - return ReviewableResult.of(memberId, academyId, !existsReview); + if (existsReview) { + throw new EntityExistsException("이미 리뷰를 남겼습니다."); + } } } diff --git a/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewReadService.java b/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewReadService.java index 0ee640226..0865a6937 100644 --- a/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewReadService.java +++ b/src/main/java/org/guzzing/studayserver/domain/review/service/ReviewReadService.java @@ -1,5 +1,7 @@ package org.guzzing.studayserver.domain.review.service; +import org.guzzing.studayserver.domain.academy.model.Academy; +import org.guzzing.studayserver.domain.member.model.Member; import org.guzzing.studayserver.domain.review.repository.ReviewRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -14,8 +16,8 @@ public ReviewReadService(final ReviewRepository reviewRepository) { this.reviewRepository = reviewRepository; } - public boolean existsReview(final long memberId, final long academyId) { - return reviewRepository.existsByMemberIdAndAcademyId(memberId, academyId); + public boolean existsReview(final Member member, final Academy academy) { + return reviewRepository.existsByMemberAndAcademy(member, academy); } } diff --git a/src/main/java/org/guzzing/studayserver/domain/review/service/dto/request/ReviewPostParam.java b/src/main/java/org/guzzing/studayserver/domain/review/service/dto/request/ReviewPostParam.java index 404ddbdbc..87a1836be 100644 --- a/src/main/java/org/guzzing/studayserver/domain/review/service/dto/request/ReviewPostParam.java +++ b/src/main/java/org/guzzing/studayserver/domain/review/service/dto/request/ReviewPostParam.java @@ -1,8 +1,8 @@ package org.guzzing.studayserver.domain.review.service.dto.request; public record ReviewPostParam( - Long memberId, - Long academyId, + long memberId, + long academyId, boolean kindness, boolean cheapFee, boolean goodFacility, diff --git a/src/main/java/org/guzzing/studayserver/domain/review/service/dto/response/ReviewPostResult.java b/src/main/java/org/guzzing/studayserver/domain/review/service/dto/response/ReviewPostResult.java index dee48ad16..37ad3a88d 100644 --- a/src/main/java/org/guzzing/studayserver/domain/review/service/dto/response/ReviewPostResult.java +++ b/src/main/java/org/guzzing/studayserver/domain/review/service/dto/response/ReviewPostResult.java @@ -11,9 +11,9 @@ import org.guzzing.studayserver.domain.review.model.ReviewType; public record ReviewPostResult( - Long reviewId, - Long memberId, - Long academyId, + long reviewId, + long memberId, + long academyId, boolean kindness, boolean cheapFee, boolean goodFacility, @@ -22,7 +22,7 @@ public record ReviewPostResult( ) { public static ReviewPostResult from(final Review entity) { - final Map reviewType = ReviewType.convertReviewListToReviewMap(entity.getReviewType()); + final Map reviewType = ReviewType.convertToReviewTypeMap(entity.getReviewType()); return new ReviewPostResult( entity.getId(), diff --git a/src/main/java/org/guzzing/studayserver/domain/review/service/dto/response/ReviewableResult.java b/src/main/java/org/guzzing/studayserver/domain/review/service/dto/response/ReviewableResult.java index 134088a2b..409b82f85 100644 --- a/src/main/java/org/guzzing/studayserver/domain/review/service/dto/response/ReviewableResult.java +++ b/src/main/java/org/guzzing/studayserver/domain/review/service/dto/response/ReviewableResult.java @@ -1,12 +1,12 @@ package org.guzzing.studayserver.domain.review.service.dto.response; public record ReviewableResult( - Long memberId, - Long academyId, + long memberId, + long academyId, boolean reviewable ) { - public static ReviewableResult of(final Long memberId, final Long academyId, final boolean reviewable) { + public static ReviewableResult of(final long memberId, final long academyId, final boolean reviewable) { return new ReviewableResult(memberId, academyId, reviewable); } diff --git a/src/test/java/org/guzzing/studayserver/domain/review/controller/ReviewRestControllerTest.java b/src/test/java/org/guzzing/studayserver/domain/review/controller/ReviewRestControllerTest.java index 06bacb84e..1d2449e78 100644 --- a/src/test/java/org/guzzing/studayserver/domain/review/controller/ReviewRestControllerTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/review/controller/ReviewRestControllerTest.java @@ -21,29 +21,38 @@ import com.epages.restdocs.apispec.ResourceSnippetParameters; import com.fasterxml.jackson.databind.ObjectMapper; -import org.guzzing.studayserver.domain.academy.listener.NewReviewListener; -import org.guzzing.studayserver.domain.academy.service.AcademyAccessService; -import org.guzzing.studayserver.domain.member.service.MemberAccessService; +import org.guzzing.studayserver.domain.academy.model.Academy; +import org.guzzing.studayserver.domain.academy.model.ReviewCount; +import org.guzzing.studayserver.domain.academy.repository.academy.AcademyRepository; +import org.guzzing.studayserver.domain.academy.repository.review.ReviewCountRepository; +import org.guzzing.studayserver.domain.member.model.Member; +import org.guzzing.studayserver.domain.member.repository.MemberRepository; import org.guzzing.studayserver.domain.review.controller.dto.request.ReviewPostRequest; import org.guzzing.studayserver.domain.review.fixture.ReviewFixture; import org.guzzing.studayserver.domain.review.repository.ReviewRepository; import org.guzzing.studayserver.testutil.JwtTestConfig; import org.guzzing.studayserver.testutil.WithMockCustomOAuth2LoginUser; +import org.guzzing.studayserver.testutil.fixture.academy.AcademyFixture; +import org.guzzing.studayserver.testutil.fixture.member.MemberFixture; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; +import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; import org.springframework.transaction.annotation.Transactional; @AutoConfigureMockMvc @AutoConfigureRestDocs +@TestMethodOrder(OrderAnnotation.class) @SpringBootTest +@Transactional class ReviewRestControllerTest { private static final String TAG = "리뷰 API"; @@ -56,27 +65,30 @@ class ReviewRestControllerTest { @Autowired private JwtTestConfig jwtTestConfig; - @MockBean - private MemberAccessService memberAccessService; - @MockBean - private AcademyAccessService academyAccessService; - @MockBean - private NewReviewListener newReviewListener; - @Autowired - private ReviewRepository reviewRepository; + private MemberRepository memberRepository; + @Autowired + private AcademyRepository academyRepository; + @Autowired + private ReviewCountRepository reviewCountRepository; + + private Academy savedAcademy; @BeforeEach void setUp() { - reviewRepository.deleteAll(); + memberRepository.save(MemberFixture.makeMemberEntity()); + savedAcademy = academyRepository.save(AcademyFixture.academySungnam()); + reviewCountRepository.save(ReviewCount.makeDefaultReviewCount(savedAcademy)); } @Test + @Order(value = 1) @DisplayName("리뷰 타입이 3개 이하고, 해당 학원에 대해서 등록한 학원이 없다면 리뷰를 등록한다.") - @WithMockCustomOAuth2LoginUser + @WithMockCustomOAuth2LoginUser(memberId = 1) void registerReview_Success() throws Exception { // Given - ReviewPostRequest request = ReviewFixture.makeReviewPostRequest(true); + ReviewPostRequest request = ReviewFixture.makeReviewPostRequest(savedAcademy.getId(), + ReviewFixture.makeValidReviewMap()); String jsonBody = objectMapper.writeValueAsString(request); // When @@ -91,7 +103,7 @@ void registerReview_Success() throws Exception { .andExpect(status().isCreated()) .andExpect(content().contentTypeCompatibleWith(APPLICATION_JSON_VALUE)) .andExpect(jsonPath("$.reviewId").isNumber()) - .andExpect(jsonPath("$.academyId").isNumber()) + .andExpect(jsonPath("$.academyId").value(savedAcademy.getId())) .andDo(document("post-review", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), @@ -122,16 +134,13 @@ void registerReview_Success() throws Exception { } @Test + @Order(value = 2) @DisplayName("리뷰를 등록한 적 없다면 리뷰 등록 가능함을 응답한다.") - @WithMockCustomOAuth2LoginUser - @Transactional + @WithMockCustomOAuth2LoginUser(memberId = 2) void getReviewable_NotExistsReview_Reviewable() throws Exception { - // Given - final Long academyId = 1L; - // When ResultActions perform = mockMvc.perform(get("/reviews/reviewable") - .param("academyId", String.valueOf(academyId)) + .param("academyId", String.valueOf(savedAcademy.getId())) .header(AUTHORIZATION_HEADER, jwtTestConfig.getJwt()) .accept(APPLICATION_JSON_VALUE) .contentType(APPLICATION_JSON_VALUE)); @@ -140,7 +149,7 @@ void getReviewable_NotExistsReview_Reviewable() throws Exception { perform.andDo(print()) .andExpect(status().isOk()) .andExpect(content().contentTypeCompatibleWith(APPLICATION_JSON_VALUE)) - .andExpect(jsonPath("$.academyId").value(1L)) + .andExpect(jsonPath("$.academyId").value(savedAcademy.getId())) .andExpect(jsonPath("$.reviewable").value(true)) .andDo(document("get-reviewable", preprocessRequest(prettyPrint()), diff --git a/src/test/java/org/guzzing/studayserver/domain/review/fixture/ReviewFixture.java b/src/test/java/org/guzzing/studayserver/domain/review/fixture/ReviewFixture.java index 1cd83ee76..4bda4add3 100644 --- a/src/test/java/org/guzzing/studayserver/domain/review/fixture/ReviewFixture.java +++ b/src/test/java/org/guzzing/studayserver/domain/review/fixture/ReviewFixture.java @@ -15,32 +15,15 @@ public class ReviewFixture { - public static final Long memberId = 1L; - public static final Long academyId = 1L; + public static ReviewPostParam makeReviewPostParam(final long memberId, final long academyId, final Map reviewMap) { + ReviewPostRequest request = makeReviewPostRequest(academyId, reviewMap); - public static ReviewPostParam makeReviewPostParam(boolean isValid) { - ReviewPostRequest request = makeReviewPostRequest(isValid); - - return ReviewPostRequest.to(1L, request); - } - - public static ReviewPostParam makeReviewPostParam(long academyId) { - return new ReviewPostParam( - 1L, - academyId, - true, - true, - false, - false, - true, - false); + return ReviewPostRequest.to(memberId, request); } - public static ReviewPostRequest makeReviewPostRequest(boolean isValid) { - Map reviewMap = isValid ? makeValidReviewMap() : makeInvalidReviewMap(); - + public static ReviewPostRequest makeReviewPostRequest(final long academyId, final Map reviewMap) { return new ReviewPostRequest( - 1L, + academyId, reviewMap.get(KINDNESS), reviewMap.get(CHEAP_FEE), reviewMap.get(GOOD_FACILITY), @@ -49,19 +32,6 @@ public static ReviewPostRequest makeReviewPostRequest(boolean isValid) { reviewMap.get(SHUTTLE_AVAILABILITY)); } - public static Map makeInvalidReviewMap() { - Map invalidReviewMap = new ConcurrentHashMap<>(); - - invalidReviewMap.put(KINDNESS, true); - invalidReviewMap.put(CHEAP_FEE, true); - invalidReviewMap.put(GOOD_FACILITY, true); - invalidReviewMap.put(GOOD_MANAGEMENT, false); - invalidReviewMap.put(LOVELY_TEACHING, true); - invalidReviewMap.put(SHUTTLE_AVAILABILITY, false); - - return invalidReviewMap; - } - public static Map makeValidReviewMap() { Map validReviewMap = new ConcurrentHashMap<>(); @@ -75,4 +45,17 @@ public static Map makeValidReviewMap() { return validReviewMap; } + public static Map makeInvalidReviewMap() { + Map invalidReviewMap = new ConcurrentHashMap<>(); + + invalidReviewMap.put(KINDNESS, true); + invalidReviewMap.put(CHEAP_FEE, true); + invalidReviewMap.put(GOOD_FACILITY, true); + invalidReviewMap.put(GOOD_MANAGEMENT, false); + invalidReviewMap.put(LOVELY_TEACHING, true); + invalidReviewMap.put(SHUTTLE_AVAILABILITY, false); + + return invalidReviewMap; + } + } diff --git a/src/test/java/org/guzzing/studayserver/domain/review/service/ReviewFacadeTest.java b/src/test/java/org/guzzing/studayserver/domain/review/service/ReviewFacadeTest.java index f63d274ce..37604fccb 100644 --- a/src/test/java/org/guzzing/studayserver/domain/review/service/ReviewFacadeTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/review/service/ReviewFacadeTest.java @@ -5,125 +5,108 @@ import static org.guzzing.studayserver.domain.review.model.ReviewType.CHEAP_FEE; import static org.guzzing.studayserver.domain.review.model.ReviewType.GOOD_FACILITY; +import jakarta.persistence.EntityExistsException; import java.util.Map; -import org.guzzing.studayserver.domain.academy.listener.NewReviewListener; import org.guzzing.studayserver.domain.academy.model.Academy; import org.guzzing.studayserver.domain.academy.model.ReviewCount; import org.guzzing.studayserver.domain.academy.repository.academy.AcademyRepository; import org.guzzing.studayserver.domain.academy.repository.review.ReviewCountRepository; -import org.guzzing.studayserver.domain.academy.service.AcademyAccessService; -import org.guzzing.studayserver.domain.member.service.MemberAccessService; +import org.guzzing.studayserver.domain.member.model.Member; +import org.guzzing.studayserver.domain.member.repository.MemberRepository; import org.guzzing.studayserver.domain.review.fixture.ReviewFixture; import org.guzzing.studayserver.domain.review.model.ReviewType; -import org.guzzing.studayserver.domain.review.repository.ReviewRepository; import org.guzzing.studayserver.domain.review.service.dto.request.ReviewPostParam; import org.guzzing.studayserver.domain.review.service.dto.response.ReviewPostResult; import org.guzzing.studayserver.domain.review.service.dto.response.ReviewableResult; -import org.guzzing.studayserver.global.exception.ReviewException; import org.guzzing.studayserver.testutil.fixture.academy.AcademyFixture; +import org.guzzing.studayserver.testutil.fixture.member.MemberFixture; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.transaction.annotation.Transactional; @SpringBootTest +@Transactional class ReviewFacadeTest { @Autowired private ReviewFacade reviewFacade; - @MockBean - private AcademyAccessService academyAccessService; - @MockBean - private MemberAccessService memberAccessService; - @Autowired - private ReviewRepository reviewRepository; - - @Autowired - private ReviewCountRepository reviewCountRepository; + private MemberRepository memberRepository; @Autowired private AcademyRepository academyRepository; @Autowired - private NewReviewListener newReviewListener; + private ReviewCountRepository reviewCountRepository; + + private Member savedMember; + private Academy savedAcademy; @BeforeEach void setUp() { - reviewRepository.deleteAll(); + savedMember = memberRepository.save(MemberFixture.makeMemberEntity()); + savedAcademy = academyRepository.save(AcademyFixture.academySungnam()); + reviewCountRepository.save(ReviewCount.makeDefaultReviewCount(savedAcademy)); } @Test @DisplayName("해당 학원에 리뷰를 남긴 적이 없으면 리뷰를 등록한다.") void createReviewOfAcademy_NotReviewYet_RegisterReview() { // Given - Academy academy = AcademyFixture.academySungnam(); - Academy savedAcademy = academyRepository.save(academy); - - ReviewCount reviewCount = ReviewCount.makeDefaultReviewCount(academy); - reviewCountRepository.save(reviewCount); - - ReviewPostParam param = ReviewFixture.makeReviewPostParam(savedAcademy.getId()); - Map validReviewMap = ReviewFixture.makeValidReviewMap(); + Map reviewMap = ReviewFixture.makeValidReviewMap(); + ReviewPostParam param = ReviewFixture.makeReviewPostParam(savedMember.getId(), savedAcademy.getId(), reviewMap); // When - int beforeKindnessCount = reviewCountRepository.getByAcademyId(param.academyId()).getKindnessCount(); ReviewPostResult result = reviewFacade.createReviewOfAcademy(param); - int afterKindnessCount = reviewCountRepository.getByAcademyId(param.academyId()).getKindnessCount(); + int kindnessCount = reviewCountRepository.getByAcademyId(param.academyId()) + .getKindnessCount(); // Then - assertThat(afterKindnessCount).isEqualTo(beforeKindnessCount + 1); + assertThat(kindnessCount).isOne(); assertThat(result).satisfies(entry -> { - assertThat(entry.memberId()).isEqualTo(ReviewFixture.memberId); + assertThat(entry.memberId()).isEqualTo(savedMember.getId()); assertThat(entry.academyId()).isEqualTo(savedAcademy.getId()); - assertThat(entry.cheapFee()).isEqualTo(validReviewMap.get(CHEAP_FEE)); - assertThat(entry.goodFacility()).isEqualTo(validReviewMap.get(GOOD_FACILITY)); + assertThat(entry.cheapFee()).isEqualTo(reviewMap.get(CHEAP_FEE)); + assertThat(entry.goodFacility()).isEqualTo(reviewMap.get(GOOD_FACILITY)); }); } @Test @DisplayName("해당 학원에 리뷰를 남겼다면 리뷰 등록에 실패한다.") - @Transactional void createReviewOfAcademy_Reviewed_Fail() { // Given - boolean isValid = true; - ReviewPostParam param = ReviewFixture.makeReviewPostParam(isValid); + ReviewPostParam param = ReviewFixture.makeReviewPostParam(savedMember.getId(), savedAcademy.getId(), + ReviewFixture.makeValidReviewMap()); reviewFacade.createReviewOfAcademy(param); // When & Then assertThatThrownBy(() -> reviewFacade.createReviewOfAcademy(param)) - .isInstanceOf(ReviewException.class) + .isInstanceOf(EntityExistsException.class) .hasMessage("이미 리뷰를 남겼습니다."); } @Test @DisplayName("리뷰를 3 항목 초과로 남겼다면 리뷰 등록에 실패한다.") - @Transactional - void createReviewOfAcademy_GreaterThanThreeReivewTypes_Fail() { + void createReviewOfAcademy_GreaterThanThreeReviewTypes_Fail() { // Given - boolean isValid = false; - ReviewPostParam param = ReviewFixture.makeReviewPostParam(isValid); + ReviewPostParam param = ReviewFixture.makeReviewPostParam(savedMember.getId(), savedAcademy.getId(), + ReviewFixture.makeInvalidReviewMap()); // When & Then assertThatThrownBy(() -> reviewFacade.createReviewOfAcademy(param)) - .isInstanceOf(ReviewException.class) + .isInstanceOf(IllegalArgumentException.class) .hasMessage("리뷰는 3개 까지 가능합니다."); } @Test @DisplayName("해당 학원에 리뷰를 남긴 적 없으면 리뷰 등록 가능하다.") - @Transactional void isReviewableToAcademy_NotExistsReview_Reviewable() { - // Given - final Long memberId = 100L; - final Long academyId = 100L; - // When - ReviewableResult result = reviewFacade.getReviewableToAcademy(memberId, academyId); + ReviewableResult result = reviewFacade.getReviewableToAcademy(savedMember.getId(), savedAcademy.getId()); // Then assertThat(result.reviewable()).isTrue(); @@ -131,11 +114,10 @@ void isReviewableToAcademy_NotExistsReview_Reviewable() { @Test @DisplayName("해당 학원에 리뷰를 남겼다면 리뷰 등록 불가하다.") - @Transactional void isReviewableToAcademy_ExistsReview_NotReviewable() { // Given - boolean isValid = true; - ReviewPostParam param = ReviewFixture.makeReviewPostParam(isValid); + ReviewPostParam param = ReviewFixture.makeReviewPostParam(savedMember.getId(), savedAcademy.getId(), + ReviewFixture.makeValidReviewMap()); reviewFacade.createReviewOfAcademy(param); From 97942670706f8cd59eaee2e06b0964352d630030 Mon Sep 17 00:00:00 2001 From: SeYoE Date: Wed, 13 Dec 2023 16:51:49 +0900 Subject: [PATCH 19/21] =?UTF-8?q?Chore:=20Jacoco=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build.gradle b/build.gradle index 675ac1bd8..0e7da291b 100644 --- a/build.gradle +++ b/build.gradle @@ -6,6 +6,7 @@ buildscript { plugins { id 'java' + id 'jacoco' id 'org.springframework.boot' version '3.1.5' id 'io.spring.dependency-management' version '1.1.3' id 'com.epages.restdocs-api-spec' version "${restdocsApiSpecVersion}" @@ -121,5 +122,10 @@ dependencies { } tasks.named('test') { + finalizedBy jacocoTestReport useJUnitPlatform() } + +tasks.named('jacocoTestReport') { + dependsOn test +} From cfd0daafa8a7f01389806714fbd863c88c88eb9a Mon Sep 17 00:00:00 2001 From: SeYoE Date: Wed, 13 Dec 2023 16:51:59 +0900 Subject: [PATCH 20/21] =?UTF-8?q?Style:=20=EC=BD=94=EB=93=9C=20=EB=A6=AC?= =?UTF-8?q?=ED=8F=AC=EB=A7=A4=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../studayserver/domain/academy/model/ReviewCount.java | 1 - .../academy/repository/review/ReviewCountJpaRepository.java | 1 - .../guzzing/studayserver/domain/review/model/Review.java | 1 - .../studayserver/domain/review/model/ReviewType.java | 2 -- .../domain/review/controller/ReviewRestControllerTest.java | 2 -- .../studayserver/domain/review/fixture/ReviewFixture.java | 6 ++++-- 6 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/model/ReviewCount.java b/src/main/java/org/guzzing/studayserver/domain/academy/model/ReviewCount.java index 820c3b2bb..4706fd329 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/model/ReviewCount.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/model/ReviewCount.java @@ -17,7 +17,6 @@ import jakarta.persistence.Table; import java.util.Map; import lombok.Getter; -import org.guzzing.studayserver.domain.review.model.Review; import org.guzzing.studayserver.domain.review.model.ReviewType; @Getter diff --git a/src/main/java/org/guzzing/studayserver/domain/academy/repository/review/ReviewCountJpaRepository.java b/src/main/java/org/guzzing/studayserver/domain/academy/repository/review/ReviewCountJpaRepository.java index f3cc27029..883c29402 100644 --- a/src/main/java/org/guzzing/studayserver/domain/academy/repository/review/ReviewCountJpaRepository.java +++ b/src/main/java/org/guzzing/studayserver/domain/academy/repository/review/ReviewCountJpaRepository.java @@ -4,7 +4,6 @@ import org.guzzing.studayserver.domain.academy.model.ReviewCount; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; -import org.springframework.transaction.annotation.Transactional; public interface ReviewCountJpaRepository extends JpaRepository, ReviewCountRepository { diff --git a/src/main/java/org/guzzing/studayserver/domain/review/model/Review.java b/src/main/java/org/guzzing/studayserver/domain/review/model/Review.java index 5c6ada8a8..e828416ac 100644 --- a/src/main/java/org/guzzing/studayserver/domain/review/model/Review.java +++ b/src/main/java/org/guzzing/studayserver/domain/review/model/Review.java @@ -5,7 +5,6 @@ import io.hypersistence.utils.hibernate.type.json.JsonType; import jakarta.persistence.Column; import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; diff --git a/src/main/java/org/guzzing/studayserver/domain/review/model/ReviewType.java b/src/main/java/org/guzzing/studayserver/domain/review/model/ReviewType.java index c9da4a3e4..dc460065c 100644 --- a/src/main/java/org/guzzing/studayserver/domain/review/model/ReviewType.java +++ b/src/main/java/org/guzzing/studayserver/domain/review/model/ReviewType.java @@ -4,8 +4,6 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; -import javax.lang.model.type.IntersectionType; -import javax.swing.text.StyledEditorKit.BoldAction; import org.guzzing.studayserver.domain.review.service.dto.request.ReviewPostParam; public enum ReviewType { diff --git a/src/test/java/org/guzzing/studayserver/domain/review/controller/ReviewRestControllerTest.java b/src/test/java/org/guzzing/studayserver/domain/review/controller/ReviewRestControllerTest.java index 1d2449e78..3ae4888d5 100644 --- a/src/test/java/org/guzzing/studayserver/domain/review/controller/ReviewRestControllerTest.java +++ b/src/test/java/org/guzzing/studayserver/domain/review/controller/ReviewRestControllerTest.java @@ -25,11 +25,9 @@ import org.guzzing.studayserver.domain.academy.model.ReviewCount; import org.guzzing.studayserver.domain.academy.repository.academy.AcademyRepository; import org.guzzing.studayserver.domain.academy.repository.review.ReviewCountRepository; -import org.guzzing.studayserver.domain.member.model.Member; import org.guzzing.studayserver.domain.member.repository.MemberRepository; import org.guzzing.studayserver.domain.review.controller.dto.request.ReviewPostRequest; import org.guzzing.studayserver.domain.review.fixture.ReviewFixture; -import org.guzzing.studayserver.domain.review.repository.ReviewRepository; import org.guzzing.studayserver.testutil.JwtTestConfig; import org.guzzing.studayserver.testutil.WithMockCustomOAuth2LoginUser; import org.guzzing.studayserver.testutil.fixture.academy.AcademyFixture; diff --git a/src/test/java/org/guzzing/studayserver/domain/review/fixture/ReviewFixture.java b/src/test/java/org/guzzing/studayserver/domain/review/fixture/ReviewFixture.java index 4bda4add3..191ec70a6 100644 --- a/src/test/java/org/guzzing/studayserver/domain/review/fixture/ReviewFixture.java +++ b/src/test/java/org/guzzing/studayserver/domain/review/fixture/ReviewFixture.java @@ -15,13 +15,15 @@ public class ReviewFixture { - public static ReviewPostParam makeReviewPostParam(final long memberId, final long academyId, final Map reviewMap) { + public static ReviewPostParam makeReviewPostParam(final long memberId, final long academyId, + final Map reviewMap) { ReviewPostRequest request = makeReviewPostRequest(academyId, reviewMap); return ReviewPostRequest.to(memberId, request); } - public static ReviewPostRequest makeReviewPostRequest(final long academyId, final Map reviewMap) { + public static ReviewPostRequest makeReviewPostRequest(final long academyId, + final Map reviewMap) { return new ReviewPostRequest( academyId, reviewMap.get(KINDNESS), From 59c36ad93cc184e38ac848ad911f3f537c9cb547 Mon Sep 17 00:00:00 2001 From: SeYoE Date: Wed, 13 Dec 2023 17:10:08 +0900 Subject: [PATCH 21/21] =?UTF-8?q?Refactor:=20Review=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20=EC=9C=A0=EB=8B=88=ED=81=AC=20=EC=A0=9C=EC=95=BD=20?= =?UTF-8?q?=EC=A1=B0=EA=B1=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/guzzing/studayserver/domain/review/model/Review.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/guzzing/studayserver/domain/review/model/Review.java b/src/main/java/org/guzzing/studayserver/domain/review/model/Review.java index e828416ac..8e02fb548 100644 --- a/src/main/java/org/guzzing/studayserver/domain/review/model/Review.java +++ b/src/main/java/org/guzzing/studayserver/domain/review/model/Review.java @@ -11,6 +11,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; import java.util.Map; import java.util.Map.Entry; import java.util.stream.Collectors; @@ -24,7 +25,7 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity -@Table(name = "reviews") +@Table(name = "reviews", uniqueConstraints = @UniqueConstraint(columnNames = {"member_id", "academy_id"})) public class Review { @Id