Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

해시태그 팔로우 구현, 검색 API 개선 #145

Merged
merged 9 commits into from
Mar 22, 2022
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -13,7 +12,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;

Expand Down Expand Up @@ -47,19 +48,20 @@ public ResponseEntity<ResultResponse> 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<ResultResponse> getHashtags(
@NotNull(message = "page는 필수입니다.") @RequestParam int page,
@NotNull(message = "size는 필수입니다.") @RequestParam int size,
@NotBlank(message = "hashtag는 필수입니다.") @RequestParam String hashtag) {
final Page<HashtagDTO> response = hashtagService.getHashTagsLikeName(page, size, hashtag.substring(1));
@ApiOperation(value = "해시태그 팔로우")
@ApiImplicitParam(name = "hashtag", value = "hashtag", example = "만두", required = true)
@PostMapping("/hashtags/follow")
public ResponseEntity<ResultResponse> followHashtag(@NotBlank(message = "hashtag는 필수입니다.") @RequestParam String hashtag) {
hashtagService.followHashtag(hashtag);
return ResponseEntity.ok(ResultResponse.of(FOLLOW_HASHTAG_SUCCESS, null));
}

return ResponseEntity.ok(ResultResponse.of(GET_HASHTAGS_SUCCESS, response));
@ApiOperation(value = "해시태그 언팔로우")
@ApiImplicitParam(name = "hashtag", value = "hashtag", example = "만두", required = true)
@DeleteMapping("/hashtags/follow")
public ResponseEntity<ResultResponse> unfollowHashtag(@NotBlank(message = "hashtag는 필수입니다.") @RequestParam String hashtag) {
hashtagService.unfollowHashtag(hashtag);
return ResponseEntity.ok(ResultResponse.of(UNFOLLOW_HASHTAG_SUCCESS, null));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -117,14 +111,4 @@ public ResponseEntity<ResultResponse> 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<ResultResponse> searchMember(@RequestParam String text) {
List<SearchedMemberDTO> memberInfos = memberService.searchMember(text);

ResultResponse result = ResultResponse.of(ResultCode.SEARCH_MEMBER_SUCCESS, memberInfos);
return new ResponseEntity<>(result, HttpStatus.valueOf(result.getStatus()));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
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.ApiImplicitParams;
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<ResultResponse> searchText(@RequestParam String text) {
List<SearchDTO> searchDTOs = searchService.searchByText(text);

ResultResponse result = ResultResponse.of(ResultCode.SEARCH_SUCCESS, searchDTOs);
return new ResponseEntity<>(result, HttpStatus.valueOf(result.getStatus()));
}

@ApiOperation(value = "검색 조회수 증가")
@ApiImplicitParams({
@ApiImplicitParam(name = "entityName", value = "조회수 증가시킬 식별 name", required = true, example = "dlwlrma"),
@ApiImplicitParam(name = "entityType", value = "조회수 증가시킬 type", required = true, example = "MEMBER")
})
@PostMapping(value = "/topsearch/upcount")
public ResponseEntity<ResultResponse> 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()));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,14 @@ public enum ErrorCode {
// Email
CANT_SEND_EMAIL(500, "E001", "이메일 전송 중 오류가 발생했습니다."),

// HashTag
HASHTAG_NOT_FOUND(400, "H001", "존재하지 않는 해시태그 입니다"),
CANT_FOLLOW_HASHTAG(400, "H002", "해시태그 팔로우 실패"),
CANT_UNFOLLOW_HASHTAG(400, "H003", "해시태그 언팔로우 실패"),

// Story
INVALID_STORY_IMAGE(400, "S001", "스토리 이미지는 필수입니다."),
INVALID_STORY_IMAGE_INDEX(400, "S002", "스토리 이미지 인덱스가 올바르지 않습니다."),
INVALID_STORY_IMAGE_INDEX(400, "S002", "스토리 이미지 인덱스가 올바르지 않습니다.")
;

private int status;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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();
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,15 @@ 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", "해시태그 언팔로우 성공"),

// Story
CREATE_STORY_SUCCESS(200, "S001", "스토리 업로드 성공"),

// Search
SEARCH_SUCCESS(200, "SE001", "검색 성공"),
INCREASE_SEARCH_COUNT_SUCCESS(200, "SE002", "검색 조회수 증가 성공"),
;

private int status;
Expand Down
22 changes: 22 additions & 0 deletions src/main/java/cloneproject/Instagram/dto/search/SearchDTO.java
Original file line number Diff line number Diff line change
@@ -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)
seonpilKim marked this conversation as resolved.
Show resolved Hide resolved
public abstract class SearchDTO {

private String dtype;

@JsonIgnore
private Long count;

}
Original file line number Diff line number Diff line change
@@ -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();
}

}
Original file line number Diff line number Diff line change
@@ -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<FollowDTO> 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<FollowDTO> followingMemberFollow) {
this.followingMemberFollow = followingMemberFollow;
}

}
Original file line number Diff line number Diff line change
@@ -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;
}

}
Loading