From e749af6291153bfa948d09df37c12ac137a692f2 Mon Sep 17 00:00:00 2001 From: DH CHOI Date: Fri, 18 Mar 2022 00:52:08 +0900 Subject: [PATCH 1/8] =?UTF-8?q?Feat:=20=ED=95=B4=EC=8B=9C=ED=83=9C?= =?UTF-8?q?=EA=B7=B8=20=ED=8C=94=EB=A1=9C=EC=9A=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/HashtagController.java | 23 ++++++++++ .../Instagram/dto/error/ErrorCode.java | 7 ++- .../Instagram/dto/result/ResultCode.java | 2 + .../entity/member/HashtagFollow.java | 44 +++++++++++++++++++ .../exception/CantFollowHashtagException.java | 9 ++++ .../CantUnfollowHashtagException.java | 9 ++++ .../exception/HashtagNotFoundException.java | 9 ++++ .../repository/HashtagFollowRepository.java | 14 ++++++ .../Instagram/service/HashtagService.java | 41 +++++++++++++++++ 9 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 src/main/java/cloneproject/Instagram/entity/member/HashtagFollow.java create mode 100644 src/main/java/cloneproject/Instagram/exception/CantFollowHashtagException.java create mode 100644 src/main/java/cloneproject/Instagram/exception/CantUnfollowHashtagException.java create mode 100644 src/main/java/cloneproject/Instagram/exception/HashtagNotFoundException.java create mode 100644 src/main/java/cloneproject/Instagram/repository/HashtagFollowRepository.java diff --git a/src/main/java/cloneproject/Instagram/controller/HashtagController.java b/src/main/java/cloneproject/Instagram/controller/HashtagController.java index 800af994..c1769a69 100644 --- a/src/main/java/cloneproject/Instagram/controller/HashtagController.java +++ b/src/main/java/cloneproject/Instagram/controller/HashtagController.java @@ -13,7 +13,9 @@ import org.springframework.data.domain.Page; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -62,4 +64,25 @@ public ResponseEntity getHashtags( return ResponseEntity.ok(ResultResponse.of(GET_HASHTAGS_SUCCESS, response)); } + + @ApiOperation(value = "해시태그 팔로우") + @ApiImplicitParam(name = "hashtag", value = "hashtag", example = "만두", required = true) + @PostMapping("/hashtags/follow") + public ResponseEntity followHashtag( + @NotBlank(message = "hashtag는 필수입니다.") @RequestParam String hashtag) { + + hashtagService.followHashtag(hashtag); + return ResponseEntity.ok(ResultResponse.of(FOLLOW_HASHTAG_SUCCESS, null)); + } + + @ApiOperation(value = "해시태그 언팔로우") + @ApiImplicitParam(name = "hashtag", value = "hashtag", example = "만두", required = true) + @DeleteMapping("/hashtags/follow") + public ResponseEntity unfollowHashtag( + @NotBlank(message = "hashtag는 필수입니다.") @RequestParam String hashtag) { + + hashtagService.unfollowHashtag(hashtag); + return ResponseEntity.ok(ResultResponse.of(UNFOLLOW_HASHTAG_SUCCESS, null)); + } + } diff --git a/src/main/java/cloneproject/Instagram/dto/error/ErrorCode.java b/src/main/java/cloneproject/Instagram/dto/error/ErrorCode.java index ba86192a..22f02fa1 100644 --- a/src/main/java/cloneproject/Instagram/dto/error/ErrorCode.java +++ b/src/main/java/cloneproject/Instagram/dto/error/ErrorCode.java @@ -77,7 +77,12 @@ public enum ErrorCode { MISMATCHED_ALARM_TYPE(400, "A001", "알람 형식이 올바르지 않습니다."), // Email - CANT_SEND_EMAIL(500, "E001", "이메일 전송 중 오류가 발생했습니다.") + CANT_SEND_EMAIL(500, "E001", "이메일 전송 중 오류가 발생했습니다."), + + // HashTag + HASHTAG_NOT_FOUND(400, "H001", "존재하지 않는 해시태그 입니다"), + CANT_FOLLOW_HASHTAG(400, "H002", "해시태그 팔로우 실패"), + CANT_UNFOLLOW_HASHTAG(400, "H003", "해시태그 언팔로우 실패") ; private int status; diff --git a/src/main/java/cloneproject/Instagram/dto/result/ResultCode.java b/src/main/java/cloneproject/Instagram/dto/result/ResultCode.java index de8e43de..38b33ed7 100644 --- a/src/main/java/cloneproject/Instagram/dto/result/ResultCode.java +++ b/src/main/java/cloneproject/Instagram/dto/result/ResultCode.java @@ -89,6 +89,8 @@ public enum ResultCode { // Hashtag GET_HASHTAG_POSTS_SUCCESS(200, "H001", "해시태그 게시물 목록 페이징 조회 성공"), GET_HASHTAGS_SUCCESS(200, "H002", "해시태그 목록 페이징 조회 성공"), + FOLLOW_HASHTAG_SUCCESS(200, "H003", "해시태그 팔로우 성공"), + UNFOLLOW_HASHTAG_SUCCESS(200, "H004", "해시태그 언팔로우 성공"), ; private int status; diff --git a/src/main/java/cloneproject/Instagram/entity/member/HashtagFollow.java b/src/main/java/cloneproject/Instagram/entity/member/HashtagFollow.java new file mode 100644 index 00000000..3eebb981 --- /dev/null +++ b/src/main/java/cloneproject/Instagram/entity/member/HashtagFollow.java @@ -0,0 +1,44 @@ +package cloneproject.Instagram.entity.member; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import cloneproject.Instagram.entity.hashtag.Hashtag; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "hashtag_follows") +public class HashtagFollow { + + @Id + @Column(name = "hashtag_follow_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + private Member member; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "hashtag_id") + private Hashtag hashtag; + + @Builder + public HashtagFollow(Member member, Hashtag hashtag) { + this.member = member; + this.hashtag = hashtag; + } + +} diff --git a/src/main/java/cloneproject/Instagram/exception/CantFollowHashtagException.java b/src/main/java/cloneproject/Instagram/exception/CantFollowHashtagException.java new file mode 100644 index 00000000..e71395e4 --- /dev/null +++ b/src/main/java/cloneproject/Instagram/exception/CantFollowHashtagException.java @@ -0,0 +1,9 @@ +package cloneproject.Instagram.exception; + +import cloneproject.Instagram.dto.error.ErrorCode; + +public class CantFollowHashtagException extends BusinessException{ + public CantFollowHashtagException(){ + super(ErrorCode.CANT_FOLLOW_HASHTAG); + } +} \ No newline at end of file diff --git a/src/main/java/cloneproject/Instagram/exception/CantUnfollowHashtagException.java b/src/main/java/cloneproject/Instagram/exception/CantUnfollowHashtagException.java new file mode 100644 index 00000000..238e0047 --- /dev/null +++ b/src/main/java/cloneproject/Instagram/exception/CantUnfollowHashtagException.java @@ -0,0 +1,9 @@ +package cloneproject.Instagram.exception; + +import cloneproject.Instagram.dto.error.ErrorCode; + +public class CantUnfollowHashtagException extends BusinessException{ + public CantUnfollowHashtagException(){ + super(ErrorCode.CANT_UNFOLLOW_HASHTAG); + } +} diff --git a/src/main/java/cloneproject/Instagram/exception/HashtagNotFoundException.java b/src/main/java/cloneproject/Instagram/exception/HashtagNotFoundException.java new file mode 100644 index 00000000..efa24d09 --- /dev/null +++ b/src/main/java/cloneproject/Instagram/exception/HashtagNotFoundException.java @@ -0,0 +1,9 @@ +package cloneproject.Instagram.exception; + +import cloneproject.Instagram.dto.error.ErrorCode; + +public class HashtagNotFoundException extends BusinessException{ + public HashtagNotFoundException(){ + super(ErrorCode.HASHTAG_NOT_FOUND); + } +} \ No newline at end of file diff --git a/src/main/java/cloneproject/Instagram/repository/HashtagFollowRepository.java b/src/main/java/cloneproject/Instagram/repository/HashtagFollowRepository.java new file mode 100644 index 00000000..3901a8f9 --- /dev/null +++ b/src/main/java/cloneproject/Instagram/repository/HashtagFollowRepository.java @@ -0,0 +1,14 @@ +package cloneproject.Instagram.repository; + +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; + +import cloneproject.Instagram.entity.member.HashtagFollow; + +public interface HashtagFollowRepository extends JpaRepository{ + + boolean existsByMemberIdAndHashtagId(Long memberId, Long hashtagId); + Optional findByMemberIdAndHashtagId(Long memberId, Long hashtagId); + +} diff --git a/src/main/java/cloneproject/Instagram/service/HashtagService.java b/src/main/java/cloneproject/Instagram/service/HashtagService.java index 705de184..6ef995d2 100644 --- a/src/main/java/cloneproject/Instagram/service/HashtagService.java +++ b/src/main/java/cloneproject/Instagram/service/HashtagService.java @@ -3,8 +3,13 @@ import cloneproject.Instagram.dto.hashtag.HashtagDTO; import cloneproject.Instagram.dto.post.PostDTO; import cloneproject.Instagram.entity.hashtag.Hashtag; +import cloneproject.Instagram.entity.member.HashtagFollow; import cloneproject.Instagram.entity.member.Member; +import cloneproject.Instagram.exception.CantFollowHashtagException; +import cloneproject.Instagram.exception.CantUnfollowHashtagException; +import cloneproject.Instagram.exception.HashtagNotFoundException; import cloneproject.Instagram.exception.MemberDoesNotExistException; +import cloneproject.Instagram.repository.HashtagFollowRepository; import cloneproject.Instagram.repository.HashtagRepository; import cloneproject.Instagram.repository.MemberRepository; import cloneproject.Instagram.repository.post.PostRepository; @@ -28,6 +33,7 @@ public class HashtagService { private final PostRepository postRepository; private final MemberRepository memberRepository; private final HashtagRepository hashtagRepository; + private final HashtagFollowRepository hashtagFollowRepository; public Page getHashTagPosts(int page, int size, String name) { page = (page == 0 ? 0 : page - 1); @@ -46,4 +52,39 @@ public Page getHashTagsLikeName(int page, int size, String name) { final Pageable pageable = PageRequest.of(page, size); return hashtagRepository.findHashtagDtoPageLikeName(pageable, name); } + + @Transactional + public void followHashtag(String hashtagName){ + String memberId = SecurityContextHolder.getContext().getAuthentication().getName(); + Hashtag hashtag = hashtagRepository.findByName(hashtagName) + .orElseThrow(HashtagNotFoundException::new); + Member member = memberRepository.findById(Long.valueOf(memberId)) + .orElseThrow(MemberDoesNotExistException::new); + + if(hashtagFollowRepository.existsByMemberIdAndHashtagId(member.getId(), hashtag.getId())){ + throw new CantFollowHashtagException(); + } + + HashtagFollow hashtagFollow = HashtagFollow.builder() + .member(member) + .hashtag(hashtag) + .build(); + + hashtagFollowRepository.save(hashtagFollow); + } + + @Transactional + public void unfollowHashtag(String hashtagName){ + String memberId = SecurityContextHolder.getContext().getAuthentication().getName(); + Hashtag hashtag = hashtagRepository.findByName(hashtagName) + .orElseThrow(HashtagNotFoundException::new); + Member member = memberRepository.findById(Long.valueOf(memberId)) + .orElseThrow(MemberDoesNotExistException::new); + + HashtagFollow hashtagFollow = hashtagFollowRepository.findByMemberIdAndHashtagId(member.getId(), hashtag.getId()) + .orElseThrow(CantUnfollowHashtagException::new); + + hashtagFollowRepository.delete(hashtagFollow); + } + } From 08b7683394e1f22305bd1731d5328c2635b13e2a Mon Sep 17 00:00:00 2001 From: DH CHOI Date: Sun, 20 Mar 2022 15:26:36 +0900 Subject: [PATCH 2/8] =?UTF-8?q?Fix:=20=EA=B8=B0=EC=A1=B4=EC=9D=98=20?= =?UTF-8?q?=EC=9C=A0=EC=A0=80=20=EA=B2=80=EC=83=89=20API=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/MemberController.java | 16 ----- .../dto/member/SearchedMemberDTO.java | 37 ----------- .../repository/MemberRepositoryQuerydsl.java | 2 - .../MemberRepositoryQuerydslImpl.java | 64 ------------------- .../Instagram/service/MemberService.java | 8 --- 5 files changed, 127 deletions(-) delete mode 100644 src/main/java/cloneproject/Instagram/dto/member/SearchedMemberDTO.java diff --git a/src/main/java/cloneproject/Instagram/controller/MemberController.java b/src/main/java/cloneproject/Instagram/controller/MemberController.java index b9c98d23..2bec35ae 100644 --- a/src/main/java/cloneproject/Instagram/controller/MemberController.java +++ b/src/main/java/cloneproject/Instagram/controller/MemberController.java @@ -7,11 +7,6 @@ import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; -import java.util.List; - -import javax.validation.constraints.NotBlank; - -import org.hibernate.validator.constraints.Length; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; @@ -22,7 +17,6 @@ import cloneproject.Instagram.dto.member.EditProfileResponse; import cloneproject.Instagram.dto.member.MenuMemberDTO; import cloneproject.Instagram.dto.member.MiniProfileResponse; -import cloneproject.Instagram.dto.member.SearchedMemberDTO; import cloneproject.Instagram.dto.member.UserProfileResponse; import cloneproject.Instagram.dto.result.ResultCode; import cloneproject.Instagram.dto.result.ResultResponse; @@ -117,14 +111,4 @@ public ResponseEntity editProfile(@Validated @RequestBody EditPr return new ResponseEntity<>(result, HttpStatus.valueOf(result.getStatus())); } - @ApiOperation(value = "멤버 검색") - @ApiImplicitParam(name = "text", value = "검색내용", required = true, example = "dlwl") - @GetMapping(value = "/search") - public ResponseEntity searchMember(@RequestParam String text) { - List memberInfos = memberService.searchMember(text); - - ResultResponse result = ResultResponse.of(ResultCode.SEARCH_MEMBER_SUCCESS, memberInfos); - return new ResponseEntity<>(result, HttpStatus.valueOf(result.getStatus())); - } - } diff --git a/src/main/java/cloneproject/Instagram/dto/member/SearchedMemberDTO.java b/src/main/java/cloneproject/Instagram/dto/member/SearchedMemberDTO.java deleted file mode 100644 index 0ca6203a..00000000 --- a/src/main/java/cloneproject/Instagram/dto/member/SearchedMemberDTO.java +++ /dev/null @@ -1,37 +0,0 @@ -package cloneproject.Instagram.dto.member; - -import java.util.List; - -import com.querydsl.core.annotations.QueryProjection; - -import cloneproject.Instagram.vo.Image; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -public class SearchedMemberDTO { - - private String username; - private String name; - private Image image; - private boolean isFollowing; - private boolean isFollower; - private boolean hasStory; - private List followingMemberFollow; // 내 팔로잉 중 해당 멤버를 팔로우 하고있는 사람 - - @QueryProjection - public SearchedMemberDTO(String username, String name, Image image, boolean isFollowing, boolean isFollower) { - this.username = username; - this.name = name; - this.image = image; - this.isFollowing = isFollowing; - this.isFollower = isFollower; - this.hasStory = false; - } - - public void setFollowingMemberFollow(List followingMemberFollow) { - this.followingMemberFollow = followingMemberFollow; - } -} - diff --git a/src/main/java/cloneproject/Instagram/repository/MemberRepositoryQuerydsl.java b/src/main/java/cloneproject/Instagram/repository/MemberRepositoryQuerydsl.java index 1e29351b..710dc976 100644 --- a/src/main/java/cloneproject/Instagram/repository/MemberRepositoryQuerydsl.java +++ b/src/main/java/cloneproject/Instagram/repository/MemberRepositoryQuerydsl.java @@ -4,7 +4,6 @@ import java.util.List; import cloneproject.Instagram.dto.member.MiniProfileResponse; -import cloneproject.Instagram.dto.member.SearchedMemberDTO; import cloneproject.Instagram.dto.member.UserProfileResponse; import cloneproject.Instagram.entity.member.Member; @@ -12,7 +11,6 @@ public interface MemberRepositoryQuerydsl { UserProfileResponse getUserProfile(Long loginedUserId, String username); MiniProfileResponse getMiniProfile(Long loginedUserId, String username); - List searchMember(Long loginedUserId, String text); List findAllByUsernames(List usernames); } diff --git a/src/main/java/cloneproject/Instagram/repository/MemberRepositoryQuerydslImpl.java b/src/main/java/cloneproject/Instagram/repository/MemberRepositoryQuerydslImpl.java index 0e040cd5..b41ec9ba 100644 --- a/src/main/java/cloneproject/Instagram/repository/MemberRepositoryQuerydslImpl.java +++ b/src/main/java/cloneproject/Instagram/repository/MemberRepositoryQuerydslImpl.java @@ -178,70 +178,6 @@ public MiniProfileResponse getMiniProfile(Long loginedUserId, String username) { } - @Override - public List searchMember(Long loginedUserId, String text) { - final List result = queryFactory - .select(new QSearchedMemberDTO( - member.username, - member.name, - member.image, - JPAExpressions - .selectFrom(follow) - .where(follow.member.id.eq(loginedUserId).and(follow.followMember.username.eq(member.username))) - .exists(), - JPAExpressions - .selectFrom(follow) - .where(follow.member.username.eq(member.username).and(follow.followMember.id.eq(loginedUserId))) - .exists() - )) - .from(member) - .where(member.username.contains(text).or(member.name.contains(text)) - .and(member.id.notIn(JPAExpressions - .select(block.blockMember.id) - .from(block) - .where(block.member.id.eq(loginedUserId))) - .and(member.id.notIn(JPAExpressions - .select(block.member.id) - .from(block) - .where(block.blockMember.id.eq(loginedUserId)))))) - .fetch(); - - final List resultUsernames = result.stream().map(SearchedMemberDTO::getUsername) - .collect(Collectors.toList()); - - final Map memberIdMap = queryFactory - .from(member) - .where(member.username.in(resultUsernames)) - .transform(groupBy(member.username).as(member.id)); - result.forEach(member -> { - member.setHasStory(memberStoryRedisRepository.findById(memberIdMap.get(member.getUsername())).isPresent()); - }); - - final List follows = queryFactory - .select(new QFollowDTO( - follow.member.username, - follow.followMember.username - )) - .from(follow) - .where(follow.followMember.username.in(resultUsernames) - .and(follow.member.id.in( - JPAExpressions - .select(follow.followMember.id) - .from(follow) - .where(follow.member.id.eq(loginedUserId)) - ))) - .fetch(); - - if (follows.isEmpty()) - return result; - - final Map> followsMap = follows.stream() - .collect(Collectors.groupingBy(FollowDTO::getFollowMemberUsername)); - result.forEach(r -> r.setFollowingMemberFollow(followsMap.get(r.getUsername()))); - - return result; - } - @Override public List findAllByUsernames(List usernames) { return queryFactory diff --git a/src/main/java/cloneproject/Instagram/service/MemberService.java b/src/main/java/cloneproject/Instagram/service/MemberService.java index 4459639d..58fbcb83 100644 --- a/src/main/java/cloneproject/Instagram/service/MemberService.java +++ b/src/main/java/cloneproject/Instagram/service/MemberService.java @@ -1,7 +1,5 @@ package cloneproject.Instagram.service; -import java.util.List; - import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -132,10 +130,4 @@ public void editProfile(EditProfileRequest editProfileRequest){ memberRepository.save(member); } - public List searchMember(String text){ - final String memberId = SecurityContextHolder.getContext().getAuthentication().getName(); - List result = memberRepository.searchMember(Long.valueOf(memberId), text); - return result; - } - } From ebc99b9b22ebc08c006a3920c098c5010d6c9949 Mon Sep 17 00:00:00 2001 From: DH CHOI Date: Sun, 20 Mar 2022 15:26:52 +0900 Subject: [PATCH 3/8] =?UTF-8?q?Feat:=20=EC=9C=A0=EC=A0=80,=20=ED=95=B4?= =?UTF-8?q?=EC=8B=9C=ED=83=9C=EA=B7=B8=20=EA=B2=80=EC=83=89=20API=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/SearchController.java | 62 +++++ .../Instagram/dto/hashtag/HashtagDTO.java | 3 + .../Instagram/dto/result/ResultCode.java | 4 + .../Instagram/dto/search/SearchDTO.java | 22 ++ .../dto/search/SearchHashtagDTO.java | 26 ++ .../Instagram/dto/search/SearchMemberDTO.java | 37 +++ .../Instagram/entity/search/Search.java | 38 +++ .../entity/search/SearchHashtag.java | 31 +++ .../Instagram/entity/search/SearchMember.java | 31 +++ .../search/SearchHashtagRepository.java | 13 + .../search/SearchMemberRepository.java | 13 + .../repository/search/SearchRepository.java | 9 + .../search/SearchRepositoryQuerydsl.java | 12 + .../search/SearchRepositoryQuerydslImpl.java | 263 ++++++++++++++++++ .../Instagram/service/MemberAuthService.java | 7 + .../Instagram/service/SearchService.java | 56 ++++ 16 files changed, 627 insertions(+) create mode 100644 src/main/java/cloneproject/Instagram/controller/SearchController.java create mode 100644 src/main/java/cloneproject/Instagram/dto/search/SearchDTO.java create mode 100644 src/main/java/cloneproject/Instagram/dto/search/SearchHashtagDTO.java create mode 100644 src/main/java/cloneproject/Instagram/dto/search/SearchMemberDTO.java create mode 100644 src/main/java/cloneproject/Instagram/entity/search/Search.java create mode 100644 src/main/java/cloneproject/Instagram/entity/search/SearchHashtag.java create mode 100644 src/main/java/cloneproject/Instagram/entity/search/SearchMember.java create mode 100644 src/main/java/cloneproject/Instagram/repository/search/SearchHashtagRepository.java create mode 100644 src/main/java/cloneproject/Instagram/repository/search/SearchMemberRepository.java create mode 100644 src/main/java/cloneproject/Instagram/repository/search/SearchRepository.java create mode 100644 src/main/java/cloneproject/Instagram/repository/search/SearchRepositoryQuerydsl.java create mode 100644 src/main/java/cloneproject/Instagram/repository/search/SearchRepositoryQuerydslImpl.java create mode 100644 src/main/java/cloneproject/Instagram/service/SearchService.java diff --git a/src/main/java/cloneproject/Instagram/controller/SearchController.java b/src/main/java/cloneproject/Instagram/controller/SearchController.java new file mode 100644 index 00000000..9ddbd4e2 --- /dev/null +++ b/src/main/java/cloneproject/Instagram/controller/SearchController.java @@ -0,0 +1,62 @@ +package cloneproject.Instagram.controller; + +import java.util.List; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import cloneproject.Instagram.dto.result.ResultCode; +import cloneproject.Instagram.dto.result.ResultResponse; +import cloneproject.Instagram.dto.search.SearchDTO; +import cloneproject.Instagram.service.SearchService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Validated +@Api(tags = "검색 API") +@RestController +@RequiredArgsConstructor +public class SearchController { + + private final SearchService searchService; + + @ApiOperation(value = "검색") + @ApiImplicitParam(name = "text", value = "검색내용", required = true, example = "dlwl") + @GetMapping(value = "/topsearch") + public ResponseEntity searchText(@RequestParam String text) { + List searchDTOs = searchService.searchByText(text); + + ResultResponse result = ResultResponse.of(ResultCode.SEARCH_SUCCESS, searchDTOs); + return new ResponseEntity<>(result, HttpStatus.valueOf(result.getStatus())); + } + + @ApiOperation(value = "유저 검색 조회수 증가") + @ApiImplicitParam(name = "username", value = "조회수 증가시킬 username", required = true, example = "dlwlrma") + @PostMapping(value = "/topsearch/member/upcount") + public ResponseEntity increaseSearchMemberCount(@RequestParam String username) { + searchService.increaseSearchMemberCount(username); + + ResultResponse result = ResultResponse.of(ResultCode.INCREASE_SEARCH_COUNT_SUCCESS, null); + return new ResponseEntity<>(result, HttpStatus.valueOf(result.getStatus())); + } + + @ApiOperation(value = "해시태그 검색 조회수 증가") + @ApiImplicitParam(name = "name", value = "조회수 증가시킬 hashtag", required = true, example = "만두") + @PostMapping(value = "/topsearch/hashtag/upcount") + public ResponseEntity increaseSearchHashtagCount(@RequestParam String name) { + searchService.increaseSearchHashtagCount(name); + + ResultResponse result = ResultResponse.of(ResultCode.INCREASE_SEARCH_COUNT_SUCCESS, null); + return new ResponseEntity<>(result, HttpStatus.valueOf(result.getStatus())); + } + +} diff --git a/src/main/java/cloneproject/Instagram/dto/hashtag/HashtagDTO.java b/src/main/java/cloneproject/Instagram/dto/hashtag/HashtagDTO.java index 2b48c303..40624a4b 100644 --- a/src/main/java/cloneproject/Instagram/dto/hashtag/HashtagDTO.java +++ b/src/main/java/cloneproject/Instagram/dto/hashtag/HashtagDTO.java @@ -1,5 +1,7 @@ package cloneproject.Instagram.dto.hashtag; +import com.querydsl.core.annotations.QueryProjection; + import cloneproject.Instagram.entity.hashtag.Hashtag; import lombok.Getter; import lombok.NoArgsConstructor; @@ -11,6 +13,7 @@ public class HashtagDTO { private String name; private Integer count; + @QueryProjection public HashtagDTO(Hashtag hashtag) { this.name = hashtag.getName(); this.count = hashtag.getCount(); diff --git a/src/main/java/cloneproject/Instagram/dto/result/ResultCode.java b/src/main/java/cloneproject/Instagram/dto/result/ResultCode.java index 469cd975..ae806b29 100644 --- a/src/main/java/cloneproject/Instagram/dto/result/ResultCode.java +++ b/src/main/java/cloneproject/Instagram/dto/result/ResultCode.java @@ -94,6 +94,10 @@ public enum ResultCode { // Story CREATE_STORY_SUCCESS(200, "S001", "스토리 업로드 성공"), + + // Search + SEARCH_SUCCESS(200, "SE001", "검색 성공"), + INCREASE_SEARCH_COUNT_SUCCESS(200, "SE002", "검색 조회수 증가 성공"), ; private int status; diff --git a/src/main/java/cloneproject/Instagram/dto/search/SearchDTO.java b/src/main/java/cloneproject/Instagram/dto/search/SearchDTO.java new file mode 100644 index 00000000..6ba6ee9d --- /dev/null +++ b/src/main/java/cloneproject/Instagram/dto/search/SearchDTO.java @@ -0,0 +1,22 @@ +package cloneproject.Instagram.dto.search; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PROTECTED) +public class SearchDTO { + + private String dtype; + + @JsonIgnore + private Long count; + +} diff --git a/src/main/java/cloneproject/Instagram/dto/search/SearchHashtagDTO.java b/src/main/java/cloneproject/Instagram/dto/search/SearchHashtagDTO.java new file mode 100644 index 00000000..8eef22c3 --- /dev/null +++ b/src/main/java/cloneproject/Instagram/dto/search/SearchHashtagDTO.java @@ -0,0 +1,26 @@ +package cloneproject.Instagram.dto.search; + +import com.querydsl.core.annotations.QueryProjection; + +import cloneproject.Instagram.entity.hashtag.Hashtag; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class SearchHashtagDTO extends SearchDTO{ + + private String name; + private Integer postCount; + + @QueryProjection + public SearchHashtagDTO(String dtype, Long count, Hashtag hashtag){ + super(dtype, count); + this.name = hashtag.getName(); + this.postCount = hashtag.getCount(); + } + +} \ No newline at end of file diff --git a/src/main/java/cloneproject/Instagram/dto/search/SearchMemberDTO.java b/src/main/java/cloneproject/Instagram/dto/search/SearchMemberDTO.java new file mode 100644 index 00000000..09639b61 --- /dev/null +++ b/src/main/java/cloneproject/Instagram/dto/search/SearchMemberDTO.java @@ -0,0 +1,37 @@ +package cloneproject.Instagram.dto.search; + +import java.util.List; + +import com.querydsl.core.annotations.QueryProjection; + +import cloneproject.Instagram.dto.member.FollowDTO; +import cloneproject.Instagram.dto.member.MemberDTO; +import cloneproject.Instagram.entity.member.Member; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class SearchMemberDTO extends SearchDTO{ + + private MemberDTO memberDTO; + private boolean isFollowing; + private boolean isFollower; + private List followingMemberFollow; + + @QueryProjection + public SearchMemberDTO(String dtype, Long count, Member member, boolean isFollowing, boolean isFollower){ + super(dtype, count); + this.memberDTO = new MemberDTO(member); + this.isFollowing = isFollowing; + this.isFollower = isFollower; + // this.followingMemberFollow = followingMemberFollow; + } + public void setFollowingMemberFollow(List followingMemberFollow) { + this.followingMemberFollow = followingMemberFollow; + } + +} \ No newline at end of file diff --git a/src/main/java/cloneproject/Instagram/entity/search/Search.java b/src/main/java/cloneproject/Instagram/entity/search/Search.java new file mode 100644 index 00000000..d210ad5a --- /dev/null +++ b/src/main/java/cloneproject/Instagram/entity/search/Search.java @@ -0,0 +1,38 @@ +package cloneproject.Instagram.entity.search; + +import lombok.Getter; + +import javax.persistence.*; + +@Getter +@Entity +@Inheritance(strategy = InheritanceType.JOINED) +@DiscriminatorColumn +@Table(name = "searches") +public class Search { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "search_id") + private Long id; + + @Column(name = "search_count") + private Long count; + + @Column(insertable = false, updatable = false) + private String dtype; + + protected Search(){ + this.count = 0L; + } + + public void upCount(){ + this.count++; + } + + @Transient + public void setDtype() { + this.dtype = getClass().getAnnotation(DiscriminatorValue.class).value(); + } + +} diff --git a/src/main/java/cloneproject/Instagram/entity/search/SearchHashtag.java b/src/main/java/cloneproject/Instagram/entity/search/SearchHashtag.java new file mode 100644 index 00000000..f3c0af20 --- /dev/null +++ b/src/main/java/cloneproject/Instagram/entity/search/SearchHashtag.java @@ -0,0 +1,31 @@ +package cloneproject.Instagram.entity.search; + +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.OneToOne; +import javax.persistence.Table; + +import cloneproject.Instagram.entity.hashtag.Hashtag; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@DiscriminatorValue("HASHTAG") +@Table(name = "search_hashtags") +public class SearchHashtag extends Search{ + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "hashtag_id") + private Hashtag hashtag; + + public SearchHashtag(Hashtag hashtag) { + super(); + this.hashtag = hashtag; + } + +} diff --git a/src/main/java/cloneproject/Instagram/entity/search/SearchMember.java b/src/main/java/cloneproject/Instagram/entity/search/SearchMember.java new file mode 100644 index 00000000..07ebed8d --- /dev/null +++ b/src/main/java/cloneproject/Instagram/entity/search/SearchMember.java @@ -0,0 +1,31 @@ +package cloneproject.Instagram.entity.search; + +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.OneToOne; +import javax.persistence.Table; + +import cloneproject.Instagram.entity.member.Member; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@DiscriminatorValue("MEMBER") +@Table(name = "search_members") +public class SearchMember extends Search{ + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + private Member member; + + public SearchMember(Member member) { + super(); + this.member = member; + } + +} diff --git a/src/main/java/cloneproject/Instagram/repository/search/SearchHashtagRepository.java b/src/main/java/cloneproject/Instagram/repository/search/SearchHashtagRepository.java new file mode 100644 index 00000000..401221d0 --- /dev/null +++ b/src/main/java/cloneproject/Instagram/repository/search/SearchHashtagRepository.java @@ -0,0 +1,13 @@ +package cloneproject.Instagram.repository.search; + +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; + +import cloneproject.Instagram.entity.search.SearchHashtag; + +public interface SearchHashtagRepository extends JpaRepository{ + + Optional findByHashtagName(String name); + +} diff --git a/src/main/java/cloneproject/Instagram/repository/search/SearchMemberRepository.java b/src/main/java/cloneproject/Instagram/repository/search/SearchMemberRepository.java new file mode 100644 index 00000000..f0c9ba75 --- /dev/null +++ b/src/main/java/cloneproject/Instagram/repository/search/SearchMemberRepository.java @@ -0,0 +1,13 @@ +package cloneproject.Instagram.repository.search; + +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; + +import cloneproject.Instagram.entity.search.SearchMember; + +public interface SearchMemberRepository extends JpaRepository{ + + Optional findByMemberUsername(String username); + +} diff --git a/src/main/java/cloneproject/Instagram/repository/search/SearchRepository.java b/src/main/java/cloneproject/Instagram/repository/search/SearchRepository.java new file mode 100644 index 00000000..d1aff165 --- /dev/null +++ b/src/main/java/cloneproject/Instagram/repository/search/SearchRepository.java @@ -0,0 +1,9 @@ +package cloneproject.Instagram.repository.search; + +import org.springframework.data.jpa.repository.JpaRepository; + +import cloneproject.Instagram.entity.search.Search; + +public interface SearchRepository extends JpaRepository, SearchRepositoryQuerydsl{ + +} diff --git a/src/main/java/cloneproject/Instagram/repository/search/SearchRepositoryQuerydsl.java b/src/main/java/cloneproject/Instagram/repository/search/SearchRepositoryQuerydsl.java new file mode 100644 index 00000000..8fb214a1 --- /dev/null +++ b/src/main/java/cloneproject/Instagram/repository/search/SearchRepositoryQuerydsl.java @@ -0,0 +1,12 @@ +package cloneproject.Instagram.repository.search; + +import java.util.List; + +import cloneproject.Instagram.dto.search.SearchDTO; + +public interface SearchRepositoryQuerydsl { + + List searchByText(Long loginedId, String text); + List searchByTextOnlyHashtag(Long loginedId, String text); + +} diff --git a/src/main/java/cloneproject/Instagram/repository/search/SearchRepositoryQuerydslImpl.java b/src/main/java/cloneproject/Instagram/repository/search/SearchRepositoryQuerydslImpl.java new file mode 100644 index 00000000..4ff63de4 --- /dev/null +++ b/src/main/java/cloneproject/Instagram/repository/search/SearchRepositoryQuerydslImpl.java @@ -0,0 +1,263 @@ +package cloneproject.Instagram.repository.search; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.querydsl.core.group.GroupBy; +import com.querydsl.jpa.JPAExpressions; +import com.querydsl.jpa.impl.JPAQueryFactory; + +import cloneproject.Instagram.dto.member.FollowDTO; +import cloneproject.Instagram.dto.member.QFollowDTO; +import cloneproject.Instagram.dto.search.QSearchHashtagDTO; +import cloneproject.Instagram.dto.search.QSearchMemberDTO; +import cloneproject.Instagram.dto.search.SearchDTO; +import cloneproject.Instagram.dto.search.SearchHashtagDTO; +import cloneproject.Instagram.dto.search.SearchMemberDTO; +import cloneproject.Instagram.entity.search.Search; +import cloneproject.Instagram.repository.story.MemberStoryRedisRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import static cloneproject.Instagram.entity.member.QMember.member; +import static cloneproject.Instagram.entity.hashtag.QHashtag.hashtag; +import static cloneproject.Instagram.entity.search.QSearch.search; +import static cloneproject.Instagram.entity.search.QSearchMember.searchMember; +import static cloneproject.Instagram.entity.search.QSearchHashtag.searchHashtag; +import static cloneproject.Instagram.entity.member.QFollow.follow; + +@Slf4j +@RequiredArgsConstructor +public class SearchRepositoryQuerydslImpl implements SearchRepositoryQuerydsl{ + + private final JPAQueryFactory queryFactory; + private final MemberStoryRedisRepository memberStoryRedisRepository; + + @Override + public List searchByText(Long loginedId, String text){ + + String keyword = text + "%"; + + List searches = queryFactory + .select(search) + .from(search) + .where(search.id.in( + JPAExpressions + .select(searchMember.id) + .from(searchMember) + .innerJoin(searchMember.member, member) + .where(searchMember.member.username.like(keyword) + .or(searchMember.member.name.like(keyword))) + ).or(search.id.in( + JPAExpressions + .select(searchHashtag.id) + .from(searchHashtag) + .innerJoin(searchHashtag.hashtag, hashtag) + .where(searchHashtag.hashtag.name.like(keyword)) + ))) + .orderBy(search.count.desc()) + .limit(50) + .distinct() + .fetch(); + + final List searchIds = searches.stream() + .map(Search::getId) + .collect(Collectors.toList()); + + Map memberMap = queryFactory + .from(searchMember) + .innerJoin(searchMember.member, member) + .where(searchMember.id.in(searchIds)) + .transform(GroupBy.groupBy(searchMember.id).as(new QSearchMemberDTO( + searchMember._super.dtype, + searchMember._super.count, + searchMember.member, + JPAExpressions + .selectFrom(follow) + .where(follow.member.id.eq(loginedId).and(follow.followMember.id.eq(searchMember.member.id))) + .exists(), + JPAExpressions + .selectFrom(follow) + .where(follow.member.id.eq(searchMember.member.id).and(follow.followMember.id.eq(loginedId))) + .exists() + ) + ) + ); + + // follow 주입 + final List resultUsernames = memberMap.values().stream().map(s -> s.getMemberDTO().getUsername()) + .collect(Collectors.toList()); + + // TODO 우선 이전의 search에 있던 코드 그대로 넣었는데 개선 필요해보임 ! + memberMap.forEach((id, member) -> { + member.getMemberDTO().setHasStory(memberStoryRedisRepository.findById(id).isPresent()); + }); + + final List follows = queryFactory + .select(new QFollowDTO( + follow.member.username, + follow.followMember.username + )) + .from(follow) + .where(follow.followMember.username.in(resultUsernames) + .and(follow.member.id.in( + JPAExpressions + .select(follow.followMember.id) + .from(follow) + .where(follow.member.id.eq(loginedId)) + ))) + .fetch(); + + final Map> followsMap = follows.stream() + .collect(Collectors.groupingBy(FollowDTO::getFollowMemberUsername)); + memberMap.forEach((id, member) -> member.setFollowingMemberFollow(followsMap.get(member.getMemberDTO().getUsername()))); + + // 해시태그 + Map hashtagMap = queryFactory + .from(searchHashtag) + .innerJoin(searchHashtag.hashtag, hashtag) + .where(searchHashtag.id.in(searchIds)) + .transform(GroupBy.groupBy(searchHashtag.id).as(new QSearchHashtagDTO( + searchHashtag.dtype, + searchHashtag.count, + searchHashtag.hashtag + )) + ); + + boolean matchingMemberExists = queryFactory + .from(searchMember) + .innerJoin(searchMember.member, member).fetchJoin() + .where(searchMember.id.in(searchIds).and(searchMember.member.username.eq(text))) + .fetchFirst() != null; + boolean matchingHashtagExists = queryFactory + .from(searchHashtag) + .innerJoin(searchHashtag.hashtag, hashtag).fetchJoin() + .where(searchHashtag.id.in(searchIds).and(searchHashtag.hashtag.name.eq(text))) + .fetchFirst() != null; + + final List searchDTOs = searches.stream() + .map(search -> { + switch (search.getDtype()) { + case "MEMBER": + return memberMap.get(search.getId()); + case "HASHTAG": + return hashtagMap.get(search.getId()); + default: + return null; + } + }) + .collect(Collectors.toList()); + + if(!matchingHashtagExists){ + SearchHashtagDTO searchHashtagDTO = queryFactory + .select(new QSearchHashtagDTO( + searchHashtag.dtype, + searchHashtag.count, + searchHashtag.hashtag + )) + .from(searchHashtag) + .innerJoin(searchHashtag.hashtag, hashtag) + .where(searchHashtag.hashtag.name.eq(text)) + .fetchFirst(); + if(searchHashtagDTO != null) { + searchDTOs.add(0, searchHashtagDTO); + searchDTOs.remove(searchDTOs.size()-1); + } + } + if(!matchingMemberExists){ + SearchMemberDTO searchMemberDTO = queryFactory + .select(new QSearchMemberDTO( + searchMember._super.dtype, + searchMember._super.count, + searchMember.member, + JPAExpressions + .selectFrom(follow) + .where(follow.member.id.eq(loginedId).and(follow.followMember.id.eq(searchMember.member.id))) + .exists(), + JPAExpressions + .selectFrom(follow) + .where(follow.member.id.eq(searchMember.member.id).and(follow.followMember.id.eq(loginedId))) + .exists() + )) + .from(searchMember) + .innerJoin(searchMember.member, member) + .where(searchMember.member.username.eq(text)) + .fetchFirst(); + if(searchMemberDTO != null) { + searchDTOs.add(0, searchMemberDTO); + searchDTOs.remove(searchDTOs.size()-1); + } + } + + return searchDTOs; + } + + + @Override + public List searchByTextOnlyHashtag(Long loginedId, String text){ + String keyword = text + "%"; + + List searches = queryFactory + .select(search) + .from(search) + .where(search.id.in( + JPAExpressions + .select(searchHashtag.id) + .from(searchHashtag) + .innerJoin(searchHashtag.hashtag, hashtag) + .where(searchHashtag.hashtag.name.like(keyword)) + )) + .orderBy(search.count.desc()) + .limit(50) + .distinct() + .fetch(); + + final List searchIds = searches.stream() + .map(Search::getId) + .collect(Collectors.toList()); + + Map hashtagMap = queryFactory + .from(searchHashtag) + .innerJoin(searchHashtag.hashtag, hashtag) + .where(searchHashtag.id.in(searchIds)) + .transform(GroupBy.groupBy(searchHashtag.id).as(new QSearchHashtagDTO( + searchHashtag.dtype, + searchHashtag.count, + searchHashtag.hashtag + )) + ); + + boolean matchingHashtagExists = queryFactory + .from(searchHashtag) + .innerJoin(searchHashtag.hashtag, hashtag).fetchJoin() + .where(searchHashtag.id.in(searchIds).and(searchHashtag.hashtag.name.eq(text))) + .fetchFirst() != null; + + final List searchDTOs = searches.stream() + .map(search -> { + return hashtagMap.get(search.getId()); + + }) + .collect(Collectors.toList()); + + if(!matchingHashtagExists){ + SearchHashtagDTO searchHashtagDTO = queryFactory + .select(new QSearchHashtagDTO( + searchHashtag.dtype, + searchHashtag.count, + searchHashtag.hashtag + )) + .from(searchHashtag) + .innerJoin(searchHashtag.hashtag, hashtag) + .where(searchHashtag.hashtag.name.eq(text)) + .fetchFirst(); + if(searchHashtagDTO != null) { + searchDTOs.add(0, searchHashtagDTO); + searchDTOs.remove(searchDTOs.size()-1); + } + } + + return searchDTOs; + } +} diff --git a/src/main/java/cloneproject/Instagram/service/MemberAuthService.java b/src/main/java/cloneproject/Instagram/service/MemberAuthService.java index d14f9ff8..48ab0a74 100644 --- a/src/main/java/cloneproject/Instagram/service/MemberAuthService.java +++ b/src/main/java/cloneproject/Instagram/service/MemberAuthService.java @@ -21,12 +21,14 @@ import cloneproject.Instagram.dto.member.UpdatePasswordRequest; import cloneproject.Instagram.entity.member.Member; import cloneproject.Instagram.entity.redis.RefreshToken; +import cloneproject.Instagram.entity.search.SearchMember; import cloneproject.Instagram.exception.AccountDoesNotMatchException; import cloneproject.Instagram.exception.CantResetPasswordException; import cloneproject.Instagram.exception.InvalidJwtException; import cloneproject.Instagram.exception.MemberDoesNotExistException; import cloneproject.Instagram.exception.UseridAlreadyExistException; import cloneproject.Instagram.repository.MemberRepository; +import cloneproject.Instagram.repository.search.SearchMemberRepository; import cloneproject.Instagram.util.JwtUtil; import cloneproject.Instagram.vo.GeoIP; import io.jsonwebtoken.JwtException; @@ -44,6 +46,7 @@ public class MemberAuthService { private final MemberRepository memberRepository; private final RefreshTokenService refreshTokenService; private final GeoIPLocationService geoIPLocationService; + private final SearchMemberRepository searchMemberRepository; private final BCryptPasswordEncoder bCryptPasswordEncoder; @@ -71,6 +74,10 @@ public boolean register(RegisterRequest registerRequest){ String encryptedPassword = bCryptPasswordEncoder.encode(member.getPassword()); member.setEncryptedPassword(encryptedPassword); memberRepository.save(member); + + SearchMember searchMember = new SearchMember(member); + searchMemberRepository.save(searchMember); + return true; } diff --git a/src/main/java/cloneproject/Instagram/service/SearchService.java b/src/main/java/cloneproject/Instagram/service/SearchService.java new file mode 100644 index 00000000..4f9779be --- /dev/null +++ b/src/main/java/cloneproject/Instagram/service/SearchService.java @@ -0,0 +1,56 @@ +package cloneproject.Instagram.service; + + +import java.util.List; + +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import cloneproject.Instagram.dto.search.SearchDTO; +import cloneproject.Instagram.entity.search.SearchHashtag; +import cloneproject.Instagram.entity.search.SearchMember; +import cloneproject.Instagram.exception.HashtagNotFoundException; +import cloneproject.Instagram.exception.MemberDoesNotExistException; +import cloneproject.Instagram.repository.search.SearchHashtagRepository; +import cloneproject.Instagram.repository.search.SearchMemberRepository; +import cloneproject.Instagram.repository.search.SearchRepository; +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class SearchService { + + private final SearchRepository searchRepository; + private final SearchMemberRepository searchMemberRepository; + private final SearchHashtagRepository searchHashtagRepository; + + @Transactional(readOnly = true) + public List searchByText(String text){ + final String memberId = SecurityContextHolder.getContext().getAuthentication().getName(); + List result; + if(text.charAt(0) == '#'){ + result = searchRepository.searchByTextOnlyHashtag(Long.valueOf(memberId), text.substring(1)); + }else{ + result = searchRepository.searchByText(Long.valueOf(memberId), text); + } + return result; + } + + @Transactional + public void increaseSearchMemberCount(String username){ + SearchMember searchMember = searchMemberRepository.findByMemberUsername(username) + .orElseThrow(MemberDoesNotExistException::new); + searchMember.upCount(); + searchMemberRepository.save(searchMember); + } + + @Transactional + public void increaseSearchHashtagCount(String name){ + SearchHashtag searchHashtag = searchHashtagRepository.findByHashtagName(name) + .orElseThrow(HashtagNotFoundException::new); + searchHashtag.upCount(); + searchHashtagRepository.save(searchHashtag); + } + +} From 6f129c7b238ecaceab7375d516f28a5fbaaf5544 Mon Sep 17 00:00:00 2001 From: seonpilKim Date: Mon, 21 Mar 2022 00:34:26 +0900 Subject: [PATCH 4/8] =?UTF-8?q?Feat:=20=ED=95=B4=EC=8B=9C=ED=83=9C?= =?UTF-8?q?=EA=B7=B8=20=EC=97=B0=EA=B4=80=20=EA=B2=80=EC=83=89=EC=96=B4=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=ED=8E=98=EC=9D=B4=EC=A7=95=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20API=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolve: #143 --- .../controller/HashtagController.java | 25 +---------- .../Instagram/dto/search/SearchDTO.java | 2 +- .../repository/HashTagRepositoryQuerydsl.java | 10 ----- .../HashTagRepositoryQuerydslImpl.java | 42 ------------------- .../repository/HashtagRepository.java | 2 +- .../Instagram/service/HashtagService.java | 7 ---- 6 files changed, 4 insertions(+), 84 deletions(-) delete mode 100644 src/main/java/cloneproject/Instagram/repository/HashTagRepositoryQuerydsl.java delete mode 100644 src/main/java/cloneproject/Instagram/repository/HashTagRepositoryQuerydslImpl.java diff --git a/src/main/java/cloneproject/Instagram/controller/HashtagController.java b/src/main/java/cloneproject/Instagram/controller/HashtagController.java index c1769a69..cd82950a 100644 --- a/src/main/java/cloneproject/Instagram/controller/HashtagController.java +++ b/src/main/java/cloneproject/Instagram/controller/HashtagController.java @@ -1,6 +1,5 @@ package cloneproject.Instagram.controller; -import cloneproject.Instagram.dto.hashtag.HashtagDTO; import cloneproject.Instagram.dto.post.PostDTO; import cloneproject.Instagram.dto.result.ResultResponse; import cloneproject.Instagram.service.HashtagService; @@ -49,28 +48,10 @@ public ResponseEntity getHashtagPosts( return ResponseEntity.ok(ResultResponse.of(GET_HASHTAG_POSTS_SUCCESS, response)); } - @ApiOperation(value = "해시태그 연관 검색어 목록 페이징 조회") - @ApiImplicitParams({ - @ApiImplicitParam(name = "page", value = "page", example = "1", required = true), - @ApiImplicitParam(name = "size", value = "size", example = "10", required = true), - @ApiImplicitParam(name = "hashtag", value = "hashtag", example = "만두", required = true) - }) - @GetMapping("/hashtags") - public ResponseEntity getHashtags( - @NotNull(message = "page는 필수입니다.") @RequestParam int page, - @NotNull(message = "size는 필수입니다.") @RequestParam int size, - @NotBlank(message = "hashtag는 필수입니다.") @RequestParam String hashtag) { - final Page response = hashtagService.getHashTagsLikeName(page, size, hashtag.substring(1)); - - return ResponseEntity.ok(ResultResponse.of(GET_HASHTAGS_SUCCESS, response)); - } - @ApiOperation(value = "해시태그 팔로우") @ApiImplicitParam(name = "hashtag", value = "hashtag", example = "만두", required = true) @PostMapping("/hashtags/follow") - public ResponseEntity followHashtag( - @NotBlank(message = "hashtag는 필수입니다.") @RequestParam String hashtag) { - + public ResponseEntity followHashtag(@NotBlank(message = "hashtag는 필수입니다.") @RequestParam String hashtag) { hashtagService.followHashtag(hashtag); return ResponseEntity.ok(ResultResponse.of(FOLLOW_HASHTAG_SUCCESS, null)); } @@ -78,9 +59,7 @@ public ResponseEntity followHashtag( @ApiOperation(value = "해시태그 언팔로우") @ApiImplicitParam(name = "hashtag", value = "hashtag", example = "만두", required = true) @DeleteMapping("/hashtags/follow") - public ResponseEntity unfollowHashtag( - @NotBlank(message = "hashtag는 필수입니다.") @RequestParam String hashtag) { - + public ResponseEntity unfollowHashtag(@NotBlank(message = "hashtag는 필수입니다.") @RequestParam String hashtag) { hashtagService.unfollowHashtag(hashtag); return ResponseEntity.ok(ResultResponse.of(UNFOLLOW_HASHTAG_SUCCESS, null)); } diff --git a/src/main/java/cloneproject/Instagram/dto/search/SearchDTO.java b/src/main/java/cloneproject/Instagram/dto/search/SearchDTO.java index 6ba6ee9d..55d7217c 100644 --- a/src/main/java/cloneproject/Instagram/dto/search/SearchDTO.java +++ b/src/main/java/cloneproject/Instagram/dto/search/SearchDTO.java @@ -12,7 +12,7 @@ @Setter @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PROTECTED) -public class SearchDTO { +public abstract class SearchDTO { private String dtype; diff --git a/src/main/java/cloneproject/Instagram/repository/HashTagRepositoryQuerydsl.java b/src/main/java/cloneproject/Instagram/repository/HashTagRepositoryQuerydsl.java deleted file mode 100644 index 457cf8b8..00000000 --- a/src/main/java/cloneproject/Instagram/repository/HashTagRepositoryQuerydsl.java +++ /dev/null @@ -1,10 +0,0 @@ -package cloneproject.Instagram.repository; - -import cloneproject.Instagram.dto.hashtag.HashtagDTO; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; - -public interface HashTagRepositoryQuerydsl { - - Page findHashtagDtoPageLikeName(Pageable pageable, String name); -} diff --git a/src/main/java/cloneproject/Instagram/repository/HashTagRepositoryQuerydslImpl.java b/src/main/java/cloneproject/Instagram/repository/HashTagRepositoryQuerydslImpl.java deleted file mode 100644 index 44b55e04..00000000 --- a/src/main/java/cloneproject/Instagram/repository/HashTagRepositoryQuerydslImpl.java +++ /dev/null @@ -1,42 +0,0 @@ -package cloneproject.Instagram.repository; - -import cloneproject.Instagram.dto.hashtag.HashtagDTO; -import cloneproject.Instagram.entity.hashtag.Hashtag; -import com.querydsl.jpa.impl.JPAQueryFactory; -import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; - -import java.util.List; -import java.util.stream.Collectors; - -import static cloneproject.Instagram.entity.hashtag.QHashtag.hashtag; - -@RequiredArgsConstructor -public class HashTagRepositoryQuerydslImpl implements HashTagRepositoryQuerydsl { - - private final JPAQueryFactory queryFactory; - - @Override - public Page findHashtagDtoPageLikeName(Pageable pageable, String name) { - final List hashtags = queryFactory - .selectFrom(hashtag) - .where(hashtag.name.like(name + "%")) - .orderBy(hashtag.count.desc()) - .limit(pageable.getPageSize()) - .offset(pageable.getOffset()) - .fetch(); - - final long total = queryFactory - .selectFrom(hashtag) - .where(hashtag.name.like(name + "%")) - .fetchCount(); - - final List hashtagDTOs = hashtags.stream() - .map(HashtagDTO::new) - .collect(Collectors.toList()); - - return new PageImpl<>(hashtagDTOs, pageable, total); - } -} diff --git a/src/main/java/cloneproject/Instagram/repository/HashtagRepository.java b/src/main/java/cloneproject/Instagram/repository/HashtagRepository.java index e9e34270..c1de0a30 100644 --- a/src/main/java/cloneproject/Instagram/repository/HashtagRepository.java +++ b/src/main/java/cloneproject/Instagram/repository/HashtagRepository.java @@ -7,7 +7,7 @@ import java.util.Optional; import java.util.Set; -public interface HashtagRepository extends JpaRepository, HashTagRepositoryQuerydsl { +public interface HashtagRepository extends JpaRepository { List findAllByNameIn(Set names); diff --git a/src/main/java/cloneproject/Instagram/service/HashtagService.java b/src/main/java/cloneproject/Instagram/service/HashtagService.java index 6ef995d2..08006512 100644 --- a/src/main/java/cloneproject/Instagram/service/HashtagService.java +++ b/src/main/java/cloneproject/Instagram/service/HashtagService.java @@ -1,6 +1,5 @@ package cloneproject.Instagram.service; -import cloneproject.Instagram.dto.hashtag.HashtagDTO; import cloneproject.Instagram.dto.post.PostDTO; import cloneproject.Instagram.entity.hashtag.Hashtag; import cloneproject.Instagram.entity.member.HashtagFollow; @@ -47,12 +46,6 @@ public Page getHashTagPosts(int page, int size, String name) { return postRepository.findPostDtoPageByHashtag(pageable, member, findHashtag.get()); } - public Page getHashTagsLikeName(int page, int size, String name) { - page = (page == 0 ? 0 : page - 1); - final Pageable pageable = PageRequest.of(page, size); - return hashtagRepository.findHashtagDtoPageLikeName(pageable, name); - } - @Transactional public void followHashtag(String hashtagName){ String memberId = SecurityContextHolder.getContext().getAuthentication().getName(); From 8a091fa78c173ef2a8cc840c86b53aae906e36ca Mon Sep 17 00:00:00 2001 From: seonpilKim Date: Mon, 21 Mar 2022 01:17:56 +0900 Subject: [PATCH 5/8] =?UTF-8?q?Feat:=20=EA=B2=8C=EC=8B=9C=EB=AC=BC/?= =?UTF-8?q?=EB=8C=93=EA=B8=80=20=EC=97=85=EB=A1=9C=EB=93=9C=20or=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20API=20=EB=A1=9C=EC=A7=81=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 게시물/댓글 업로드 API: 해시태그 첫 생성 시, SearchHashtag 엔티티 생성 - 게시물/댓글 삭제 API: 해시태그를 삭제하는 경우, SearchHashtag 엔티티 제거 Resolve: #143 --- .../search/SearchHashtagRepository.java | 7 +++-- .../Instagram/service/PostService.java | 9 ++++-- .../Instagram/service/SearchService.java | 31 +++++++++++++------ 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/main/java/cloneproject/Instagram/repository/search/SearchHashtagRepository.java b/src/main/java/cloneproject/Instagram/repository/search/SearchHashtagRepository.java index 401221d0..b3833861 100644 --- a/src/main/java/cloneproject/Instagram/repository/search/SearchHashtagRepository.java +++ b/src/main/java/cloneproject/Instagram/repository/search/SearchHashtagRepository.java @@ -1,13 +1,16 @@ package cloneproject.Instagram.repository.search; +import java.util.List; import java.util.Optional; +import cloneproject.Instagram.entity.hashtag.Hashtag; import org.springframework.data.jpa.repository.JpaRepository; import cloneproject.Instagram.entity.search.SearchHashtag; -public interface SearchHashtagRepository extends JpaRepository{ - +public interface SearchHashtagRepository extends JpaRepository { + Optional findByHashtagName(String name); + List findAllByHashtagIn(List hashtags); } diff --git a/src/main/java/cloneproject/Instagram/service/PostService.java b/src/main/java/cloneproject/Instagram/service/PostService.java index 0df4a492..e6190536 100644 --- a/src/main/java/cloneproject/Instagram/service/PostService.java +++ b/src/main/java/cloneproject/Instagram/service/PostService.java @@ -76,6 +76,7 @@ public class PostService { private final JoinRoomRepository joinRoomRepository; private final HashtagRepository hashtagRepository; private final HashtagPostRepository hashtagPostRepository; + private final SearchService searchService; public Page getPostDtoPage(int size, int page) { page = (page == 0 ? 0 : page - 1) + 10; @@ -403,13 +404,14 @@ private void registerHashtags(Post post, String content) { .collect(Collectors.toMap(Hashtag::getName, h -> h)); final List newHashtagPost = new ArrayList<>(); names.forEach(name -> { - Hashtag hashtag; + final Hashtag hashtag; if (hashtagMap.containsKey(name)) { hashtag = hashtagMap.get(name); hashtag.upCount(); - } - else + } else { hashtag = hashtagRepository.save(new Hashtag(name)); + searchService.createSearchHashtag(hashtag); + } newHashtagPost.add(new HashtagPost(hashtag, post)); }); hashtagPostRepository.saveAllBatch(newHashtagPost); @@ -429,6 +431,7 @@ private void unregisterHashtags(Post post) { final List hashtagPosts = hashtagPostRepository.findAllByHashtagIn(deleteHashtags); hashtagPostRepository.deleteAllInBatch(hashtagPosts); hashtagRepository.deleteAllInBatch(deleteHashtags); + searchService.deleteSearchHashtags(deleteHashtags); } public Page getCommentDtoPage(Long postId, int page) { diff --git a/src/main/java/cloneproject/Instagram/service/SearchService.java b/src/main/java/cloneproject/Instagram/service/SearchService.java index 4f9779be..d367568b 100644 --- a/src/main/java/cloneproject/Instagram/service/SearchService.java +++ b/src/main/java/cloneproject/Instagram/service/SearchService.java @@ -1,8 +1,9 @@ package cloneproject.Instagram.service; - import java.util.List; +import java.util.stream.Collectors; +import cloneproject.Instagram.entity.hashtag.Hashtag; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -20,37 +21,47 @@ @Service @RequiredArgsConstructor public class SearchService { - + private final SearchRepository searchRepository; private final SearchMemberRepository searchMemberRepository; private final SearchHashtagRepository searchHashtagRepository; @Transactional(readOnly = true) - public List searchByText(String text){ + public List searchByText(String text) { final String memberId = SecurityContextHolder.getContext().getAuthentication().getName(); - List result; - if(text.charAt(0) == '#'){ + final List result; + if (text.charAt(0) == '#') { result = searchRepository.searchByTextOnlyHashtag(Long.valueOf(memberId), text.substring(1)); - }else{ + } else { result = searchRepository.searchByText(Long.valueOf(memberId), text); } return result; } @Transactional - public void increaseSearchMemberCount(String username){ + public void increaseSearchMemberCount(String username) { SearchMember searchMember = searchMemberRepository.findByMemberUsername(username) - .orElseThrow(MemberDoesNotExistException::new); + .orElseThrow(MemberDoesNotExistException::new); searchMember.upCount(); searchMemberRepository.save(searchMember); } @Transactional - public void increaseSearchHashtagCount(String name){ + public void increaseSearchHashtagCount(String name) { SearchHashtag searchHashtag = searchHashtagRepository.findByHashtagName(name) - .orElseThrow(HashtagNotFoundException::new); + .orElseThrow(HashtagNotFoundException::new); searchHashtag.upCount(); searchHashtagRepository.save(searchHashtag); } + @Transactional + public void createSearchHashtag(Hashtag hashtag) { + searchHashtagRepository.save(new SearchHashtag(hashtag)); + } + + @Transactional + public void deleteSearchHashtags(List hashtags) { + final List searchHashtags = searchHashtagRepository.findAllByHashtagIn(hashtags); + searchHashtagRepository.deleteAllInBatch(searchHashtags); + } } From 3c48b3171c52a170107f06e19f3f3bd6de060bbe Mon Sep 17 00:00:00 2001 From: DH CHOI Date: Mon, 21 Mar 2022 23:49:15 +0900 Subject: [PATCH 6/8] =?UTF-8?q?Fix:=20=EC=9D=BC=EC=B9=98=ED=95=98=EB=8A=94?= =?UTF-8?q?=20=EA=B2=80=EC=83=89=EC=96=B4=20=EC=B2=98=EB=A6=AC=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 검색어와 완전히 일치하는 해시태그, 유저네임의 처리 수정 - 쿼리를 날리는 방식에서 List의 contains함수를 이용하도록 수정 - 검색 조회수 증가의 유저, 해시태그를 하나의 API로 합침 --- .../controller/SearchController.java | 22 ++++++--------- .../search/SearchRepositoryQuerydslImpl.java | 19 +++++-------- .../Instagram/service/SearchService.java | 28 ++++++++++--------- 3 files changed, 30 insertions(+), 39 deletions(-) diff --git a/src/main/java/cloneproject/Instagram/controller/SearchController.java b/src/main/java/cloneproject/Instagram/controller/SearchController.java index 9ddbd4e2..cb16797b 100644 --- a/src/main/java/cloneproject/Instagram/controller/SearchController.java +++ b/src/main/java/cloneproject/Instagram/controller/SearchController.java @@ -16,6 +16,7 @@ import cloneproject.Instagram.service.SearchService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -39,21 +40,14 @@ public ResponseEntity searchText(@RequestParam String text) { return new ResponseEntity<>(result, HttpStatus.valueOf(result.getStatus())); } - @ApiOperation(value = "유저 검색 조회수 증가") - @ApiImplicitParam(name = "username", value = "조회수 증가시킬 username", required = true, example = "dlwlrma") + @ApiOperation(value = "검색 조회수 증가") + @ApiImplicitParams({ + @ApiImplicitParam(name = "entityName", value = "조회수 증가시킬 식별 name", required = true, example = "dlwlrma"), + @ApiImplicitParam(name = "entityType", value = "조회수 증가시킬 type", required = true, example = "MEMBER") + }) @PostMapping(value = "/topsearch/member/upcount") - public ResponseEntity increaseSearchMemberCount(@RequestParam String username) { - searchService.increaseSearchMemberCount(username); - - ResultResponse result = ResultResponse.of(ResultCode.INCREASE_SEARCH_COUNT_SUCCESS, null); - return new ResponseEntity<>(result, HttpStatus.valueOf(result.getStatus())); - } - - @ApiOperation(value = "해시태그 검색 조회수 증가") - @ApiImplicitParam(name = "name", value = "조회수 증가시킬 hashtag", required = true, example = "만두") - @PostMapping(value = "/topsearch/hashtag/upcount") - public ResponseEntity increaseSearchHashtagCount(@RequestParam String name) { - searchService.increaseSearchHashtagCount(name); + public ResponseEntity increaseSearchMemberCount(@RequestParam String entityName, @RequestParam String entityType) { + searchService.increaseSearchCount(entityName, entityType); ResultResponse result = ResultResponse.of(ResultCode.INCREASE_SEARCH_COUNT_SUCCESS, null); return new ResponseEntity<>(result, HttpStatus.valueOf(result.getStatus())); diff --git a/src/main/java/cloneproject/Instagram/repository/search/SearchRepositoryQuerydslImpl.java b/src/main/java/cloneproject/Instagram/repository/search/SearchRepositoryQuerydslImpl.java index 4ff63de4..2977550f 100644 --- a/src/main/java/cloneproject/Instagram/repository/search/SearchRepositoryQuerydslImpl.java +++ b/src/main/java/cloneproject/Instagram/repository/search/SearchRepositoryQuerydslImpl.java @@ -57,7 +57,7 @@ public List searchByText(Long loginedId, String text){ .where(searchHashtag.hashtag.name.like(keyword)) ))) .orderBy(search.count.desc()) - .limit(50) + .limit(2) .distinct() .fetch(); @@ -87,7 +87,7 @@ public List searchByText(Long loginedId, String text){ // follow 주입 final List resultUsernames = memberMap.values().stream().map(s -> s.getMemberDTO().getUsername()) - .collect(Collectors.toList()); + .collect(Collectors.toList()); // TODO 우선 이전의 search에 있던 코드 그대로 넣었는데 개선 필요해보임 ! memberMap.forEach((id, member) -> { @@ -125,16 +125,11 @@ public List searchByText(Long loginedId, String text){ )) ); - boolean matchingMemberExists = queryFactory - .from(searchMember) - .innerJoin(searchMember.member, member).fetchJoin() - .where(searchMember.id.in(searchIds).and(searchMember.member.username.eq(text))) - .fetchFirst() != null; - boolean matchingHashtagExists = queryFactory - .from(searchHashtag) - .innerJoin(searchHashtag.hashtag, hashtag).fetchJoin() - .where(searchHashtag.id.in(searchIds).and(searchHashtag.hashtag.name.eq(text))) - .fetchFirst() != null; + final List resultHashtagNames = hashtagMap.values().stream().map(h -> h.getName()) + .collect(Collectors.toList()); + + boolean matchingMemberExists = resultUsernames.contains(text); + boolean matchingHashtagExists = resultHashtagNames.contains(text); final List searchDTOs = searches.stream() .map(search -> { diff --git a/src/main/java/cloneproject/Instagram/service/SearchService.java b/src/main/java/cloneproject/Instagram/service/SearchService.java index d367568b..42ba8c8e 100644 --- a/src/main/java/cloneproject/Instagram/service/SearchService.java +++ b/src/main/java/cloneproject/Instagram/service/SearchService.java @@ -39,19 +39,21 @@ public List searchByText(String text) { } @Transactional - public void increaseSearchMemberCount(String username) { - SearchMember searchMember = searchMemberRepository.findByMemberUsername(username) - .orElseThrow(MemberDoesNotExistException::new); - searchMember.upCount(); - searchMemberRepository.save(searchMember); - } - - @Transactional - public void increaseSearchHashtagCount(String name) { - SearchHashtag searchHashtag = searchHashtagRepository.findByHashtagName(name) - .orElseThrow(HashtagNotFoundException::new); - searchHashtag.upCount(); - searchHashtagRepository.save(searchHashtag); + public void increaseSearchCount(String entityName, String entityType) { + switch(entityType){ + case "MEMBER": + SearchMember searchMember = searchMemberRepository.findByMemberUsername(entityName) + .orElseThrow(MemberDoesNotExistException::new); + searchMember.upCount(); + searchMemberRepository.save(searchMember); + break; + case "HASHTAG": + SearchHashtag searchHashtag = searchHashtagRepository.findByHashtagName(entityName) + .orElseThrow(HashtagNotFoundException::new); + searchHashtag.upCount(); + searchHashtagRepository.save(searchHashtag); + break; + } } @Transactional From 736b77021135fdae2ba1262dac534f86c19b5ad9 Mon Sep 17 00:00:00 2001 From: DH CHOI Date: Mon, 21 Mar 2022 23:53:33 +0900 Subject: [PATCH 7/8] =?UTF-8?q?Fix:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=9B=84=20=EB=B3=B5=EA=B5=AC=EC=8B=9C=EC=BC=9C=EB=86=93?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EC=9D=80=20=EC=BD=94=EB=93=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/search/SearchRepositoryQuerydslImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/cloneproject/Instagram/repository/search/SearchRepositoryQuerydslImpl.java b/src/main/java/cloneproject/Instagram/repository/search/SearchRepositoryQuerydslImpl.java index 2977550f..0a15014d 100644 --- a/src/main/java/cloneproject/Instagram/repository/search/SearchRepositoryQuerydslImpl.java +++ b/src/main/java/cloneproject/Instagram/repository/search/SearchRepositoryQuerydslImpl.java @@ -57,7 +57,7 @@ public List searchByText(Long loginedId, String text){ .where(searchHashtag.hashtag.name.like(keyword)) ))) .orderBy(search.count.desc()) - .limit(2) + .limit(50) .distinct() .fetch(); From f00455db38c7cb5b57c2889c269a9c0d2620a572 Mon Sep 17 00:00:00 2001 From: vectorch-dev Date: Tue, 22 Mar 2022 12:33:22 +0900 Subject: [PATCH 8/8] =?UTF-8?q?Fix:=20=EA=B2=80=EC=83=89=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=EC=88=98=20=EC=A6=9D=EA=B0=80=20URI=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cloneproject/Instagram/controller/SearchController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/cloneproject/Instagram/controller/SearchController.java b/src/main/java/cloneproject/Instagram/controller/SearchController.java index cb16797b..764cbf29 100644 --- a/src/main/java/cloneproject/Instagram/controller/SearchController.java +++ b/src/main/java/cloneproject/Instagram/controller/SearchController.java @@ -45,7 +45,7 @@ public ResponseEntity searchText(@RequestParam String text) { @ApiImplicitParam(name = "entityName", value = "조회수 증가시킬 식별 name", required = true, example = "dlwlrma"), @ApiImplicitParam(name = "entityType", value = "조회수 증가시킬 type", required = true, example = "MEMBER") }) - @PostMapping(value = "/topsearch/member/upcount") + @PostMapping(value = "/topsearch/upcount") public ResponseEntity increaseSearchMemberCount(@RequestParam String entityName, @RequestParam String entityType) { searchService.increaseSearchCount(entityName, entityType);