1편에서 이어집니다.
2편은 구체적인 기능 구현입니다.
Follow Controller
*from_user: 팔로우를 요청하는 유저
*to_user: 팔로우를 요청받은 유저
팔로우 걸기, 팔로잉/팔로워 목록 조회, 팔로우 취소 기능을 구현했다.
@RestController
@RequiredArgsConstructor
public class FollowController {
private final UserService userService;
private final FollowService followService;
/**
* 친구 추가
*/
@PostMapping("/users/follow/{friendName}")
public ResponseEntity follow(Authentication authentication, @PathVariable("friendName") String friendName) {
User from_user = userService.findUser(authentication.getName());
User to_user = userService.findUser(friendName);
followService.follow(from_user, to_user);
return ResponseEntity.ok().build();
}
/**
* 팔로잉 목록 조회
*/
@GetMapping("/users/{userName}/following")
public ResponseEntity<List<FollowDTO>> getFollowingList(@PathVariable("userName") String userName, Authentication auth) {
User from_user = userService.findUser(userName);
User requestUser=userService.findUser(auth.getName());
return ResponseEntity.ok().body(followService.followingList(from_user, requestUser));
}
/**
* 팔로워 목록 조회
*/
@GetMapping("/users/{userName}/follower")
public ResponseEntity<List<FollowDTO>> getFollowerList(@PathVariable("userName") String userName, Authentication auth) {
User to_user = userService.findUser(userName);
User requestUser=userService.findUser(auth.getName());
return ResponseEntity.ok().body(followService.followerList(to_user, requestUser));
}
/**
* 팔로우 취소
*/
@DeleteMapping("/users/follow/{friendName}")
public ResponseEntity<String> deleteFollow(Authentication authentication){
return ResponseEntity.ok().body(followService.cancelFollow(userService.findUser(authentication.getName())));
}
}
팔로잉(팔로워) 목록 조회의 API를 처음에는 /users/following(follower) 이렇게 설계했었는데,
나의 팔로잉/팔로워 목록뿐만 아니라 다른 사람의 팔로잉/팔로워 목록을 조회하는 경우도 있어서
목록의 주체를 PathVariable userName으로 추가했다.(본인의 목록을 조회하면 자신의 userName이 들어감.)
또한 getFollwingList와 getFollowerList의 requestUser는 로그인한 사용자를 의미하는데,
이런 식으로 다른 사람의 팔로잉/팔로워 목록이더라도
나와의 관계를 표시하기 위해 필요하다.
다른 사람의 목록을 볼 때에도, 내가 이미 팔로우를 한 사람인지,
아예 관련이 없는 사람인지 보여주고 싶기 때문에 추가했다.
Follow Service
Follow 기능
public String follow(User from_user, User to_user) {
// 자기 자신 follow 안됨
if (from_user == to_user)
throw new FollowException(ErrorCode.INVALID_REQUEST, "자기 자신을 follow할 수 없습니다.");
// 중복 follow x
if (followRepository.findFollow(from_user, to_user).isPresent())
throw new FollowException(ErrorCode.FOLLOW_DUPLICATED, "이미 follow했습니다.");
Follow follow = Follow.builder()
.toUser(to_user)
.fromUser(from_user)
.build();
followRepository.save(follow);
return "Success";
}
Follow 기능에서는 자기 자신을 follow하는 경우와 이미 follow한 사람을 또 follow하는 경우를 막아놓았다.
Following/Follower 리스트
//following 리스트
public List<FollowDTO> followingList(User selectedUser, User requestUser) {
List<Follow> list = followRepository.findByFromUser(selectedUser);
List<FollowDTO> followList = new ArrayList<>();
for (Follow f : list) {
followList.add(userRepository.findByUserName(f.getToUser().getUserName())
.orElseThrow().toFollow(findStatus(f.getToUser(), requestUser)));
}
return followList;
}
//follower list
public List<FollowDTO> followerList(User selectedUser, User requestUser) {
List<Follow> list = followRepository.findByToUser(selectedUser);
List<FollowDTO> followerList = new ArrayList<>();
for (Follow f : list) {
followerList.add(userRepository.findByUserName(f.getFromUser().getUserName())
.orElseThrow().toFollow(findStatus(f.getFromUser(), requestUser)));
}
return followerList;
}
두 메서드는 거의 비슷하게 생겼다.
Following 리스트는 selectedUser가 follow한 사람들이기 때문에 FromUser에서 검색해서 찾고,
Follower 리스트는 selectedUser를 follow한 사람들이어서 ToUser에서 찾는다.
findStatus 메서드는 로그인한 사용자(requestUser)와의 관계를 알기 위한 메서드다.
//A와 B의 follow관계 찾기
private String findStatus(User selectedUser, User requestUser) {
if (selectedUser.getUserName() == requestUser.getUserName())
return "self";
if (followRepository.findFollow(requestUser, selectedUser).isEmpty())
return "none";
return "following";
}
requestUser가 selectedUser를 following하는지 안 하는지만 판별한다.
Follow 취소
public String cancelFollow(User user) {
followRepository.deleteFollowByFromUser(user);
return "Success";
}
JPA의 deleteBy를 공부했을 때, 만약 findByFromUser 조회시 값이 없다면
EmptyResultDataAccessException이 발생한다고 했는데,
없는 follow를 delete할 때도 아무 예외가 발생하지 않고 Success를 리턴한다.
좀 더 공부가 필요한 부분이다.
Follow Repository
public interface FollowRepository extends JpaRepository<Follow, Long> {
List<Follow> findByFromUser(User from_user);
List<Follow> findByToUser(User to_user);
void deleteFollowByFromUser(User from_user);
@Query("select f from Follow f where f.fromUser = :from and f.toUser = :to")
Optional<Follow> findFollow(@Param("from") User from_user, @Param("to") User to_user);
}
JpaRepository로 작성하였다.
Jpa는 공부할 것이 엄청 많다고 느낀다.(지금 내가 짠 코드는 많은 쿼리를 유발한다...ㅠㅠ)
'캡스톤프로젝트' 카테고리의 다른 글
[HTTP Method] PUT vs PATCH 결정하기 (0) | 2023.09.22 |
---|---|
[Nginx, Amazon Linux] Certbot을 이용한 https 인증받기 (0) | 2023.09.13 |
졸업프로젝트, 태초마을로 돌아가다 (0) | 2023.09.02 |
[SpringBoot] 팔로워, 팔로잉 기능 구현하기 1 (0) | 2023.08.24 |
Jenkins, EC2를 이용한 Springboot의 CI/CD 파이프라인 구축 (1) | 2023.05.26 |