좋아요 기능의 경우 처음엔 그냥 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 객체를 이용해서 받을 수 있다.