Project/Coffee Board

[Coffee Board] 게시판 구현 2 - 좋아요(Like) 기능

한비Skyla 2024. 7. 17. 09:03

✏️ 고려사항

  • 질문 글에 '좋아요' 추가. 
  • 한 건의 질문에 '좋아요' 한번만 추가. 
  • 좋아요 눌렀다가 한 번 또 누르면 좋아요 취소
  • 취소된 좋아요는 DB에서 삭제
  • 질문글에 좋아요 개수 표시 

☘️ 구현내용

board 에 추가 해야 함. like는 객체와 상태를 저장할 repository 만 필요. 

좋아요를 누른다 > service 로직 create like, control 로직 post like. 

 

- Controller

1. board id 를 받아서 board 확인.

2. 좋아요를 누르는 사람이 누구인지 member id 는 dto로 받음. --- context  authentication. 

3. 좋아요 만들기. service 로직. 

4. 리턴은 성공했다만 보내도 될 듯. 

 

- Service

* 여기가 진짜 어려웠음. 

1. 좋아요하면서 받은 board 와 member 가 유효한지 확인해야 함. 

2. board 에 like 가 없으면 만들어야 함. DB에 저장.

// 비정규화.

3. 동시에 count 증가 시키면서 board 와 member 저장. 보드에도 like 저장. 서로 영향을 주어야 되니까 cascade. 

4. board 에 like 가 있으면 지워줘야 함. DB에도 지워야 함. 

5. ⭐️ 지울 때, cascade 해서 같이 저장되어 있는 board 의 like 도 지워야 함.⭐️  !!!!!!!!!!!!!!!!!!!!!!!!!!!

6. 동시에 count도 1 내려야 함. 이 상태는 board 에서 가지고 있음. 

 

- Repository

* 안 건드려도 되는 줄 알았지만. 쿼리메서드를 활용해서 verify 를 repository 에서 할 수 있는 게 있음..!!! 

findBy + 컬럼명을 사용하면 컬럼명과 일치하는 데이터를 찾는 조건을 추가함. 

1. board 와 member 를 받아서, 일치하는 like 만 데리고 와라. 

2. DB에서 가지고 올 때는 Optional 임. 

Optional<Like> findByMemberAndBoard(Member member, Board board);

 

 

[Java] Spring Boot Jpa findBy 단일, 여러개 조건 검색 사용법

Spring Data Jpa 쿼리 메소드란?Spring-data-jpa의 JpaRepository는 메소드 이름 규칙에 따라 쿼리를 만들어주는 기능이 있습니다.쿼리 메소드 기능을 사용해서 AND 조건, OR 조건 등 여러 조건을 사용해서 쿼

priming.tistory.com

 

JPA로 원하는 매개변수로 findBy 메소드 생성하기

기본제공 findById(PK) 메소드 public Optional getMember(Long idx) { return memberRepository.findById(idx); } JPA에서 ID값을 파라미터로 SELECT 할 수 있는 기본 findById 메소드를 제공한다. 하지만 ID 필드가 아닌 다른 여

devfunny.tistory.com

 

🔎 코드작성 

<Like Entity>

@Getter
@Setter
@NoArgsConstructor
@Entity
@Table(name = "likes")
public class Like {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long likeId;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "BOARD_ID")
    private Board board;
    public void setBoard (Board board) {
        this.board = board;
        if(board.getLike() != this) {
            board.setLike(this);
        }
    }
    
    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "MEMBER_ID")
    private Member member;
    public void setMember (Member member) {
        this.member = member;
        if(!member.getLikes().contains(this)) {
            member.setLikes(this);
        }
    }

 

  • @Table (name = "likes")
    • like 는 Table 에서 예약어임. !! 바꿔주어야 함. 
  • Member, Board 받기. 
    • cascade 는 값을 받아야 하는 쪽에서 구현하기.
    • 한 Member 당 Like 는 여러 개 달 수 있음. Member -일-다- Like 관계. 
    • 한 보드에 한 멤버는 Like 를 Board 를 달 수 있음. Like -일-일- Board 관계.

 

 

<LikeRepository>

public interface LikeRepository extends JpaRepository<Like, Long> {
    Optional<Like> findByMemberAndBoard(Member member, Board board);
}
  • 해당하는 member 와 board 에 맞는 like 를 데리고 와라. 

 

<BoardService>

  • like는 board에서 추가와 삭제를 하기 때문에 BoardService 에서 해야 함. 
  • 버튼을 누르면 해당 경로에 맞는. 요청을 수행하게 됨. html. 
public void createLike (long boardId, Authentication authentication) {

        // like 를 할 boardId 를 가지고 와서 board 를 데리고 옴. 
        Optional<Board> board = boardRepository.findById(boardId);
        Board findBoard = board.orElseThrow(() 
                  -> new BusinessLogicException(ExceptionCode.BOARD_NOT_FOUND));
        // 받은 authentication의 principal 로 member 를 데리고 옴. 
        Optional<Member> member = memberRepository
                             .findByEmail((String) authentication.getPrincipal());
        Member findMember = member.orElseThrow(() 
                  -> new BusinessLogicException(ExceptionCode.MEMBER_NOT_FOUND));
        // 찾아놓은 board 와 member 로 like 를 가지고 옴.  
        Optional<Like> findLike = likeRepository
                              .findByMemberAndBoard(findMember, findBoard);
        // 찾아놓은 like 가 있으면. 
        if( findLike.isPresent()) {
            // delete 를 해라.
            Like deleteLike = findLike.orElseThrow (() 
                      -> new BusinessLogicException(ExceptionCode.LIKE_EXISTS));
            findBoard.decreaseCount();
            boardRepository.save(findBoard);
        } else {
            // like 가 없으면 like 를 더함. 
            Like addlike= new Like();
            addlike.setBoard(findBoard);
            addlike.setMember(findMember);
            findBoard.increasedCount();
            likeRepository.save(addlike);
        }
    }
  • cascade 로 member 와 board 를 엮어 놨기 때문에 add 를 하면 자동으로 board 와 member 에 영향을 미침.
  • 추가는 가능하지만, 삭제도 따로 메서드를 만들어 주어야 함. 

<Like Entity> 추가

    public void deleteBoard (Board board) {
        this.board = null;
        if(board.getLike() == this) {
            board.deleteLike(this);
        }
    }
    public void deleteMember (Member member) {
        this.member = null;
        if(member.getLikes().contains(this)) {
            member.deleteLikes(this);
        }
    }
  • board 에 like 가 있으면, delete like 를 하는데, board 에 null 을 저장한다. 
  • member 에 like 가 있으면, delete like 를 하는데, member 에 null 을 저장한다.