어디까지 갈 수 있을까?
5 팔로우 본문
팔로우 service
import com.post_show_blues.vine.domain.follow.FollowRepository;
import com.post_show_blues.vine.domain.member.MemberRepository;
import com.post_show_blues.vine.domain.notice.NoticeRepository;
import com.post_show_blues.vine.dto.NoticeResultDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@RequiredArgsConstructor
@Service
public class FollowService {
private final FollowRepository followRepository;
private final NoticeRepository noticeRepository;
private final MemberRepository memberRepository;
/**
* 팔로우
*/
@Transactional
public void isFollow(long fromMemberId, long toMemberId){
followRepository.rFollow(fromMemberId, toMemberId);
noticeSave(fromMemberId, toMemberId);
}
/**
* 언팔로우
*/
@Transactional
public void isUnFollow(long fromMemberId, long toMemberId){
followRepository.rUnFollow(fromMemberId, toMemberId);
}
private void noticeSave(long fromMemberId, long toMemberId){
String fromMemberNickname = memberRepository.findById(fromMemberId).get().getNickname();
NoticeResultDTO noticeResultDTO = NoticeResultDTO.builder()
.memberId(toMemberId)
.text(fromMemberNickname + "님이 회원님을 팔로잉 했습니다.")
.link("/member/"+fromMemberId)
.build();
noticeRepository.save(noticeResultDTO.toEntity());
}
}
사실 follow service의 메소드도 이름을 follow로 하고 싶었는데 그러면 엔티티 이름이랑 repository의 메소드 이름이랑 겹칠 것 같아서 차선책으로 isFollow로 지었다. 이런 경우 어떻게 해야될 지는 계속 고민해야 될 듯 하다
우리 서비스는 인스타그램처럼 팔로우하면 알람테이블에 저장해놓는 구조이므로 follow 함과 동시에 테이블에 저장하도록 했다. link 에는 해당 메시지를 넣었을때 어디로 갈 지 주소값을 넣어봤다.
알림 dto
import com.post_show_blues.vine.domain.notice.Notice;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class NoticeResultDTO {
private Long memberId;
private String text;
private String link;
public Notice toEntity() {
return Notice.builder()
.memberId(memberId)
.text(text)
.link(link)
.build();
}
}
entity랑 모양 똑같은데 entity는 언제든지 변경될 수 있으니 dto를 따로 만들어주는게 좋을 듯 하다
팔로우 repository
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface FollowRepository extends JpaRepository<Follow, Long> {
@Modifying
@Query(value="INSERT INTO follow (from_member_id, to_member_id) VALUES (:fromMemberId, :toMemberId)", nativeQuery = true)
void rFollow(@Param("fromMemberId") long fromMemberId,@Param("toMemberId") long toMemberId);
@Modifying
@Query(value="DELETE FROM follow WHERE from_member_id=:fromMemberId AND to_member_id=:toMemberId", nativeQuery = true)
void rUnFollow(@Param("fromMemberId") long fromMemberId,@Param("toMemberId") long toMemberId);
}
insert를 할 때 Spring data JPA의 save()를 사용하면 되기 때문에 JPQL에는 insert 문이 없다. 그러므로 nativeQuery를 쓰자.
어차피 각각 받으므로 묶어줬다가 다시 나누지 말고 각각 나눠서 매핑해주자
팔로우 엔티티
import com.post_show_blues.vine.domain.member.Member;
import lombok.*;
import javax.persistence.*;
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString
@Table(
uniqueConstraints = {
@UniqueConstraint(
name="follow_uk",
columnNames={"from_member_id", "to_member_id"}
)
}
)
public class Follow {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="follow_id")
private Long id;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="from_member_id",nullable = false)
private Member fromMemberId; //팔로우 하는 멤버
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="to_member_id",nullable = false)
private Member toMemberId; //팔로우 받는 멤버
}
XToOne은 fetch=FetchType.Lazy를 붙여주는 게 좋다고 한다. 안 그러면 연관관계에 있는 테이블 다 끌어와서 검색한다고 함.
팔로우 서비스 테스트
import com.post_show_blues.vine.domain.follow.Follow;
import com.post_show_blues.vine.domain.follow.FollowRepository;
import com.post_show_blues.vine.domain.member.Member;
import com.post_show_blues.vine.domain.member.MemberRepository;
import com.post_show_blues.vine.domain.notice.Notice;
import com.post_show_blues.vine.domain.notice.NoticeRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import static org.assertj.core.api.Assertions.*;
@SpringBootTest
@Transactional
public class FollowServiceTest {
@Autowired
FollowService followService;
@Autowired
FollowRepository followRepository;
@Autowired
MemberRepository memberRepository;
@Autowired
NoticeRepository noticeRepository;
Member memberA;
Member memberB;
@BeforeEach
public void setup(){
memberA = memberA();
memberB = memberB();
followService.isFollow(memberA.getId(), memberB.getId());
}
@Test
public void 팔로우() throws Exception {
//given
//setup()에서 함
System.out.println("memberA = " + memberA);
//when
List<Follow> followList = followRepository.findAll();
Follow follow = followList.get(followList.size()-1);
System.out.println("follow = " + follow);
System.out.println(followList.contains(follow));
//then
assertThat(follow.getFromMemberId().getId()).isEqualTo(memberA.getId());
assertThat(follow.getToMemberId().getId()).isEqualTo(memberB.getId());
}
@Test
public void 알람테이블() throws Exception {
//given
//setup()에서 함
//when
List<Notice> noticeList = noticeRepository.findAll();
Notice notice = noticeList.get(noticeList.size() - 1);
//then
assertThat(notice.getMemberId()).isEqualTo(memberB.getId());
}
@Test
public void 언팔로우() throws Exception {
//given
System.out.println("memberA = " + memberA);
List<Follow> followList = followRepository.findAll();
Follow follow = followList.get(followList.size()-1);
//when
followService.isUnFollow(memberA.getId(), memberB.getId());
List<Follow> unFollow = followRepository.findAll();
//then
assertThat(unFollow.contains(follow)).isEqualTo(false);
}
Member memberA() {
Member memberA = Member.builder()
.name("memberA")
.email("member@duksung.ac.kr")
.nickname("memberNickname")
.password("1111")
.phone("010-0000-0000")
.university("덕성대학교")
.build();
memberRepository.save(memberA);
return memberA;
}
Member memberB() {
Member memberB = Member.builder()
.name("memberB")
.email("member@kookmin.ac.kr")
.nickname("Nickname")
.password("1111")
.phone("010-0000-0000")
.university("국민대학교")
.build();
memberRepository.save(memberB);
return memberB;
}
}
@BeforeEach
각각의 테스트 메소드 실행 전에 실행
List<Follow> followList = followRepository.findAll();
Follow follow = followList.get(followList.size()-1);
assertThat(follow.getFromMemberId().getId()).isEqualTo(memberA.getId());
사실 이 부분에서 이렇게 비교하는게 아니라 followRepository에 jpa쿼리메소드 형식으로 findByFromMemberIdAndToMemberId로 메소드를 만들려고 했었다.
그런데 테스트에서만 사용할 메소드를 실제 우리 서비스에 올라갈 코드에 넣는 건 아니라고 생각해서 테스트 클래스 안에서 extends FollowRepository로 클래스 하나 만들어서 메소드 집어넣었는데 안 돌아간다. 뭐지...? 배움의 부족인 것 같다 더 공부하는 걸로...
코드 깃헙 주소 https://github.com/JMine97/vine
참고 강의 https://www.easyupclass.com/course/218/about
'프로젝트 > 만남형 SNS' 카테고리의 다른 글
6 회원 프로필 사진 올리기 (0) | 2021.06.22 |
---|---|
4 회원정보수정 (0) | 2021.06.05 |
3 로그인 (0) | 2021.06.05 |
2 회원가입 (0) | 2021.06.05 |
1 기획 및 DB스키마 (0) | 2021.06.03 |