diff --git a/server/sql/231224_1450.sql b/server/sql/231224_1450.sql index 1e46604..c618d03 100644 --- a/server/sql/231224_1450.sql +++ b/server/sql/231224_1450.sql @@ -1,2 +1,2 @@ ALTER TABLE alcohol_type - ADD `display_order` bigint DEFAULT NULL \ No newline at end of file + ADD `display_order` int DEFAULT NULL \ No newline at end of file diff --git a/server/src/main/java/com/bside/bside_311/component/AlcoholManager.java b/server/src/main/java/com/bside/bside_311/component/AlcoholManager.java index 3666afa..f060bc7 100644 --- a/server/src/main/java/com/bside/bside_311/component/AlcoholManager.java +++ b/server/src/main/java/com/bside/bside_311/component/AlcoholManager.java @@ -1,17 +1,24 @@ package com.bside.bside_311.component; +import com.bside.bside_311.dto.AlcoholSearchCondition; import com.bside.bside_311.entity.Alcohol; +import com.bside.bside_311.entity.AlcoholType; import com.bside.bside_311.entity.Post; import com.bside.bside_311.entity.PostAlcohol; import com.bside.bside_311.entity.YesOrNo; import com.bside.bside_311.repository.AlcoholRepository; +import com.bside.bside_311.repository.AlcoholTypeRepository; import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Component; @Component @RequiredArgsConstructor public class AlcoholManager { private final AlcoholRepository alcoholRepository; + private final AlcoholTypeRepository alcoholTypeRepository; public void connectAlcoholWithPost(Long alcoholNo, String alcoholFeature, Post post) { Alcohol alcohol = alcoholRepository.findByIdAndDelYnIs(alcoholNo, YesOrNo.N).orElseThrow( @@ -20,4 +27,22 @@ public void connectAlcoholWithPost(Long alcoholNo, String alcoholFeature, Post p post.addPostAlcohol(postAlcohol); alcohol.addPostAlcohol(postAlcohol); } + + public Page searchAlcohol(Pageable pageable, String searchKeyword, + Long alcoholType) { + if (ObjectUtils.isNotEmpty(alcoholType)) { + AlcoholType alcoholType1 = alcoholTypeRepository.findByIdAndDelYnIs(alcoholType, YesOrNo.N) + .orElseThrow( + () -> new IllegalArgumentException( + "술 종류가 존재하지 않습니다.")); + } + // 술 종류 fetch join + return alcoholRepository.searchAlcoholPage(AlcoholSearchCondition.builder() + .searchKeyword( + searchKeyword) + .alcoholType( + alcoholType) + .build(), + pageable); + } } diff --git a/server/src/main/java/com/bside/bside_311/component/AttachManager.java b/server/src/main/java/com/bside/bside_311/component/AttachManager.java index cdcf658..4c58b3a 100644 --- a/server/src/main/java/com/bside/bside_311/component/AttachManager.java +++ b/server/src/main/java/com/bside/bside_311/component/AttachManager.java @@ -1,5 +1,6 @@ package com.bside.bside_311.component; +import com.bside.bside_311.dto.AttachDto; import com.bside.bside_311.entity.Attach; import com.bside.bside_311.entity.AttachType; import com.bside.bside_311.entity.YesOrNo; @@ -8,7 +9,10 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static com.bside.bside_311.util.ValidateUtil.resourceChangeableCheckByThisRequestToken; @@ -50,4 +54,32 @@ public void deleteAttachesByRefNoAndAttachType(Long refNo, AttachType attachType imageStorage.delete(attach.getPublicId()); } } + + public Map> getAttachInfoMapBykeysAndType(List keys, + AttachType attachType) { + List attachList = + attachRepository.findByRefNoInAndAttachTypeIsAndDelYnIs(keys, attachType, + YesOrNo.N); + Map> kToAMap = new HashMap<>(); + for (Attach attach : attachList) { + if (!kToAMap.containsKey(attach.getRefNo())) { + kToAMap.put(attach.getRefNo(), new ArrayList<>()); + } + List attachDtos = kToAMap.get(attach.getRefNo()); + attachDtos.add(AttachDto.of(attach)); + } + return kToAMap; + } + + public List getAttachListBykeyAndType(Long key, + AttachType attachType) { + List attachList = + attachRepository.findByRefNoInAndAttachTypeIsAndDelYnIs(List.of(key), attachType, + YesOrNo.N); + List attachDtos = new ArrayList<>(); + for (Attach attach : attachList) { + attachDtos.add(AttachDto.of(attach)); + } + return attachDtos; + } } diff --git a/server/src/main/java/com/bside/bside_311/component/PostManager.java b/server/src/main/java/com/bside/bside_311/component/PostManager.java deleted file mode 100644 index d9ce88a..0000000 --- a/server/src/main/java/com/bside/bside_311/component/PostManager.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.bside.bside_311.component; - -import com.bside.bside_311.entity.Post; -import com.bside.bside_311.entity.YesOrNo; -import com.bside.bside_311.repository.PostRepository; -import com.bside.bside_311.util.MessageUtil; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -public class PostManager { - private final PostRepository postRepository; - - public void savePost(Post post) { - postRepository.save(post); - } - - public Post findPost(Long postNo) { - return postRepository.findByIdAndDelYnIs(postNo, YesOrNo.N).orElseThrow( - () -> new IllegalArgumentException(MessageUtil.POST_NOT_FOUND_MSG)); - } - - public void deletePost(Post post) { - post.setDelYn(YesOrNo.Y); - postRepository.save(post); - } -} diff --git a/server/src/main/java/com/bside/bside_311/component/PostService.java b/server/src/main/java/com/bside/bside_311/component/PostService.java new file mode 100644 index 0000000..091166d --- /dev/null +++ b/server/src/main/java/com/bside/bside_311/component/PostService.java @@ -0,0 +1,72 @@ +package com.bside.bside_311.component; + +import com.bside.bside_311.dto.GetPostsToOneMvo; +import com.bside.bside_311.dto.PostSearchCondition; +import com.bside.bside_311.entity.Post; +import com.bside.bside_311.entity.YesOrNo; +import com.bside.bside_311.repository.PostMybatisRepository; +import com.bside.bside_311.repository.PostRepository; +import com.bside.bside_311.util.AuthUtil; +import com.bside.bside_311.util.MessageUtil; +import lombok.RequiredArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +@RequiredArgsConstructor +public class PostService { + private final PostRepository postRepository; + private final PostMybatisRepository postMybatisRepository; + + public void savePost(Post post) { + postRepository.save(post); + } + + public Post findPost(Long postNo) { + return postRepository.findByIdAndDelYnIs(postNo, YesOrNo.N).orElseThrow( + () -> new IllegalArgumentException(MessageUtil.POST_NOT_FOUND_MSG)); + } + + public void deletePost(Post post) { + post.setDelYn(YesOrNo.Y); + postRepository.save(post); + } + + public Page getPostListCommon(Pageable pageable, String searchKeyword, + List searchUserNoList, + Boolean isLikedByMe, Boolean isCommentedByMe, + List searchAlcoholNoList) { + return postRepository.searchPageSimple( + PostSearchCondition.builder().searchKeyword(searchKeyword) + .searchUserNoList(searchUserNoList) + .isLikedByMe(isLikedByMe) + .isCommentedByMe(isCommentedByMe) + .myUserNo( + AuthUtil.getUserNoFromAuthentication()) + .searchAlcoholNoList(searchAlcoholNoList) + .build(), pageable); + } + + public Page getPostListPopular(Long page, Long size) { + return postRepository.searchPagePopular(page, size); + } + + public Map getGetPostsToOneMvoMap(List postNos) { + List postsToOneList = + CollectionUtils.isNotEmpty(postNos) ? postMybatisRepository.getPostsToOne(postNos) : + List.of(); + Map postsToOneMap = new HashMap<>(); + for (GetPostsToOneMvo getPostsToOneMvo : postsToOneList) { + postsToOneMap.put(getPostsToOneMvo.getPostNo(), getPostsToOneMvo); + } + return postsToOneMap; + } + + +} diff --git a/server/src/main/java/com/bside/bside_311/component/UserManager.java b/server/src/main/java/com/bside/bside_311/component/UserManager.java new file mode 100644 index 0000000..124f1cf --- /dev/null +++ b/server/src/main/java/com/bside/bside_311/component/UserManager.java @@ -0,0 +1,25 @@ +package com.bside.bside_311.component; + +import com.bside.bside_311.entity.User; +import com.bside.bside_311.entity.YesOrNo; +import com.bside.bside_311.repository.UserRepository; +import com.bside.bside_311.util.MessageUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +@Slf4j +@Component +@RequiredArgsConstructor +public class UserManager { + private final UserRepository userRepository; + + public User getUser(Long userNo) { + if (ObjectUtils.isEmpty(userNo)) { + return null; + } + return userRepository.findByIdAndDelYnIs(userNo, YesOrNo.N).orElseThrow( + () -> new IllegalArgumentException(MessageUtil.USER_NOT_FOUND_MSG)); + } +} diff --git a/server/src/main/java/com/bside/bside_311/controller/AlcoholController.java b/server/src/main/java/com/bside/bside_311/controller/AlcoholController.java index b9ed0de..4e5689b 100644 --- a/server/src/main/java/com/bside/bside_311/controller/AlcoholController.java +++ b/server/src/main/java/com/bside/bside_311/controller/AlcoholController.java @@ -14,6 +14,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; +import jakarta.validation.constraints.Positive; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; @@ -102,9 +103,13 @@ public Page getAlcoholV2( Pageable pageable, @RequestParam(required = false, name = "searchKeyword") @Schema(description = "키워드", example = "키워드") - String searchKeyword) { + String searchKeyword, + @RequestParam(required = false, name = "alcoholType") + @Schema(description = "술 타입(선택)", example = "1") + @Positive(message = "술 타입은 1이상의 숫자만 가능합니다.") + Long alcoholType) { log.info(">>> AlcoholController.getAlcohol"); - return alcoholService.getAlcoholV2(pageable, searchKeyword); + return alcoholService.getAlcoholV2(pageable, searchKeyword, alcoholType); } @Operation(summary = "[o]술 상세 조회", description = "술 상세 조회 API") diff --git a/server/src/main/java/com/bside/bside_311/controller/PostController.java b/server/src/main/java/com/bside/bside_311/controller/PostController.java index 0f682d5..ec1537b 100644 --- a/server/src/main/java/com/bside/bside_311/controller/PostController.java +++ b/server/src/main/java/com/bside/bside_311/controller/PostController.java @@ -12,8 +12,9 @@ import com.bside.bside_311.dto.GetPostResponseDto; import com.bside.bside_311.dto.GetQuotesByPostResponseDto; import com.bside.bside_311.dto.PostResponseDto; +import com.bside.bside_311.dto.common.ResultDto; import com.bside.bside_311.entity.Post; -import com.bside.bside_311.service.PostService; +import com.bside.bside_311.service.PostFacade; import com.bside.bside_311.util.AuthUtil; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Schema; @@ -48,7 +49,7 @@ @RequestMapping("/posts") @Tag(name = "게시글", description = "게시글 API") public class PostController { - private final PostService postService; + private final PostFacade postFacade; @Operation(summary = "[o]게시글 등록 ", description = "게시글 등록 API") @UserRequired @@ -56,7 +57,7 @@ public class PostController { @ResponseStatus(HttpStatus.CREATED) public AddPostResponseDto addPost(@RequestBody @Valid AddPostRequestDto addPostRequestDto) { log.info(">>> PostController.addPost"); - return postService.addPost(Post.of(addPostRequestDto), addPostRequestDto.getAlcoholNo(), + return postFacade.addPost(Post.of(addPostRequestDto), addPostRequestDto.getAlcoholNo(), addPostRequestDto.getAlcoholFeature(), addPostRequestDto.getTagList()); } @@ -67,7 +68,7 @@ public void editPost(@PathVariable("postNo") Long postNo, @RequestBody @Valid EditPostRequestDto editPostRequestDto) { log.info(">>> PostController.editPost"); - postService.editPost(postNo, editPostRequestDto); + postFacade.editPost(postNo, editPostRequestDto); } @Operation(summary = "[o]게시글 삭제", description = "게시글 삭제 API") @@ -75,7 +76,7 @@ public void editPost(@PathVariable("postNo") Long postNo, @DeleteMapping("/{postNo}") public void deletePost(@PathVariable("postNo") Long postNo) { log.info(">>> PostController.deletePost"); - postService.deletePost(postNo); + postFacade.deletePost(postNo); } @Operation(summary = "[o]게시글 목록 조회(v1)", description = "게시글 조회 API") @@ -110,7 +111,7 @@ public GetPostResponseDto getPosts(@RequestParam(name = "page", defaultValue = " } catch (Exception e) { log.error(">>> PostController.getPost searchUserNos 파싱 에러 Exception", e); } - return postService.getPosts(page, size, orderColumn, orderType, searchKeyword, + return postFacade.getPosts(page, size, orderColumn, orderType, searchKeyword, searchUserNoList); } @@ -165,15 +166,29 @@ public Page getPostsV2( } } - return postService.getPostsV2(pageable, searchKeyword, searchUserNoList, isLikedByMe, + return postFacade.getPostsV2(pageable, searchKeyword, searchUserNoList, isLikedByMe, isCommentedByMe, searchAlcoholNoList); } + // TODO 추후 캐싱 처리 예정.(레디스) + @Operation(summary = "[o] 인기 게시글 목록 조회", description = "인기 게시글 조회 API Page, size 사용법.
ex1) /posts/popular?page=0&size=10
ex2) /posts/popular?page=1&size=10") + @GetMapping("/popular") + public ResultDto> getPostsPopular( + @RequestParam(required = true, name = "page") + @Schema(description = "페이지", example = "0") + Long page, + @RequestParam(required = true, name = "size") + @Schema(description = "사이즈", example = "10") + Long size + ) { + return postFacade.getPostsPopular(page, size); + } + @Operation(summary = "[o]게시글 상세 조회", description = "게시글 상세 조회 API") @GetMapping("/{postNo}") public PostResponseDto getPostDetail(@PathVariable("postNo") Long postNo) { log.info(">>> PostController.getPostDetail"); - return postService.getPostDetail(postNo); + return postFacade.getPostDetail(postNo); } @Operation(summary = "[o]게시글 댓글 등록", description = "게시글 댓글 등록 API") @@ -183,7 +198,7 @@ public PostResponseDto getPostDetail(@PathVariable("postNo") Long postNo) { public AddCommentResponseDto addComment(@PathVariable("postNo") Long postNo, @Valid @RequestBody AddCommentRequestDto addCommentRequestDto) { log.info(">>> PostController.addComment"); - return postService.addComment(postNo, addCommentRequestDto); + return postFacade.addComment(postNo, addCommentRequestDto); } @Operation(summary = "[o]게시글 댓글 조회", description = "게시글 댓글 조회 API") @@ -191,7 +206,7 @@ public AddCommentResponseDto addComment(@PathVariable("postNo") Long postNo, @Va @ResponseStatus(HttpStatus.CREATED) public GetPostCommentsResponseDto getPostComments(@PathVariable("postNo") Long postNo) { log.info(">>> PostController.getPostComments"); - return postService.getPostComments(postNo); + return postFacade.getPostComments(postNo); } @Operation(summary = "[o]게시글 댓글 수정", description = "게시글 댓글 수정 API") @@ -202,7 +217,7 @@ public void editComment(@PathVariable("postNo") Long postNo, @Valid @RequestBody EditCommentRequestDto editCommentRequestDto) { log.info(">>> PostController.editComment"); - postService.editComment(postNo, commentNo, editCommentRequestDto); + postFacade.editComment(postNo, commentNo, editCommentRequestDto); } @Operation(summary = "[o]게시글 댓글 삭제", description = "게시글 댓글 삭제 API") @@ -211,7 +226,7 @@ public void editComment(@PathVariable("postNo") Long postNo, public void deleteComment(@PathVariable("postNo") Long postNo, @PathVariable("commentNo") Long commentNo) { log.info(">>> PostController.deleteComment"); - postService.deleteComment(postNo, commentNo); + postFacade.deleteComment(postNo, commentNo); } @Operation(summary = "[o]인용 등록 ", description = "인용 등록 API") @@ -224,7 +239,7 @@ public AddQuoteResponseDto addQuote(@PathVariable("postNo") , @PathVariable("quotedPostNo") @Schema(example = "2", description = "인용하는 포스트 번호") Long quotedPostNo) { log.info(">>> PostController.addQuote"); - return AddQuoteResponseDto.of(postService.addQuote(postNo, quotedPostNo)); + return AddQuoteResponseDto.of(postFacade.addQuote(postNo, quotedPostNo)); } @Operation(summary = "[o]인용 삭제", description = "인용 삭제 API") @@ -232,14 +247,14 @@ public AddQuoteResponseDto addQuote(@PathVariable("postNo") @UserRequired public void deleteQuote(@PathVariable("quoteNo") Long quoteNo) { log.info(">>> PostController.deleteQuote"); - postService.deleteQuote(quoteNo); + postFacade.deleteQuote(quoteNo); } @Operation(summary = "[o]인용 복수 조회", description = "인용 복수 조회 API") @GetMapping("/post-quotes/{postNo}") public GetQuotesByPostResponseDto getQuotesByPost(@PathVariable("postNo") Long postNo) { log.info(">>> PostController.getQuoteDetail"); - return postService.getQuotesByPost(postNo); + return postFacade.getQuotesByPost(postNo); } @Operation(summary = "[o]게시글 좋아요", description = "게시글 좋아요 API") @@ -248,7 +263,7 @@ public GetQuotesByPostResponseDto getQuotesByPost(@PathVariable("postNo") Long p public void likePost(@PathVariable("postNo") Long postNo) { log.info(">>> PostController.likePost"); Long userNo = AuthUtil.getUserNoFromAuthentication(); - postService.likePost(userNo, postNo); + postFacade.likePost(userNo, postNo); } @Operation(summary = "[o]게시글 좋아요 취소", description = "게시글 좋아요 취소 API") @@ -257,7 +272,7 @@ public void likePost(@PathVariable("postNo") Long postNo) { public void likeCancelPost(@PathVariable("postNo") Long postNo) { log.info(">>> PostController.likeCancelPost"); Long userNo = AuthUtil.getUserNoFromAuthentication(); - postService.likeCancelPost(userNo, postNo); + postFacade.likeCancelPost(userNo, postNo); } } diff --git a/server/src/main/java/com/bside/bside_311/controller/UserController.java b/server/src/main/java/com/bside/bside_311/controller/UserController.java index a7989d7..a5fd030 100644 --- a/server/src/main/java/com/bside/bside_311/controller/UserController.java +++ b/server/src/main/java/com/bside/bside_311/controller/UserController.java @@ -11,11 +11,13 @@ import com.bside.bside_311.dto.UserSignupRequestDto; import com.bside.bside_311.dto.UserSignupResponseDto; import com.bside.bside_311.dto.UserUpdateRequestDto; +import com.bside.bside_311.dto.common.ResultDto; import com.bside.bside_311.entity.Role; import com.bside.bside_311.entity.User; import com.bside.bside_311.service.UserService; import com.bside.bside_311.util.AuthUtil; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -30,6 +32,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; @@ -131,12 +134,29 @@ public Page getMyFollowingUsers(Pageable pageable) { @Operation(summary = "[o]나를 팔로잉하는 유저 조회", description = "나를 팔로잉하는 유저 조회") @UserRequired @GetMapping("/users-of-following-me") - public Page getUsersOfFollowingMe(Pageable pageable) { + public Page getUsersPopular(Pageable pageable) { Long myUserNo = AuthUtil.getUserNoFromAuthentication(); log.info(">>> UserController.getMyFollowingUsers"); return userService.getUsersOfFollowingMe(myUserNo, pageable); } + + // TODO 추후 캐싱 처리 예정.(레디스) + @Operation(summary = "[o]인기순 유저 조회", description = "인기순 유저 조회") + @UserRequired + @GetMapping("/popular") + public ResultDto> getUsersOfFollowingMe( + @RequestParam(required = true, name = "page") + @Schema(description = "페이지", example = "0") + Long page, + @RequestParam(required = true, name = "size") + @Schema(description = "사이즈", example = "10") + Long size) { + log.info(">>> UserController.getMyFollowingUsers"); + Long myUserNo = AuthUtil.getUserNoFromAuthentication(); + return userService.getUsersPopular(page, size, myUserNo); + } + @Operation(summary = "[o]유저 정보 조회", description = "유저 정보 조회 API") @GetMapping("/{userNo}/summary") public GetUserInfoResponseDto getUserInfo(@PathVariable("userNo") Long userNo) { diff --git a/server/src/main/java/com/bside/bside_311/dto/AlcoholSearchCondition.java b/server/src/main/java/com/bside/bside_311/dto/AlcoholSearchCondition.java index 3460026..c897f61 100644 --- a/server/src/main/java/com/bside/bside_311/dto/AlcoholSearchCondition.java +++ b/server/src/main/java/com/bside/bside_311/dto/AlcoholSearchCondition.java @@ -13,4 +13,6 @@ public class AlcoholSearchCondition { @Schema(description = "키워드", example = "키워드") String searchKeyword; + @Schema(description = "술 종류 PK", example = "1") + Long alcoholType; } diff --git a/server/src/main/java/com/bside/bside_311/dto/PostResponseDto.java b/server/src/main/java/com/bside/bside_311/dto/PostResponseDto.java index d074aaa..d88323d 100644 --- a/server/src/main/java/com/bside/bside_311/dto/PostResponseDto.java +++ b/server/src/main/java/com/bside/bside_311/dto/PostResponseDto.java @@ -58,7 +58,8 @@ public class PostResponseDto { private Long quoteCount; public static PostResponseDto of(Post post, User user, Alcohol alcohol, List tags, - List comments, List attachDtos + List comments, List postAttachDtos, + List profileAttachDtos , Boolean isLikedByMe, Boolean isFollowedByMe, Long likeCount, Long quoteCount) { PostResponseDtoBuilder postResponseDtoBuilder = PostResponseDto.builder(); if (user != null) { @@ -74,10 +75,12 @@ public static PostResponseDto of(Post post, User user, Alcohol alcohol, List profileImgUrls = new ArrayList<>(); @@ -44,4 +45,19 @@ public static UserResponseDto of(User user, List userAttachDtos, .profileImgUrls(userAttachDtos) .build(); } + + public static UserResponseDto of(UserIncludeFollowCountDto user, List attachDtos, + Boolean isFollowedByMe) { + return UserResponseDto.builder() + .nickname(user.getNickname()) + .id(user.getId()) + .userNo(user.getUserNo()) + .introduction(user.getIntroduction()) + .createdBy(user.getCreatedBy()) + .isFollowedByMe(isFollowedByMe) + .profileImgUrls(attachDtos) + // followedCount + .followedCount(user.getFollowedCount()) + .build(); + } } diff --git a/server/src/main/java/com/bside/bside_311/dto/common/ResultDto.java b/server/src/main/java/com/bside/bside_311/dto/common/ResultDto.java new file mode 100644 index 0000000..217360d --- /dev/null +++ b/server/src/main/java/com/bside/bside_311/dto/common/ResultDto.java @@ -0,0 +1,21 @@ +package com.bside.bside_311.dto.common; + +import com.bside.bside_311.util.ResultCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor(staticName = "of") +public class ResultDto { + private final String resultCode; + private final String message; + private final D data; + + public static ResultDto of(ResultCode resultCode, D data) { + return new ResultDto(resultCode.getCode(), resultCode.getMessage(), data); + } + + public static ResultDto successOf(D data) { + return new ResultDto(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), data); + } +} diff --git a/server/src/main/java/com/bside/bside_311/exercise/TestController.java b/server/src/main/java/com/bside/bside_311/exercise/TestController.java index ba4c819..6f861da 100644 --- a/server/src/main/java/com/bside/bside_311/exercise/TestController.java +++ b/server/src/main/java/com/bside/bside_311/exercise/TestController.java @@ -1,6 +1,9 @@ package com.bside.bside_311.exercise; import com.bside.bside_311.config.security.AdminRequired; +import com.bside.bside_311.dto.UserResponseDto; +import com.bside.bside_311.dto.common.ResultDto; +import com.bside.bside_311.entity.User; import lombok.RequiredArgsConstructor; import org.springframework.core.io.InputStreamResource; import org.springframework.core.io.Resource; @@ -43,4 +46,9 @@ public ResponseEntity getImage() { return ResponseEntity.notFound() .build(); } + + @GetMapping("/common-result-dto") + public ResultDto testCommonResultDto() { + return ResultDto.of("200", "success", UserResponseDto.of(User.of(1L))); + } } diff --git a/server/src/main/java/com/bside/bside_311/init/Initializer.java b/server/src/main/java/com/bside/bside_311/init/Initializer.java index 18536d0..d603397 100644 --- a/server/src/main/java/com/bside/bside_311/init/Initializer.java +++ b/server/src/main/java/com/bside/bside_311/init/Initializer.java @@ -71,11 +71,6 @@ private static void copyInputStreamToFile(InputStream inputStream, File file) th FileUtils.copyInputStreamToFile(inputStream, file); } - private void setSecurityContextUserNo(Long userNo) { - SecurityContextHolder.getContext() - .setAuthentication(easyUserRoleAuthenticationFactory(userNo)); - } - @PostConstruct public void init() throws JsonProcessingException { initAlcoholType(); @@ -91,6 +86,11 @@ public void init() throws JsonProcessingException { } + private void setSecurityContextUserNo(Long userNo) { + SecurityContextHolder.getContext() + .setAuthentication(easyUserRoleAuthenticationFactory(userNo)); + } + private void initPostQuotes() { // 인용하기. // 2번 게시글이 1번 게시글을 인용. @@ -158,6 +158,7 @@ private void initFollowingRelation() { // 4L -> 2L // 5L -> 2L // 2L -> 4L + // 1L -> 2L setSecurityContextUserNo(1L); setSecutiryContextDoSomethingAndClear(1L, () -> { userController.followUser(3L); @@ -177,6 +178,9 @@ private void initFollowingRelation() { setSecutiryContextDoSomethingAndClear(2L, () -> { userController.followUser(4L); }); + setSecutiryContextDoSomethingAndClear(1L, () -> { + userController.followUser(2L); + }); } private void initAlcoholsAndPosts() { diff --git a/server/src/main/java/com/bside/bside_311/repository/AlcoholRepositoryImpl.java b/server/src/main/java/com/bside/bside_311/repository/AlcoholRepositoryImpl.java index 0e2c782..685c0ad 100644 --- a/server/src/main/java/com/bside/bside_311/repository/AlcoholRepositoryImpl.java +++ b/server/src/main/java/com/bside/bside_311/repository/AlcoholRepositoryImpl.java @@ -2,27 +2,21 @@ import com.bside.bside_311.dto.AlcoholSearchCondition; import com.bside.bside_311.entity.Alcohol; -import com.bside.bside_311.entity.Post; -import com.bside.bside_311.entity.QAlcohol; -import com.bside.bside_311.entity.QAlcoholType; -import com.bside.bside_311.entity.QUser; import com.bside.bside_311.entity.YesOrNo; import com.bside.bside_311.repository.support.Querydsl4RepositorySupport; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; +import org.apache.commons.lang3.ObjectUtils; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.util.StringUtils; -import java.util.Optional; import java.util.function.Function; import static com.bside.bside_311.entity.QAlcohol.alcohol; import static com.bside.bside_311.entity.QAlcoholType.alcoholType; -import static com.bside.bside_311.entity.QPost.post; public class AlcoholRepositoryImpl extends Querydsl4RepositorySupport implements AlcoholRepositoryCustom { @@ -39,14 +33,20 @@ public Page searchAlcoholPage(AlcoholSearchCondition condition, Pageabl query -> query.select(alcohol) .from(alcohol) .leftJoin(alcoholType).on((alcohol.alcoholType.eq(alcoholType)) - .and(alcohol.delYn.eq(YesOrNo.N)) - .and(alcoholType.delYn.eq(YesOrNo.N))) + .and(alcohol.delYn.eq(YesOrNo.N)) + .and(alcoholType.delYn.eq(YesOrNo.N))) .where(contentLike(condition.getSearchKeyword()), + alcoholTypeIs(condition.getAlcoholType()), notDeleted()); return applyPagination(pageable, jpaQueryFactoryJPAQueryFunction ); } + private BooleanExpression alcoholTypeIs(Long alcoholType) { + return ObjectUtils.isNotEmpty(alcoholType) ? alcohol.alcoholType.id.eq(alcoholType) : + null; + } + private BooleanExpression contentLike(String searchKeyword) { return StringUtils.hasText(searchKeyword) ? alcohol.name.contains(searchKeyword) : null; } diff --git a/server/src/main/java/com/bside/bside_311/repository/PostRepositoryCustom.java b/server/src/main/java/com/bside/bside_311/repository/PostRepositoryCustom.java index cb059a2..9139a88 100644 --- a/server/src/main/java/com/bside/bside_311/repository/PostRepositoryCustom.java +++ b/server/src/main/java/com/bside/bside_311/repository/PostRepositoryCustom.java @@ -7,4 +7,6 @@ public interface PostRepositoryCustom { Page searchPageSimple(PostSearchCondition condition, Pageable pageable); + + Page searchPagePopular(Long page, Long size); } diff --git a/server/src/main/java/com/bside/bside_311/repository/PostRepositoryImpl.java b/server/src/main/java/com/bside/bside_311/repository/PostRepositoryImpl.java index add0493..2df2ad5 100644 --- a/server/src/main/java/com/bside/bside_311/repository/PostRepositoryImpl.java +++ b/server/src/main/java/com/bside/bside_311/repository/PostRepositoryImpl.java @@ -12,7 +12,9 @@ import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; +import org.springframework.data.support.PageableExecutionUtils; import org.springframework.util.StringUtils; import java.util.List; @@ -60,6 +62,28 @@ public Page searchPageSimple(PostSearchCondition condition, Pageable pagea ); } + @Override + public Page searchPagePopular(Long page, Long size) { + List postQueryResults = queryFactory.select(post) + .from(post) + .leftJoin(postLike) + .on(postLike.post.eq(post).and( + postLike.delYn.eq(YesOrNo.N))) + .where(notDeleted()) + .groupBy(post.id) + .orderBy(postLike.count().desc()) + .offset(page * size) + .limit(size) + .fetch(); + // groupBy 행 결과를 query로 받음. + JPAQuery prepareCountQuery = queryFactory.selectOne() + .from(post) + .where(notDeleted()) + .groupBy(post.id); + return PageableExecutionUtils.getPage(postQueryResults, PageRequest.of(page.intValue(), + size.intValue()), () -> prepareCountQuery.fetch().size()); + } + private BooleanExpression contentLike(String searchKeyword) { return StringUtils.hasText(searchKeyword) ? post.content.contains(searchKeyword) : null; } diff --git a/server/src/main/java/com/bside/bside_311/repository/UserFollowRepository.java b/server/src/main/java/com/bside/bside_311/repository/UserFollowRepository.java index 8515bd6..2b05aa0 100644 --- a/server/src/main/java/com/bside/bside_311/repository/UserFollowRepository.java +++ b/server/src/main/java/com/bside/bside_311/repository/UserFollowRepository.java @@ -16,6 +16,10 @@ List findByFollowingIsAndFollowedIsInAndDelYnIs(User followingUser, List followedUserNos, YesOrNo delYn); + List findByFollowingIsAndFollowed_IdIsInAndDelYnIs(User followingUser, + List followedUserNos, + YesOrNo delYn); + Long countByFollowedAndDelYnIs(User followed, YesOrNo delYn); Long countByFollowingAndDelYnIs(User following, YesOrNo delYn); diff --git a/server/src/main/java/com/bside/bside_311/repository/UserRepositoryCustom.java b/server/src/main/java/com/bside/bside_311/repository/UserRepositoryCustom.java index a460efa..c97501b 100644 --- a/server/src/main/java/com/bside/bside_311/repository/UserRepositoryCustom.java +++ b/server/src/main/java/com/bside/bside_311/repository/UserRepositoryCustom.java @@ -1,5 +1,6 @@ package com.bside.bside_311.repository; +import com.bside.bside_311.dto.UserIncludeFollowCountDto; import com.bside.bside_311.entity.User; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -8,4 +9,6 @@ public interface UserRepositoryCustom { Page getMyFollowingUsersPage(Long userNo, Pageable pageable); Page getUsersOfFollowingMePage(Long userNo, Pageable pageable); + + Page getUsersPopular(Long page, Long size); } diff --git a/server/src/main/java/com/bside/bside_311/repository/UserRepositoryImpl.java b/server/src/main/java/com/bside/bside_311/repository/UserRepositoryImpl.java index 0d65028..ed57ba5 100644 --- a/server/src/main/java/com/bside/bside_311/repository/UserRepositoryImpl.java +++ b/server/src/main/java/com/bside/bside_311/repository/UserRepositoryImpl.java @@ -1,15 +1,20 @@ package com.bside.bside_311.repository; +import com.bside.bside_311.dto.UserIncludeFollowCountDto; import com.bside.bside_311.entity.User; import com.bside.bside_311.entity.YesOrNo; import com.bside.bside_311.repository.support.Querydsl4RepositorySupport; +import com.querydsl.core.Tuple; import com.querydsl.jpa.JPAExpressions; import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; +import org.springframework.data.support.PageableExecutionUtils; +import java.util.List; import java.util.function.Function; import static com.bside.bside_311.entity.QUser.user; @@ -72,4 +77,32 @@ public Page getUsersOfFollowingMePage(Long myUserNo, Pageable pageable) { return applyPagination(pageable, jpaQueryFactoryJPAQueryFunction); } + + @Override + public Page getUsersPopular(Long page, Long size) { + List userQueryResults = queryFactory.select(user, userFollow.count()) + .from(user) + .leftJoin(userFollow) + .on(userFollow.followed.eq(user).and( + userFollow.delYn.eq(YesOrNo.N))) + .where(user.delYn.eq(YesOrNo.N)) + .groupBy(user.id) + .orderBy(userFollow.count().desc()) + .offset(page * size) + .limit(size) + .fetch(); + JPAQuery prepareCountQuery = queryFactory.selectOne() + .from(user) + .leftJoin(userFollow) + .on(userFollow.followed.eq(user).and( + userFollow.delYn.eq(YesOrNo.N))) + .where(user.delYn.eq(YesOrNo.N)) + .groupBy(user.id); + Page userTuples = + PageableExecutionUtils.getPage(userQueryResults, PageRequest.of(page.intValue(), + size.intValue()), () -> prepareCountQuery.fetch().size()); + return userTuples.map(tuple -> { + return UserIncludeFollowCountDto.of(tuple.get(user), tuple.get(userFollow.count())); + }); + } } diff --git a/server/src/main/java/com/bside/bside_311/service/AlcoholService.java b/server/src/main/java/com/bside/bside_311/service/AlcoholService.java index cfbdfc4..4a2cf7c 100644 --- a/server/src/main/java/com/bside/bside_311/service/AlcoholService.java +++ b/server/src/main/java/com/bside/bside_311/service/AlcoholService.java @@ -1,9 +1,10 @@ package com.bside.bside_311.service; +import com.bside.bside_311.component.AlcoholManager; +import com.bside.bside_311.component.AttachManager; import com.bside.bside_311.dto.AddAlcoholRequestDto; import com.bside.bside_311.dto.AddAlcoholResponseDto; import com.bside.bside_311.dto.AlcoholResponseDto; -import com.bside.bside_311.dto.AlcoholSearchCondition; import com.bside.bside_311.dto.AttachDto; import com.bside.bside_311.dto.EditAlcoholRequestDto; import com.bside.bside_311.dto.GetAlcoholResponseDto; @@ -14,7 +15,6 @@ import com.bside.bside_311.entity.AlcoholNickname; import com.bside.bside_311.entity.AlcoholTag; import com.bside.bside_311.entity.AlcoholType; -import com.bside.bside_311.entity.Attach; import com.bside.bside_311.entity.AttachType; import com.bside.bside_311.entity.Tag; import com.bside.bside_311.entity.YesOrNo; @@ -45,6 +45,8 @@ @RequiredArgsConstructor @Transactional public class AlcoholService { + private final AlcoholManager alcoholManager; + private final AttachManager attachManager; private final AlcoholRepository alcoholRepository; private final TagService tagService; private final TagRepository tagRepository; @@ -189,25 +191,12 @@ public GetAlcoholResponseDto getAlcohol(Long page, Long size, String orderColumn return GetAlcoholResponseDto.of(alcoholResponseDtos, alcoholsCount); } - public Page getAlcoholV2(Pageable pageable, String searchKeyword) { - // 술 종류 fetch join - Page alcohols = alcoholRepository.searchAlcoholPage(AlcoholSearchCondition.builder() - .searchKeyword( - searchKeyword) - .build(), - pageable); + public Page getAlcoholV2(Pageable pageable, String searchKeyword, + Long alcoholType) { + Page alcohols = alcoholManager.searchAlcohol(pageable, searchKeyword, alcoholType); List alcoholNos = alcohols.stream().map(Alcohol::getId).toList(); - List alcoholAttachList = - attachRepository.findByRefNoInAndAttachTypeIsAndDelYnIs(alcoholNos, AttachType.ALCOHOL, - YesOrNo.N); - Map> aToAMap = new HashMap<>(); - for (Attach attach : alcoholAttachList) { - if (!aToAMap.containsKey(attach.getRefNo())) { - aToAMap.put(attach.getRefNo(), new ArrayList<>()); - } - List attachDtos = aToAMap.get(attach.getRefNo()); - attachDtos.add(AttachDto.of(attach)); - } + Map> aToAMap = attachManager.getAttachInfoMapBykeysAndType(alcoholNos, + AttachType.ALCOHOL); return alcohols.map(alcohol -> { List attachDtos = aToAMap.getOrDefault(alcohol.getId(), new ArrayList<>()); return AlcoholResponseDto.of(alcohol, attachDtos); diff --git a/server/src/main/java/com/bside/bside_311/service/PostService.java b/server/src/main/java/com/bside/bside_311/service/PostFacade.java similarity index 68% rename from server/src/main/java/com/bside/bside_311/service/PostService.java rename to server/src/main/java/com/bside/bside_311/service/PostFacade.java index cf11c24..5bcd531 100644 --- a/server/src/main/java/com/bside/bside_311/service/PostService.java +++ b/server/src/main/java/com/bside/bside_311/service/PostFacade.java @@ -3,9 +3,10 @@ import com.bside.bside_311.component.AlcoholManager; import com.bside.bside_311.component.AttachManager; import com.bside.bside_311.component.PostAlcoholManager; -import com.bside.bside_311.component.PostManager; +import com.bside.bside_311.component.PostService; import com.bside.bside_311.component.PostTagManager; import com.bside.bside_311.component.TagManager; +import com.bside.bside_311.component.UserManager; import com.bside.bside_311.dto.AddCommentRequestDto; import com.bside.bside_311.dto.AddCommentResponseDto; import com.bside.bside_311.dto.AddPostResponseDto; @@ -19,9 +20,8 @@ import com.bside.bside_311.dto.GetPostsToOneMvo; import com.bside.bside_311.dto.GetQuotesByPostResponseDto; import com.bside.bside_311.dto.PostResponseDto; -import com.bside.bside_311.dto.PostSearchCondition; +import com.bside.bside_311.dto.common.ResultDto; import com.bside.bside_311.entity.Alcohol; -import com.bside.bside_311.entity.Attach; import com.bside.bside_311.entity.AttachType; import com.bside.bside_311.entity.Comment; import com.bside.bside_311.entity.Post; @@ -44,7 +44,7 @@ import com.bside.bside_311.repository.UserFollowRepository; import com.bside.bside_311.repository.UserRepository; import com.bside.bside_311.util.AuthUtil; -import com.bside.bside_311.util.MessageUtil; +import com.bside.bside_311.util.ResultCode; import io.micrometer.common.util.StringUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -66,7 +66,8 @@ @Slf4j @RequiredArgsConstructor @Transactional -public class PostService { +public class PostFacade { + private final UserManager userManager; private final TagManager tagManager; private final AttachManager attachManager; private final PostTagManager postTagManager; @@ -75,7 +76,7 @@ public class PostService { private final AlcoholManager alcoholManager; private final UserRepository userRepository; private final PostLikeRepository postLikeRepository; - private final PostManager postManager; + private final PostService postService; private final PostRepository postRepository; private final PostMybatisRepository postMybatisRepository; private final TagRepository tagRepository; @@ -86,6 +87,18 @@ public class PostService { private final PostQuoteRepository postQuoteRepository; private final UserFollowRepository userFollowRepository; + private Alcohol getAlcohol(Post post) { + if (ObjectUtils.isEmpty(post) || CollectionUtils.isEmpty(post.getPostAlcohols())) { + return null; + } + List postAlcohols = post.getPostAlcohols(); + if (CollectionUtils.isNotEmpty(postAlcohols)) { + return postAlcohols.stream().filter(postAlcohol -> postAlcohol.getDelYn() == YesOrNo.N) + .map(PostAlcohol::getAlcohol).findFirst().orElse(null); + } + return null; + } + public AddPostResponseDto addPost( Post post, Long alcoholNo, String alcoholFeature, List tagStrList) { @@ -93,7 +106,7 @@ public AddPostResponseDto addPost( if (CollectionUtils.isNotEmpty(tagStrList)) { tagManager.registerTagsToPost(post, tagStrList); } - postManager.savePost(post); + postService.savePost(post); if (alcoholNo != null) { alcoholManager.connectAlcoholWithPost(alcoholNo, alcoholFeature, post); } @@ -101,9 +114,8 @@ public AddPostResponseDto addPost( return AddPostResponseDto.of(post); } - public void editPost(Long postNo, EditPostRequestDto editPostRequestDto) { - Post post = postManager.findPost(postNo); + Post post = postService.findPost(postNo); resourceChangeableCheckByThisRequestToken(post); if (StringUtils.isNotEmpty(editPostRequestDto.getPostContent())) { post.setContent(editPostRequestDto.getPostContent()); @@ -134,67 +146,39 @@ public void editPost(Long postNo, EditPostRequestDto editPostRequestDto) { } } - public void deletePost(Long postNo) { - Post post = postManager.findPost(postNo); + Post post = postService.findPost(postNo); resourceChangeableCheckByThisRequestToken(post); - postManager.deletePost(post); + postService.deletePost(post); postTagManager.deletePostTagByPost(post); postAlcoholManager.deletePostAlcoholByPost(post); attachManager.deleteAttachesByRefNoAndAttachType(postNo, AttachType.POST); } - - public PostResponseDto getPostDetail(Long postNo, List attachDtos) { - Post post = postManager.findPost(postNo); + public PostResponseDto getPostDetail(Long postNo) { + Post post = postService.findPost(postNo); Long userNo = post.getCreatedBy(); - User user = null; - if (userNo != null) { - user = userRepository.findByIdAndDelYnIs(userNo, YesOrNo.N).orElseThrow( - () -> new IllegalArgumentException(MessageUtil.USER_NOT_FOUND_MSG)); - } - Alcohol alcohol = null; - List postAlcohols = post.getPostAlcohols(); - if (CollectionUtils.isNotEmpty(postAlcohols)) { - alcohol = postAlcohols.stream().filter(postAlcohol -> postAlcohol.getDelYn() == YesOrNo.N) - .map(PostAlcohol::getAlcohol).findFirst().orElse(null); - } - - List nonDeletedPostTags = - post.getPostTags().stream().filter(postTag -> postTag.getDelYn() == YesOrNo.N).toList(); - - List tags = tagRepository.findByPostTagsInAndDelYnIs(nonDeletedPostTags, YesOrNo.N); - List comments = commentRepository.findByPostAndDelYnIs(post, YesOrNo.N); - if (attachDtos == null) { - attachDtos = - AttachDto.of( - attachRepository.findByRefNoAndAttachTypeIsAndDelYnIs(post.getId(), AttachType.POST, - YesOrNo.N)); - } + User user = userManager.getUser(userNo); + Alcohol alcohol = getAlcohol(post); + List tags = getTags(post); + List comments = getComments(post); + + List postAttachDtos = + attachManager.getAttachListBykeyAndType(post.getId(), AttachType.POST); + List profileAttachDtos = + attachManager.getAttachListBykeyAndType(post.getId(), AttachType.PROFILE); // isFollowedByMe, isLikedByMe, quoteInfo, likeCount, quoteCount Long myUserNo = AuthUtil.getUserNoFromAuthentication(); - Boolean isLikedByMe = null; - Boolean isFollowdByMe = null; - if (myUserNo != null) { - isLikedByMe = - postLikeRepository.findByUserAndPostAndDelYnIs(User.of(myUserNo), post, YesOrNo.N) - .isPresent(); - if (post.getCreatedBy() != null) { - isFollowdByMe = userFollowRepository.findByFollowingAndFollowedAndDelYnIs( - User.of(myUserNo), User.of(post.getCreatedBy()), YesOrNo.N).isPresent(); - } - } - Long likeCount = postLikeRepository.countByPostAndDelYnIs(post, YesOrNo.N); - Long quoteCount = postQuoteRepository.countByPostAndDelYnIs(post, YesOrNo.N); + Boolean isLikedByMe = getLikedByMe(post, myUserNo); + Boolean isFollowdByMe = getFollowedByMe(post, myUserNo); + Long likeCount = getLikeCount(post); + Long quoteCount = getQuoteCount(post); - return PostResponseDto.of(post, user, alcohol, tags, comments, attachDtos, isLikedByMe, + return PostResponseDto.of(post, user, alcohol, tags, comments, postAttachDtos, + profileAttachDtos, isLikedByMe, isFollowdByMe, likeCount, quoteCount); } - public PostResponseDto getPostDetail(Long postNo) { - return getPostDetail(postNo, null); - } - public GetPostResponseDto getPosts(Long page, Long size, String orderColumn, String orderType, String searchKeyword, List searchUserNoList) { GetPostVo getPostVo = GetPostVo.builder() @@ -221,47 +205,20 @@ public Page getPostsV2(Pageable pageable, Boolean isLikedByMe, Boolean isCommentedByMe, List searchAlcoholNoList) { Page posts = - postRepository.searchPageSimple(PostSearchCondition.builder().searchKeyword(searchKeyword) - .searchUserNoList(searchUserNoList) - .isLikedByMe(isLikedByMe) - .isCommentedByMe(isCommentedByMe) - .myUserNo( - AuthUtil.getUserNoFromAuthentication()) - .searchAlcoholNoList(searchAlcoholNoList) - .build(), pageable); + postService.getPostListCommon(pageable, searchKeyword, searchUserNoList, isLikedByMe, + isCommentedByMe, + searchAlcoholNoList); + List postNos = posts.stream().map(Post::getId).toList(); - List postsToOneList = - CollectionUtils.isNotEmpty(postNos) ? postMybatisRepository.getPostsToOne(postNos) : - List.of(); - Map postsToOneMap = new HashMap<>(); - for (GetPostsToOneMvo getPostsToOneMvo : postsToOneList) { - postsToOneMap.put(getPostsToOneMvo.getPostNo(), getPostsToOneMvo); - } + Map postsToOneMap = + postService.getGetPostsToOneMvoMap(postNos); - List postAttachList = - attachRepository.findByRefNoInAndAttachTypeIsAndDelYnIs(postNos, AttachType.POST, - YesOrNo.N); - Map> pToAMap = new HashMap<>(); - for (Attach attach : postAttachList) { - if (!pToAMap.containsKey(attach.getRefNo())) { - pToAMap.put(attach.getRefNo(), new ArrayList<>()); - } - List attachDtos = pToAMap.get(attach.getRefNo()); - attachDtos.add(AttachDto.of(attach)); - } + Map> pToAMap = + attachManager.getAttachInfoMapBykeysAndType(postNos, AttachType.POST); List postCreatedBys = posts.stream().map(Post::getCreatedBy).toList(); - List userAttachList = - attachRepository.findByRefNoInAndAttachTypeIsAndDelYnIs(postCreatedBys, AttachType.PROFILE, - YesOrNo.N); - Map> uToAMap = new HashMap<>(); - for (Attach attach : userAttachList) { - if (!uToAMap.containsKey(attach.getRefNo())) { - uToAMap.put(attach.getRefNo(), new ArrayList<>()); - } - List attachDtos = uToAMap.get(attach.getRefNo()); - attachDtos.add(AttachDto.of(attach)); - } + Map> uToAMap = + attachManager.getAttachInfoMapBykeysAndType(postCreatedBys, AttachType.PROFILE); return posts.map(post -> { GetPostsToOneMvo getPostsToOneMvo = postsToOneMap.get(post.getId()); @@ -271,8 +228,31 @@ public Page getPostsV2(Pageable pageable, }); } + public ResultDto> getPostsPopular(Long page, Long size) { + Page posts = + postService.getPostListPopular(page, size); + + List postNos = posts.stream().map(Post::getId).toList(); + Map postsToOneMap = + postService.getGetPostsToOneMvoMap(postNos); + + Map> pToAMap = + attachManager.getAttachInfoMapBykeysAndType(postNos, AttachType.POST); + + List postCreatedBys = posts.stream().map(Post::getCreatedBy).toList(); + Map> uToAMap = + attachManager.getAttachInfoMapBykeysAndType(postCreatedBys, AttachType.PROFILE); + + return ResultDto.of(ResultCode.SUCCESS, posts.map(post -> { + GetPostsToOneMvo getPostsToOneMvo = postsToOneMap.get(post.getId()); + List postAttachDtos = pToAMap.getOrDefault(post.getId(), new ArrayList<>()); + List userAttachDtos = uToAMap.getOrDefault(post.getCreatedBy(), new ArrayList<>()); + return PostResponseDto.of(post, getPostsToOneMvo, postAttachDtos, userAttachDtos); + })); + } + public AddCommentResponseDto addComment(Long postNo, AddCommentRequestDto addCommentRequestDto) { - Post post = postManager.findPost(postNo); + Post post = postService.findPost(postNo); Comment comment = Comment.of(post, addCommentRequestDto.getCommentContent()); post.addComment(comment); commentRepository.save(comment); @@ -281,7 +261,7 @@ public AddCommentResponseDto addComment(Long postNo, AddCommentRequestDto addCom } public GetPostCommentsResponseDto getPostComments(Long postNo) { - Post post = postManager.findPost(postNo); + Post post = postService.findPost(postNo); List comments = post.getComments().stream().filter(comment -> comment.getDelYn() == YesOrNo.N).toList(); // FIXME 최적화. 추후 페이징 처리할것. @@ -293,25 +273,15 @@ public GetPostCommentsResponseDto getPostComments(Long postNo) { createdByToUser.put(user.getId(), user); } - List attachList = - attachRepository.findByRefNoInAndAttachTypeIsAndDelYnIs(commentCreatedList, - AttachType.PROFILE, - YesOrNo.N); - Map> uToAMap = new HashMap<>(); - for (Attach attach : attachList) { - if (!uToAMap.containsKey(attach.getRefNo())) { - uToAMap.put(attach.getRefNo(), new ArrayList<>()); - } - List attachDtos = uToAMap.get(attach.getRefNo()); - attachDtos.add(AttachDto.of(attach)); - } + Map> uToAMap = + attachManager.getAttachInfoMapBykeysAndType(commentCreatedList, AttachType.PROFILE); return GetPostCommentsResponseDto.of(comments, createdByToUser, uToAMap); } public void editComment(Long postNo, Long commentNo, EditCommentRequestDto editCommentRequestDto) { - postManager.findPost(postNo); + postService.findPost(postNo); Comment comment = commentRepository.findByIdAndDelYnIs(commentNo, YesOrNo.N).orElseThrow( () -> new IllegalArgumentException("댓글이 존재하지 않습니다.")); resourceChangeableCheckByThisRequestToken(comment); @@ -322,7 +292,7 @@ public void editComment(Long postNo, Long commentNo, } public void deleteComment(Long postNo, Long commentNo) { - postManager.findPost(postNo); + postService.findPost(postNo); Comment comment = commentRepository.findByIdAndDelYnIs(commentNo, YesOrNo.N).orElseThrow( () -> new IllegalArgumentException("댓글이 존재하지 않습니다.")); resourceChangeableCheckByThisRequestToken(comment); @@ -330,7 +300,7 @@ public void deleteComment(Long postNo, Long commentNo) { } public PostQuote addQuote(Long postNo, Long quotedPostNo) { - Post post = postManager.findPost(postNo); + Post post = postService.findPost(postNo); Post quotedPost = postRepository.findByIdAndDelYnIs(quotedPostNo, YesOrNo.N).orElseThrow( () -> new IllegalArgumentException("인용할 게시글이 존재하지 않습니다.")); @@ -349,15 +319,14 @@ public void deleteQuote(Long quoteNo) { } public GetQuotesByPostResponseDto getQuotesByPost(Long postNo) { - Post post = postManager.findPost(postNo); + Post post = postService.findPost(postNo); List postQuotes = postQuoteRepository.findByPostAndDelYnIs(post, YesOrNo.N); return GetQuotesByPostResponseDto.of(postQuotes); } public void likePost(Long userNo, Long postNo) { - User user = userRepository.findByIdAndDelYnIs(userNo, YesOrNo.N).orElseThrow( - () -> new IllegalArgumentException(MessageUtil.USER_NOT_FOUND_MSG)); - Post post = postManager.findPost(postNo); + User user = userManager.getUser(userNo); + Post post = postService.findPost(postNo); PostLike postLike = postLikeRepository.findByUserAndPostAndDelYnIs(user, post, YesOrNo.N).orElse( @@ -366,9 +335,8 @@ public void likePost(Long userNo, Long postNo) { } public void likeCancelPost(Long userNo, Long postNo) { - User user = userRepository.findByIdAndDelYnIs(userNo, YesOrNo.N).orElseThrow( - () -> new IllegalArgumentException(MessageUtil.USER_NOT_FOUND_MSG)); - Post post = postManager.findPost(postNo); + User user = userManager.getUser(userNo); + Post post = postService.findPost(postNo); PostLike postLike = postLikeRepository.findByUserAndPostAndDelYnIs(user, post, YesOrNo.N).orElseThrow( @@ -376,4 +344,50 @@ public void likeCancelPost(Long userNo, Long postNo) { resourceChangeableCheckByThisRequestToken(postLike); postLike.setDelYn(YesOrNo.Y); } + + private Long getQuoteCount(Post post) { + return postQuoteRepository.countByPostAndDelYnIs(post, YesOrNo.N); + } + + private Long getLikeCount(Post post) { + return postLikeRepository.countByPostAndDelYnIs(post, YesOrNo.N); + } + + private Boolean getFollowedByMe(Post post, Long myUserNo) { + if (ObjectUtils.isEmpty(post) || ObjectUtils.isEmpty(post.getCreatedBy()) || ObjectUtils + .isEmpty( + myUserNo)) { + return null; + } + return userFollowRepository.findByFollowingAndFollowedAndDelYnIs( + User.of(myUserNo), User.of(post.getCreatedBy()), YesOrNo.N).isPresent(); + } + + private Boolean getLikedByMe(Post post, Long myUserNo) { + if (ObjectUtils.isEmpty(post) || ObjectUtils.isEmpty(post.getId()) || + ObjectUtils.isEmpty(myUserNo)) { + return null; + } + return postLikeRepository.findByUserAndPostAndDelYnIs(User.of(myUserNo), post, YesOrNo.N) + .isPresent(); + } + + private List getPostAttachDto(Post post) { + return AttachDto.of( + attachRepository.findByRefNoAndAttachTypeIsAndDelYnIs(post.getId(), AttachType.POST, + YesOrNo.N)); + } + + private List getComments(Post post) { + return commentRepository.findByPostAndDelYnIs(post, YesOrNo.N); + } + + private List getTags(Post post) { + if (ObjectUtils.isEmpty(post) || CollectionUtils.isEmpty(post.getPostTags())) { + return List.of(); + } + List nonDeletedPostTags = + post.getPostTags().stream().filter(postTag -> postTag.getDelYn() == YesOrNo.N).toList(); + return tagRepository.findByPostTagsInAndDelYnIs(nonDeletedPostTags, YesOrNo.N); + } } diff --git a/server/src/main/java/com/bside/bside_311/service/UserService.java b/server/src/main/java/com/bside/bside_311/service/UserService.java index 9427553..61794c8 100644 --- a/server/src/main/java/com/bside/bside_311/service/UserService.java +++ b/server/src/main/java/com/bside/bside_311/service/UserService.java @@ -5,10 +5,12 @@ import com.bside.bside_311.dto.GetUserInfoResponseDto; import com.bside.bside_311.dto.LoginResponseDto; import com.bside.bside_311.dto.MyInfoResponseDto; +import com.bside.bside_311.dto.UserIncludeFollowCountDto; import com.bside.bside_311.dto.UserLoginRequestDto; import com.bside.bside_311.dto.UserResponseDto; import com.bside.bside_311.dto.UserSignupResponseDto; import com.bside.bside_311.dto.UserUpdateRequestDto; +import com.bside.bside_311.dto.common.ResultDto; import com.bside.bside_311.entity.Attach; import com.bside.bside_311.entity.AttachType; import com.bside.bside_311.entity.User; @@ -230,6 +232,24 @@ public Map> getUserFollowInfoFollowingIsAndFollowedIsIn(L return uToFMap; } + public Map> getUserFollowInfoFollowingIsAndFollowed_IdIsIn(Long myUserNo, + List followedUserNoList) { + List userFollowList = + userFollowRepository.findByFollowingIsAndFollowed_IdIsInAndDelYnIs(User.of(myUserNo), + followedUserNoList, + YesOrNo.N); + Map> uToFMap = new HashMap<>(); + for (UserFollow userFollow : userFollowList) { + Long targetUserNo = userFollow.getFollowed().getId(); + if (!uToFMap.containsKey(targetUserNo)) { + uToFMap.put(targetUserNo, new ArrayList<>()); + } + List userFollows = uToFMap.get(targetUserNo); + userFollows.add(userFollow); + } + return uToFMap; + } + public Map> getUserAttachInfos(List userNos) { List userAttachList = @@ -245,4 +265,17 @@ public Map> getUserAttachInfos(List userNos) { } return uToAMap; } + + public ResultDto> getUsersPopular(Long page, Long size, Long myUserNo) { + Page users = userRepository.getUsersPopular(page, size); + List userNos = users.stream().map(UserIncludeFollowCountDto::getUserNo).toList(); + Map> uToUFMap = + getUserFollowInfoFollowingIsAndFollowed_IdIsIn(myUserNo, userNos); + Map> uToAMap = getUserAttachInfos(userNos); + return ResultDto.successOf(users.map(user -> { + List attachDtos = uToAMap.getOrDefault(user.getId(), List.of()); + Boolean isFollowedByMe = uToUFMap.containsKey(user.getId()); + return UserResponseDto.of(user, attachDtos, isFollowedByMe); + })); + } } diff --git a/server/src/main/java/com/bside/bside_311/util/ResultCode.java b/server/src/main/java/com/bside/bside_311/util/ResultCode.java new file mode 100644 index 0000000..e47b944 --- /dev/null +++ b/server/src/main/java/com/bside/bside_311/util/ResultCode.java @@ -0,0 +1,25 @@ +package com.bside.bside_311.util; + +public enum ResultCode { + SUCCESS("RES000", "success"), + FAIL("RES999", "fail"), + UNAUTHORIZED("RES998", "unauthorized"), + NOT_FOUND("404", "not found"), + INTERNAL_SERVER_ERROR("RES997", "internal server error"); + + private final String code; + private final String message; + + ResultCode(String code, String message) { + this.code = code; + this.message = message; + } + + public String getCode() { + return this.code; + } + + public String getMessage() { + return this.message; + } +} diff --git a/server/src/test/java/com/bside/bside_311/controller/AlcoholControllerTest.java b/server/src/test/java/com/bside/bside_311/controller/AlcoholControllerTest.java index e0bfffc..30437a2 100644 --- a/server/src/test/java/com/bside/bside_311/controller/AlcoholControllerTest.java +++ b/server/src/test/java/com/bside/bside_311/controller/AlcoholControllerTest.java @@ -27,4 +27,24 @@ void getAlcoholTypeList() throws Exception { //then } + + @Test + void getAlcoholV2_success() throws Exception { + // given + // when + // then + String queryParameter = "?alcoholType=1&searchKeyword=소주"; + mockMvc.perform(get(String.format("/alcohols/v2%s", queryParameter))) + .andExpect(status().isOk()); + } + + @Test + void getAlcoholV2_fail() throws Exception { + // given + // when + // then + String queryParameter = "?alcoholType=asdf&searchKeyword=소주"; + mockMvc.perform(get(String.format("/alcohols/v2%s", queryParameter))) + .andExpect(status().is4xxClientError()); + } } \ No newline at end of file diff --git a/server/src/test/java/com/bside/bside_311/controller/PostControllerTest.java b/server/src/test/java/com/bside/bside_311/controller/PostControllerTest.java index 39d000c..e0eaa74 100644 --- a/server/src/test/java/com/bside/bside_311/controller/PostControllerTest.java +++ b/server/src/test/java/com/bside/bside_311/controller/PostControllerTest.java @@ -3,7 +3,7 @@ import com.bside.bside_311.dto.AddPostRequestDto; import com.bside.bside_311.dto.AddPostResponseDto; import com.bside.bside_311.entity.Post; -import com.bside.bside_311.service.PostService; +import com.bside.bside_311.service.PostFacade; import com.bside.bside_311.util.JwtUtil; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Test; @@ -29,7 +29,7 @@ class PostControllerTest extends ControllerTest { private MockMvc mockMvc; @MockBean - private PostService postService; + private PostFacade postFacade; @Autowired private ObjectMapper objectMapper; @@ -40,7 +40,7 @@ void addPost_success() throws Exception { AddPostRequestDto addPostRequestDto = AddPostRequestDto.builder().alcoholNo(1L).alcoholFeature("산뜻함. 달콤함.").postContent("게시글 내용") .postType("BASIC").positionInfo("위치 정보").build(); - given(postService.addPost(any(), any(), any(), any())).willReturn( + given(postFacade.addPost(any(), any(), any(), any())).willReturn( AddPostResponseDto.of(Post.builder().id(1L).build())); //when //then @@ -115,6 +115,28 @@ void getPostsV2_fail_due_to_parsing_error() throws Exception { .andExpect(status().is4xxClientError()); } + @Test + void getPostsPopular_success() throws Exception { + //given + //when + //then + String queryParameter = "?page=1&size=10"; + mockMvc.perform( + get(String.format("/posts/popular%s", queryParameter))) + .andExpect(status().isOk()); + } + + @Test + void getPostsPopular_fail() throws Exception { + //given + //when + //then + String queryParameter = "?page=asdf&size=10"; + mockMvc.perform( + get(String.format("/posts/popular%s", queryParameter))) + .andExpect(status().is4xxClientError()); + } + @Test void getPostDetail_success() { } diff --git a/server/src/test/java/com/bside/bside_311/controller/UserControllerTest.java b/server/src/test/java/com/bside/bside_311/controller/UserControllerTest.java index c722d52..421e508 100644 --- a/server/src/test/java/com/bside/bside_311/controller/UserControllerTest.java +++ b/server/src/test/java/com/bside/bside_311/controller/UserControllerTest.java @@ -274,4 +274,26 @@ void getUsersOfFollowingMePage_success() throws Exception { .andExpect(status().isOk()) .andExpect(content().string(containsString("userNo"))); } + + @Test + void getUsersPopular_success() throws Exception { + //given + //when + //then + String queryParameter = "?page=1&size=10"; + mockMvc.perform(get(String.format("/user/popular%s", queryParameter)).header("Authorization", + "Bearer " + userAccessToken)) + .andExpect(status().isOk()); + } + + @Test + void getUsersPopular_fail() throws Exception { + //given + //when + //then + String queryParameter = "?page=asdf&size=10"; + mockMvc.perform(get(String.format("/user/popular%s", queryParameter)).header("Authorization", + "Bearer " + userAccessToken)) + .andExpect(status().is4xxClientError()); + } } \ No newline at end of file diff --git a/server/src/test/java/com/bside/bside_311/repository/AlcoholRepositoryTest.java b/server/src/test/java/com/bside/bside_311/repository/AlcoholRepositoryTest.java new file mode 100644 index 0000000..47a8a6f --- /dev/null +++ b/server/src/test/java/com/bside/bside_311/repository/AlcoholRepositoryTest.java @@ -0,0 +1,92 @@ +package com.bside.bside_311.repository; + +import com.bside.bside_311.dto.AlcoholSearchCondition; +import com.bside.bside_311.entity.Alcohol; +import com.bside.bside_311.entity.AlcoholType; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; + +import java.util.ArrayList; +import java.util.List; + +@DataJpaTest +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +class AlcoholRepositoryTest { + @Autowired + AlcoholTypeRepository alcoholTypeRepository; + + @Autowired + AlcoholRepository alcoholRepository; + + @PersistenceContext + private EntityManager em; + + @Test + void findByAlcoholType() { + //given 술타입이 3종류 있다. + // 그리고 술은 한 8개 있음. + // 그중에 3개 정도가 내가 조회하려는 타입임. + //when 술타입으로 조회하면 + //then 3개가 조회됨. + List alcoholTypeList = dataInitAlcoholType(); + List alcoholList = dataInitAlcohol(alcoholTypeList); + + // when. + Page byAlcoholType = + alcoholRepository.searchAlcoholPage(AlcoholSearchCondition.builder() + .alcoholType( + alcoholTypeList.get( + 0).getId()) + .build(), + PageRequest.of(0, 10)); + + // then. + List content = byAlcoholType.getContent(); + content.forEach(System.out::println); + Assertions.assertThat(content.size()).isEqualTo(4); + + + } + + private List dataInitAlcohol(List alcoholTypeList) { + List alcoholList = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + // 술 10개 만들기 + // alcoholTypeList 기준. + // 0idx : 4 + // 1idx : 3 + // 2idx : 3 + alcoholList.add( + Alcohol.builder().name("술" + i).description("설명이다" + i) + .alcoholType(alcoholTypeList.get(i % 3)).build()); + } + alcoholRepository.saveAll(alcoholList); + em.flush(); + em.clear(); + return alcoholList; + } + + private List dataInitAlcoholType() { + List alcoholTypeList = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + // 알코올 타입 3개 만들기 + alcoholTypeList.add( + AlcoholType.builder().name("맥주" + i).description("설명이다" + i).displayOrder(i + 1L) + .build()); + } + alcoholTypeRepository.saveAll(alcoholTypeList); + em.flush(); + em.clear(); + + + return alcoholTypeList; + } + +} \ No newline at end of file diff --git a/server/src/test/java/com/bside/bside_311/repository/PostRepositoryTest.java b/server/src/test/java/com/bside/bside_311/repository/PostRepositoryTest.java new file mode 100644 index 0000000..1558724 --- /dev/null +++ b/server/src/test/java/com/bside/bside_311/repository/PostRepositoryTest.java @@ -0,0 +1,113 @@ +package com.bside.bside_311.repository; + +import com.bside.bside_311.entity.Post; +import com.bside.bside_311.entity.PostLike; +import com.bside.bside_311.entity.User; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.data.domain.Page; + +import java.util.ArrayList; +import java.util.List; + +@DataJpaTest +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +//@Rollback(false) +class PostRepositoryTest { + @Autowired + UserRepository userRepository; + + @Autowired + PostRepository postRepository; + + @Autowired + PostLikeRepository postLikeRepository; + + @PersistenceContext + private EntityManager em; + + @Test + void searchPagePopular() { + //given + // 게시글이 3개 정도 있다. + // 그런데 그 게시글들은 좋아요 수가 아래와 같음. + // 1st idx 게시글 : 좋아요 1개. + // 2st idx 게시글 : 좋아요 3개. + // 3st idx 게시글 : 좋아요 2개. + List inputPosts = dataInitSearchPagePostPopular(); + + + em.flush(); + em.clear(); + + //when + Page posts = postRepository.searchPagePopular(0L, 10L); + + + //then + List content = posts.getContent(); + content.forEach(System.out::println); + Assertions.assertThat(posts.getTotalElements()).isEqualTo(3); + Assertions.assertThat(content.get(0).getId()).isEqualTo(inputPosts.get(1).getId()); + } + + @Test + void searchPagePopularPageTest() { + //given + // 게시글이 3개 정도 있다. + // 그런데 그 게시글들은 좋아요 수가 아래와 같음. + // 1st idx 게시글 : 좋아요 1개. + // 2st idx 게시글 : 좋아요 3개. + // 3st idx 게시글 : 좋아요 2개. + List inputPosts = dataInitSearchPagePostPopular(); + + //when + Page posts = postRepository.searchPagePopular(1L, 2L); + + + //then + List content = posts.getContent(); + content.forEach(System.out::println); + Assertions.assertThat(posts.getTotalElements()).isEqualTo(3); + Assertions.assertThat(content.get(0).getId()).isEqualTo(inputPosts.get(0).getId()); + // 이 뜻은 사이즈 크기가 2인데, 1번째 페이지를 보여달라는 뜻.(0부터 시작.) + // 그러니까 지금 데이터 순서가 (idx 기준) 2, 1, 0 이니까, 0번째 인덱스의 데이터를 가리키는 것이 맞음. + } + + private List dataInitSearchPagePostPopular() { + List userList = new ArrayList<>(); + for (int i = 0; i < 5; i++) { + User test = User.builder().id(i + 1L) + .userId(String.format("test%d", i)) + .nickname(String.format("test%d", i)) + .password("test1!").build(); + userList.add(test); + } + userRepository.saveAllAndFlush(userList); + + List inputPosts = new ArrayList<>(); + Post p1 = Post.builder().content("1st contest hello").build(); + Post p2 = Post.builder().content("2st contest hi").build(); + Post p3 = Post.builder().content("3rd contest goodBye").build(); + inputPosts.add(p1); + inputPosts.add(p2); + inputPosts.add(p3); + postRepository.saveAllAndFlush(inputPosts); + + List postLikeList = new ArrayList<>(); + postLikeList.add(PostLike.of(userList.get(0), p1)); + postLikeList.add(PostLike.of(userList.get(0), p2)); + postLikeList.add(PostLike.of(userList.get(1), p2)); + postLikeList.add(PostLike.of(userList.get(2), p2)); + postLikeList.add(PostLike.of(userList.get(3), p3)); + postLikeList.add(PostLike.of(userList.get(4), p3)); + postLikeRepository.saveAllAndFlush(postLikeList); + return inputPosts; + } + +} \ No newline at end of file diff --git a/server/src/test/java/com/bside/bside_311/repository/UserFollowRepositoryTest.java b/server/src/test/java/com/bside/bside_311/repository/UserFollowRepositoryTest.java index af06d28..1400121 100644 --- a/server/src/test/java/com/bside/bside_311/repository/UserFollowRepositoryTest.java +++ b/server/src/test/java/com/bside/bside_311/repository/UserFollowRepositoryTest.java @@ -3,15 +3,12 @@ import com.bside.bside_311.entity.UserFollow; import com.bside.bside_311.entity.YesOrNo; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; import java.util.List; -@ExtendWith(SpringExtension.class) @DataJpaTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) class UserFollowRepositoryTest { diff --git a/server/src/test/java/com/bside/bside_311/repository/UserRepositoryTest.java b/server/src/test/java/com/bside/bside_311/repository/UserRepositoryTest.java index 5b149ca..2e38c50 100644 --- a/server/src/test/java/com/bside/bside_311/repository/UserRepositoryTest.java +++ b/server/src/test/java/com/bside/bside_311/repository/UserRepositoryTest.java @@ -1,5 +1,6 @@ package com.bside.bside_311.repository; +import com.bside.bside_311.dto.UserIncludeFollowCountDto; import com.bside.bside_311.entity.User; import com.bside.bside_311.entity.UserFollow; import com.bside.bside_311.entity.YesOrNo; @@ -9,18 +10,18 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; -import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.List; import java.util.Optional; -@SpringBootTest -@Transactional +@DataJpaTest +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) //@Rollback(false) class UserRepositoryTest { @Autowired @@ -144,4 +145,63 @@ public void getUsersOfFollowingMePage_success() { Assertions.assertThat(myFollowingUsersPage.getContent().size()).isEqualTo(2); } + @Test + void searchUserPopularTest() { + //given + // 유저가 3명 정도 있다. + // 그런데 그 유저들은 팔로워 수가 아래와 같음. + // 1st idx 유저 : 팔로워 1개. + // 2st idx 유저 : 팔로워 3개. + // 3st idx 유저 : 팔로워 2개. + List inputUsers = dataInitSearchUserPopular(); + + //when + Page users = userRepository.getUsersPopular(0L, 10L); + + //then + List content = users.getContent(); + content.forEach(System.out::println); + Assertions.assertThat(content.get(0).getUserNo()).isEqualTo(inputUsers.get(1).getId()); + } + + @Test + void searchUserPopularPageTest() { + //given + // 유저가 3명 정도 있다. + // 그런데 그 유저들은 팔로워 수가 아래와 같음. + // 0st idx 유저 : 팔로워 1개. + // 1st idx 유저 : 팔로워 3개. + // 2st idx 유저 : 팔로워 2개. + List inputUsers = dataInitSearchUserPopular(); + + //when + Page users = userRepository.getUsersPopular(1L, 2L); + + //then + List content = users.getContent(); + content.forEach(System.out::println); + Assertions.assertThat(content.get(0).getUserNo()).isEqualTo(inputUsers.get(0).getId()); + } + + private List dataInitSearchUserPopular() { + List userList = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + User test = User.builder().id(i + 1L) + .userId(String.format("test%d", i)) + .nickname(String.format("test%d", i)) + .password("test1!").build(); + userList.add(test); + } + userRepository.saveAllAndFlush(userList); + List userFollowList = new ArrayList<>(); + userFollowList.add(UserFollow.of(userList.get(1), userList.get(0))); + userFollowList.add(UserFollow.of(userList.get(2), userList.get(1))); + userFollowList.add(UserFollow.of(userList.get(3), userList.get(1))); + userFollowList.add(UserFollow.of(userList.get(4), userList.get(1))); + userFollowList.add(UserFollow.of(userList.get(5), userList.get(2))); + userFollowList.add(UserFollow.of(userList.get(6), userList.get(2))); + userFollowRepository.saveAllAndFlush(userFollowList); + return userList; + } + } \ No newline at end of file