-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
340 additions
and
1 deletion.
There are no files selected for viewing
49 changes: 49 additions & 0 deletions
49
src/main/java/com/leets/X/domain/follow/controller/FollowController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package com.leets.X.domain.follow.controller; | ||
|
||
import com.leets.X.domain.follow.dto.response.FollowResponse; | ||
import com.leets.X.domain.follow.service.FollowService; | ||
import com.leets.X.global.common.response.ResponseDto; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.security.core.annotation.AuthenticationPrincipal; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
import java.util.List; | ||
|
||
import static com.leets.X.domain.follow.controller.ResponseMessage.*; | ||
|
||
@Tag(name = "FOLLOW") | ||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/api/v1/follows") | ||
public class FollowController { | ||
private final FollowService followService; | ||
|
||
@PostMapping("/{userId}") | ||
@Operation(summary = "팔로우 하기") | ||
public ResponseDto<String> follow(@PathVariable Long userId, @AuthenticationPrincipal String email){ | ||
followService.follow(userId, email); | ||
return ResponseDto.response(FOLLOW_SUCCESS.getCode(), FOLLOW_SUCCESS.getMessage()); | ||
} | ||
|
||
@GetMapping("follower/{userId}") | ||
@Operation(summary = "해당 유저의 팔로워 조회(해당 유저를 팔로우 하는 사용자 목록") | ||
public ResponseDto<List<FollowResponse>> getFollowers(@PathVariable Long userId){ | ||
return ResponseDto.response(GET_FOLLOWER_SUCCESS.getCode(), GET_FOLLOWER_SUCCESS.getMessage(), followService.getFollowers(userId)); | ||
} | ||
|
||
@GetMapping("following/{userId}") | ||
@Operation(summary = "해당 유저의 팔로잉 조회(해당 유저가 팔로우 하는 사용자 목록") | ||
public ResponseDto<List<FollowResponse>> getFollowings(@PathVariable Long userId){ | ||
return ResponseDto.response(GET_FOLLOWING_SUCCESS.getCode(), GET_FOLLOWING_SUCCESS.getMessage(), followService.getFollowings(userId)); | ||
} | ||
|
||
@DeleteMapping("/{userId}") | ||
@Operation(summary = "언팔로우 하기") | ||
public ResponseDto<String> unfollow(@PathVariable Long userId, @AuthenticationPrincipal String email){ | ||
followService.unfollow(userId, email); | ||
return ResponseDto.response(UNFOLLOW_SUCCESS.getCode(), UNFOLLOW_SUCCESS.getMessage()); | ||
} | ||
|
||
} |
17 changes: 17 additions & 0 deletions
17
src/main/java/com/leets/X/domain/follow/controller/ResponseMessage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package com.leets.X.domain.follow.controller; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
|
||
@Getter | ||
@AllArgsConstructor | ||
public enum ResponseMessage { | ||
|
||
FOLLOW_SUCCESS(200, "팔로우에 성공했습니다."), | ||
GET_FOLLOWER_SUCCESS(200, "팔로워 목록 조회에 성공했습니다."), | ||
GET_FOLLOWING_SUCCESS(200, "팔로잉 목록 조회에 성공했습니다."), | ||
UNFOLLOW_SUCCESS(200, "언팔로우에 성공했습니다."); | ||
|
||
private final int code; | ||
private final String message; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,35 @@ | ||
package com.leets.X.domain.follow.domain;public class Follow { | ||
package com.leets.X.domain.follow.domain; | ||
|
||
import com.leets.X.domain.user.domain.User; | ||
import com.leets.X.global.common.domain.BaseTimeEntity; | ||
import jakarta.persistence.*; | ||
import lombok.*; | ||
|
||
@Entity | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@AllArgsConstructor | ||
@Builder | ||
@Getter | ||
public class Follow extends BaseTimeEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
@Column(name = "follow_id") | ||
private Long id; | ||
|
||
@ManyToOne | ||
@JoinColumn(name = "follower_id") | ||
private User follower; | ||
|
||
@ManyToOne | ||
@JoinColumn(name = "followed_id") | ||
private User followed; | ||
|
||
public static Follow of(User follower, User followed) { | ||
return Follow.builder() | ||
.follower(follower) | ||
.followed(followed) | ||
.build(); | ||
} | ||
|
||
} |
22 changes: 22 additions & 0 deletions
22
src/main/java/com/leets/X/domain/follow/dto/response/FollowResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.leets.X.domain.follow.dto.response; | ||
|
||
import com.leets.X.domain.user.domain.User; | ||
import lombok.Builder; | ||
|
||
@Builder | ||
public record FollowResponse( | ||
Long id, | ||
String name, | ||
String customId, | ||
String introduce | ||
// boolean followStatus | ||
) { | ||
public static FollowResponse from(User user) { | ||
return FollowResponse.builder() | ||
.id(user.getId()) | ||
.name(user.getName()) | ||
.customId(user.getCustomId()) | ||
.introduce(user.getIntroduce()) | ||
.build(); | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
src/main/java/com/leets/X/domain/follow/exception/AlreadyFollowException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.leets.X.domain.follow.exception; | ||
|
||
import com.leets.X.global.common.exception.BaseException; | ||
|
||
import static com.leets.X.domain.follow.exception.ErrorMessage.*; | ||
|
||
public class AlreadyFollowException extends BaseException { | ||
public AlreadyFollowException() { | ||
super(ALREADY_FOLLOW.getCode(), ALREADY_FOLLOW.getMessage()); | ||
} | ||
} | ||
|
20 changes: 20 additions & 0 deletions
20
src/main/java/com/leets/X/domain/follow/exception/ErrorMessage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.leets.X.domain.follow.exception; | ||
|
||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
|
||
@Getter | ||
@AllArgsConstructor | ||
public enum ErrorMessage { | ||
|
||
ALREADY_FOLLOW(400,"이미 팔로우한 상태입니다."), | ||
INVALID_FOLLOW(400, "자기 자신은 팔로우 할 수 없습니다."), | ||
FOLLOW_NOT_FOUND(404, "팔로우 데이터를 찾을 수 없습니다."), | ||
INVALID_UNFOLLOW(400, "팔로우 하지 않은 상대는 언팔로우 할 수 없습니다."); | ||
|
||
|
||
private final int code; | ||
private final String message; | ||
|
||
} |
12 changes: 12 additions & 0 deletions
12
src/main/java/com/leets/X/domain/follow/exception/FollowNotFoundException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.leets.X.domain.follow.exception; | ||
|
||
import com.leets.X.global.common.exception.BaseException; | ||
|
||
import static com.leets.X.domain.follow.exception.ErrorMessage.*; | ||
|
||
public class FollowNotFoundException extends BaseException { | ||
public FollowNotFoundException() { | ||
super(FOLLOW_NOT_FOUND.getCode(), FOLLOW_NOT_FOUND.getMessage()); | ||
} | ||
} | ||
|
11 changes: 11 additions & 0 deletions
11
src/main/java/com/leets/X/domain/follow/exception/InvalidFollowException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.leets.X.domain.follow.exception; | ||
|
||
import com.leets.X.global.common.exception.BaseException; | ||
|
||
import static com.leets.X.domain.follow.exception.ErrorMessage.*; | ||
|
||
public class InvalidFollowException extends BaseException { | ||
public InvalidFollowException() { | ||
super(INVALID_FOLLOW.getCode(), INVALID_FOLLOW.getMessage()); | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/main/java/com/leets/X/domain/follow/exception/InvalidUnfollowException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.leets.X.domain.follow.exception; | ||
|
||
import com.leets.X.global.common.exception.BaseException; | ||
|
||
import static com.leets.X.domain.follow.exception.ErrorMessage.*; | ||
|
||
public class InvalidUnfollowException extends BaseException { | ||
public InvalidUnfollowException() { | ||
super(INVALID_UNFOLLOW.getCode(), INVALID_UNFOLLOW.getMessage()); | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
src/main/java/com/leets/X/domain/follow/repository/FollowRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.leets.X.domain.follow.repository; | ||
|
||
import com.leets.X.domain.follow.domain.Follow; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
public interface FollowRepository extends JpaRepository<Follow, Long> { | ||
|
||
Optional<Follow> findByFollowerIdAndFollowedId(Long followerId, Long followedId); | ||
|
||
// followerId가 포함된 객체 리스트 반환 | ||
List<Follow> findByFollowerId(Long followerId); | ||
|
||
// followedId가 포함된 객체 리스트 반환 | ||
List<Follow> findByFollowedId(Long followedId); | ||
|
||
boolean existsByFollowerIdAndFollowedId(Long followerId, Long followedId); | ||
|
||
} |
96 changes: 96 additions & 0 deletions
96
src/main/java/com/leets/X/domain/follow/service/FollowService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package com.leets.X.domain.follow.service; | ||
|
||
import com.leets.X.domain.follow.domain.Follow; | ||
import com.leets.X.domain.follow.dto.response.FollowResponse; | ||
import com.leets.X.domain.follow.exception.AlreadyFollowException; | ||
import com.leets.X.domain.follow.exception.FollowNotFoundException; | ||
import com.leets.X.domain.follow.exception.InvalidFollowException; | ||
import com.leets.X.domain.follow.exception.InvalidUnfollowException; | ||
import com.leets.X.domain.follow.repository.FollowRepository; | ||
import com.leets.X.domain.user.domain.User; | ||
import com.leets.X.domain.user.service.UserService; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.util.List; | ||
@Slf4j | ||
@Service | ||
@RequiredArgsConstructor | ||
public class FollowService { | ||
private final FollowRepository followRepository; | ||
private final UserService userService; | ||
|
||
@Transactional | ||
public void follow(Long userId, String email){ | ||
User follower = userService.find(email); | ||
User followed = userService.find(userId); | ||
|
||
validate(follower.getId(), followed.getId()); | ||
|
||
Follow follow = followRepository.save(Follow.of(follower, followed)); | ||
|
||
follower.addFollowing(follow); | ||
followed.addFollower(follow); | ||
} | ||
|
||
public List<FollowResponse> getFollowers(Long userId){ | ||
User user = userService.find(userId); | ||
|
||
List<Follow> followerList = user.getFollowerList(); | ||
|
||
return followerList.stream() | ||
.map(follow -> { | ||
return FollowResponse.from(follow.getFollower()); }) | ||
.toList(); | ||
} | ||
|
||
public List<FollowResponse> getFollowings(Long userId){ | ||
User user = userService.find(userId); | ||
|
||
List<Follow> followingList = user.getFollowingList(); | ||
|
||
return followingList.stream() | ||
.map(follow -> { | ||
return FollowResponse.from(follow.getFollowed()); }) | ||
.toList(); | ||
} | ||
|
||
@Transactional | ||
public void unfollow(Long userId, String email){ | ||
User follower = userService.find(email); | ||
User followed = userService.find(userId); | ||
|
||
Follow follow = check(follower.getId(), followed.getId()); | ||
|
||
follower.removeFollowing(follow); | ||
followed.removeFollower(follow); | ||
|
||
followRepository.delete(follow); | ||
} | ||
|
||
public Follow find(Long followerId, Long followedId){ | ||
return followRepository.findByFollowerIdAndFollowedId(followerId, followedId) | ||
.orElseThrow(FollowNotFoundException::new); | ||
} | ||
|
||
// 기존 팔로우 정보가 있는지, 나한테 요청을 하지 않는지 검증 | ||
private void validate(Long followerId, Long followedId){ | ||
if(followRepository.existsByFollowerIdAndFollowedId(followerId, followedId)){ | ||
throw new AlreadyFollowException(); | ||
} | ||
if(followerId.equals(followedId)){ | ||
throw new InvalidFollowException(); | ||
} | ||
} | ||
|
||
// 팔로우 되어 있는지 확인 | ||
private Follow check(Long followerId, Long followedId){ | ||
if(!followRepository.existsByFollowerIdAndFollowedId(followerId, followedId)){ | ||
throw new InvalidUnfollowException(); | ||
} | ||
return find(followerId, followedId); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters