게시글에 좋아요 기능 추가

안민기·2023년 12월 1일

좋아요 기능의 경우 처음엔 그냥 put으로 호출해서 변수를 +1 올려주면 끝이라고 생각했는데 생각해보니 중복 추천 방지, 추천 글 표시 등의 기능을 위해 사용자들의 추천 내역을 기록해야 했다.

Likes.java (entity)

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@EntityListeners(AuditingEntityListener.class)
@Table(name = "likes")
 public class Likes {
	@Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
      
	
	@Column(name="post_id")
	private Long postId;
	
	@Column(name="user_id")
	private Long userId;
	
	@Builder
	public Likes(Long post_id, Long user_id)
	{
		this.postId = post_id;
		this.userId = user_id;
	}
}

게시글(일기)의 고유 id와 사용자의 id값을 함께 저장하는 테이블을 만들어서 처리하기로 했다.

LikesDTO.java

package com.mydiary.my_diary_server.dto;

import com.mydiary.my_diary_server.domain.Likes;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@Getter
public class LikesDTO {
	private Long postId;
	private Long userId;
	
	public LikesDTO(long post_id, long user_id)
	{
		this.postId = post_id;
		this.userId = user_id;
	}
	
	public Likes toEntity(Likes like)
	{
		return Likes.builder()
				.postId(like.getPostId())
				.userId(like.getUserId())
				.build();
	}
}

당연히 Likes 테이블의 고유값을 넘겨줄 필요는 없으므로 DTO에서는 해당 부분을 제외하고 작성했다.

이제 좋아요 요청이 들어오면 해당 테이블을 질의해서 기록이 없을경우 +1, 기록이 있을경우 추천수를 -1 해주고 테이블을 삭제하면 된다.

똑같은 로직으로 해당 게시글에 유저가 좋아요를 눌렀는지 확인해주는 기능 또한 구현을 했다. 좋아요 내역이 있을경우 1, 아닐경우 0으로 값을 리턴해준다.

DiaryService.recommend

    
    public void recommend(LikesDTO dto)
    {
    	Likes likes = likesRepository.findByUserIdAndPostId(dto.getUserId(), dto.getPostId());
    	Diary article = diaryRepository.findById(dto.getPostId())
    			.orElseThrow(() -> new IllegalArgumentException("not found : " + dto.getPostId()));
    		
    	if(likes == null)
    	{
    		article.recommend(true);
    		likesRepository.save(new Likes(dto.getPostId(), dto.getUserId()));
    	}
    		
    	else
    	{
    		article.recommend(false);
    		likesRepository.delete(likes);
    	}
    }
    

DiaryService.checkLike

   
    public Integer checkLike(String author, Long id)
    {
    	Likes like = likesRepository.findByUserIdAndPostId(Long.parseLong(author), id);
    	if(like != null)
    		return 1;
    	else
    		return 0;
    }

LikesRepository

@Repository
public interface LikesRepository extends JpaRepository<Likes, Long> {	
	Likes findByUserIdAndPostId(Long user_id, Long post_id);
}

질의 시 게시글의 id와 사용자의 id를 함께 질의해야해서 어떤식으로 구현할 지 고민했는데 알고보니 JpaRepository에서 다중질의 또한 Specification을 제공해주고 있었다. 함수명을 만들 때 And나 Or을 넣어서 질의를 원하는 변수명을 넣어주면 알아서 질의문을 만들어 준다.

Controller의 일부 코드

    
    @PutMapping("/recommend/{id}")
    @Operation(summary="공감")
    public void recommendDiary(@PathVariable long id, Principal principal)
    {
    	LikesDTO like = new LikesDTO(id, Long.parseLong(principal.getName()));
    	diaryService.recommend(like);
    }
    
    @GetMapping("/recommend/{id}")
    @Operation(summary="공감확인")
    public Integer recommendCheck(@PathVariable long id, Principal principal)
    {
    	return diaryService.checkLike(principal.getName(), id);
    }

엔드포인트는 똑같이 해주고 Get과 Put으로 추천기능과 추천확인 요청을 할 수 있도록 구현해놨다. 게시글의 id는 애초에 요청할 때 받게 해놓았고 사용자의 id는 스프링시큐리티의 Principal 객체를 이용해서 받을 수 있다.

profile
개발 블로그

0개의 댓글