Follower Service

강한친구·2022년 7월 18일
0

기능

인스타그램에 있는것처럼, 팔로우 처리와 언팔로우 처리를 구현했다. 추후, 프론트의 요청에 따라 해당 유저가 팔로우한 유저를 전부 보여주는 기능을 구현할 계획이다.

API Spec

@Getter @Setter
public class FolloweeNameDto {

    String followeeName;
}

프론트단에서는 로그인한 유저가 특정 유저 팔로우 버튼을 눌렀을 때 그 유저의 username을 보내준다.

Follow Entity

@Entity
@Getter @Setter
public class Followers {

    @Id @GeneratedValue
    @Column(name = "FOLLOWERS_TABLE_ID")
    private long id;

    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;

    @Column(name = "FOLLOWEE_ID", nullable = false)
    private long followeeId;

//    @Column(nullable = false)
//    private boolean status = true;

    @CreationTimestamp
    private Timestamp createdAt;
    @UpdateTimestamp
    private Timestamp updatedAt;

    //B logic

    public static Followers createFollowerShip(long id, Member member) {
        Followers followers = new Followers();
        followers.setFolloweeId(id);
        followers.setMember(member);
        return followers;
    }
}

Folowers 엔티티는 Member와 다대일 관계이다. 하나의 맴버는 여러 팔로우 관계를 가질 수 있기 때문이다.

createFollowShip은 followee id와 follower member 객체로 새로운 follow 객체를 만드는 메서드이다.

Controller

	@PostMapping("/doFollow")
    public int followMember(@RequestBody FolloweeNameDto followeeName, HttpServletResponse response, HttpServletRequest request) {
        memberService.makeFollow(followeeName.getFolloweeName(), getUsername(request));
        return response.getStatus();
    }

    @PostMapping("/undoFollow")
    public int unfollowMember(@RequestBody FolloweeNameDto followeeName, HttpServletResponse response, HttpServletRequest request) {
        memberService.makeUnFollow(followeeName.getFolloweeName(), getUsername(request));
        return response.getStatus();
    }
    
    private String getUsername (HttpServletRequest request) {
        HttpSession session = request.getSession(false);

        SecurityContextImpl context = (SecurityContextImpl)session.getAttribute("SPRING_SECURITY_CONTEXT");
        return context.getAuthentication().getName();
    }
    

팔로우 하는 기능과, 기존에 있던 팔로우를 삭제하는 기능 두가지가 존재한다.

둘다 followee 의 username을 받아서 사용한다.
follower의 username은 session에서 꺼내서 사용한다.
이전글 참조

Service

public void makeFollow(String followeeName, String username) {
        Member followee = memberRepository.findByUsername(followeeName);
        Member follower = memberRepository.findByUsername(username);

        Followers followerShip = Followers.createFollowerShip(followee.getId(), follower);

        followersRepository.makeFollow(followerShip);
    }
    
public void makeUnFollow(String followeeName, String username) {
        long followeeId = memberRepository.findByUsername(followeeName).getId();
        Member follower = memberRepository.findByUsername(username);
        followersRepository.unFollow(followeeId, follower);
    }

서비스에서는 각각 username을 기반으로, member 객체를 찾아낸다.

makeFollow

팔로우를 생성하는 경우, createFollowerShip 메서드를 통해서 새로운 follower 객체를 만들어낸다. 그 후, 이를 repository로 넘긴다.

makeUnFollow

언팔로우 기능의 겨우, repository에서 followeeId와 member 객체를 통해 삭제처리를 해주기에 이를 repository로 전달한다.

Repository

@Repository
@RequiredArgsConstructor
public class FollowersRepository {

    private final EntityManager em;

    public void makeFollow(Followers followers) {
        em.persist(followers);
    }

    public void unFollow(long followeeId, Member follower) {
        String jpql = "delete from Followers m where m.followeeId =:followeeId and m.member = :follower";
        Query query = em.createQuery(jpql)
                .setParameter("followeeId", followeeId)
                .setParameter("follower", follower);
        query.executeUpdate();
    }
}

makeFollow

이미 만들어진 followers 객체를 저장하면 된다.

unFollow

jpql 삭제쿼리를 날려야한다.

여기서 주의할점의 몇가지 있다.

		String jpql = "delete from Followers m where m.followeeId =:followeeId and m.member = :follower";
        Query query = em.createQuery(jpql)
                .setParameter("followeeId", followeeId)
                .setParameter("follower", follower);
        query.executeUpdate();

삭제 / 업데이트 쿼리는 쿼리를 직접 db로 날리는 방식이다. 따라서 createQuery를 하고나서 이를 변수에 저장하고, execute 해야한다.
마치 jdbc와 같다.

하지만 createQuery의 기본형은 List형태이다.

따라서 Query 타입으로 저장되도록 잘 조정해야한다.
또한, 기존의 createQuery처럼 뒤에 따로 class를 매핑해줄 필요가 없다. 만약 클래스를 매핑하게 되면

Update/delete queries cannot be typed JPA

오류가 발생하게 된다.

PostMan Test

로그인

makeFollow

8000번 Jameson 유저는 8001번 Carius를 팔로우 할 것이다.

unFollow

언팔로우를 하면, status를 바꿀 수도 있겠지만, 아예 삭제하는 방식을 선택했다.

보는것처럼 쿼리가 잘 날아간것을 볼 수 있다.

실제 db에서도 사라져있다.

추가 구현할 기능

  1. 프론트단에서 유저가 팔로우하고 있는 전체 명단이나, 유저를 팔로우하는 명단을 요구하는 경우, 이를 반환할 수 있는 기능을 구현해야한다. 다만 id로 저장하기 때문에 username으로 반환을 해야하는데, 이 과정에서 sql 최적화에 실패하면 많은 자원이 낭비될 것 같다.

0개의 댓글