인스타그램에 있는것처럼, 팔로우 처리와 언팔로우 처리를 구현했다. 추후, 프론트의 요청에 따라 해당 유저가 팔로우한 유저를 전부 보여주는 기능을 구현할 계획이다.
@Getter @Setter
public class FolloweeNameDto {
String followeeName;
}
프론트단에서는 로그인한 유저가 특정 유저 팔로우 버튼을 눌렀을 때 그 유저의 username을 보내준다.
@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 객체를 만드는 메서드이다.
@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에서 꺼내서 사용한다.
이전글 참조
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 객체를 찾아낸다.
팔로우를 생성하는 경우, createFollowerShip 메서드를 통해서 새로운 follower 객체를 만들어낸다. 그 후, 이를 repository로 넘긴다.
언팔로우 기능의 겨우, repository에서 followeeId와 member 객체를 통해 삭제처리를 해주기에 이를 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();
}
}
이미 만들어진 followers 객체를 저장하면 된다.
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
오류가 발생하게 된다.
8000번 Jameson 유저는 8001번 Carius를 팔로우 할 것이다.
언팔로우를 하면, status를 바꿀 수도 있겠지만, 아예 삭제하는 방식을 선택했다.
보는것처럼 쿼리가 잘 날아간것을 볼 수 있다.
실제 db에서도 사라져있다.