코로나가 얼추 나은 줄 알았는데 목이 아직 아프다..
9일차에는 목표 페이지에 누를 수 있는 좋아요 기능을 추가했다.
이전 프로젝트에서 좋아요를 만들 기회가 있었지만, 직접 만들어 본 경험은 이번이 처음이다.
일단은 좋아요 정보를 담는 테이블이 필요하다는 생각이 들었다. 같은 사용자가 좋아요를 여러번 누를 때 좋아요 수가 계속 올라가면 안되기 때문이다.
테이블은 이런 식으로 구성했다.
@Entity
@Table(name = "likes")
class Like(
@ManyToOne(fetch = FetchType.LAZY)
@OnDelete(action = OnDeleteAction.CASCADE)
@JoinColumn(name = "user_id")
val user: User,
@ManyToOne(fetch = FetchType.LAZY)
@OnDelete(action = OnDeleteAction.CASCADE)
@JoinColumn(name = "resolution_id")
val resolution: Resolution
) {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "like_id")
val id: Long? = null
}
user와 resolution을 n대1 관계로 가짐으로써 어떤 사용자가 어떤 resolution에 좋아요를 눌렀는지 확인할 수 있다.
컨트롤러는 아래와 같이 구성했다.
@RestController
@RequestMapping("api/likes")
class LikeController(
private val likeService: LikeService
) {
@PostMapping
fun insertLike(
@RequestBody likeRequest: LikeRequest
): ResponseEntity<Unit>{
return ResponseEntity.ok(likeService.insertLike(likeRequest))
}
@DeleteMapping
fun deleteLike(
@RequestBody likeRequest: LikeRequest
): ResponseEntity<Unit>{
likeService.deleteLike(likeRequest)
return ResponseEntity.noContent().build()
}
}
좋아요를 하는것과 취소하는 건 like 테이블에 데이터를 생성하거나 삭제하는 일이므로 @PostMapping과 @DeleteMapping을 사용했다.
여기서 사용자는 좋아요 버튼을 누르면 좋아요가 +1, 한번 더 누르면 좋아요를 취소하는 방식을 사용했는데, 한 메서드 내에서 처리할 수 있지만 이런 식으로 2개의 api로 분리한 이유가 있다.
일단 분리를 하지 않을 경우, PostMapping 요청 안에 좋아요 추가와 삭제 모두 구현해야 한다. 이는 Restful하지 못한 설계라고 할 수 있다.
아래는 로직이 구현되는 LikeService이다.
@Service
class LikeServiceImpl(
private val userRepository: UserRepository,
private val resolutionRepository: ResolutionRepository,
private val likeRepository: LikeRepository
): LikeService {
@Transactional
override fun insertLike(request: LikeRequest) {
val user = userRepository.findByIdOrNull(request.userId) ?: TODO("예외처리")
val resolution = resolutionRepository.findByIdOrNull(request.resolutionId) ?: TODO("예외처리")
if (!likeRepository.existsByUserAndResolution(user, resolution)){
resolution.updateLikeCount(true)
likeRepository.save(LikeResponse.from(user, resolution))
}
else{
TODO("이미 좋아요를 눌렀을 때")
}
}
@Transactional
override fun deleteLike(request: LikeRequest) {
val user = userRepository.findByIdOrNull(request.userId) ?: TODO("예외처리")
val resolution = resolutionRepository.findByIdOrNull(request.resolutionId) ?: TODO("예외처리")
likeRepository.findByUserAndResolution(user, resolution)
?.let {
resolution.updateLikeCount(false)
likeRepository.delete(it) }
?: TODO("예외처리")
}
}
만약 사용자가 좋아요를 하지 않았을 경우에 (즉, like테이블에 존재하지 않을 경우) Resolution 엔티티에 있는 likeCount를 증가시키는 메서드 updateLikeCount를 실행한다. 이 메서드는 인자가 true일 때 likeCount를 +1, false일 때 likeCount를 -1 한다.
이런 식으로 좋아요 기능을 구현해 봤다. 요즘 컨디션이 안좋아 코드 치는게 죽을맛이다... 역시 건강해지는게 일단은 최우선인것 같다.
'캠프 개발일지' 카테고리의 다른 글
개발일지 - 15일차: 목표 랭킹 알고리즘 수정 및 오류 직면 (2) | 2024.03.14 |
---|---|
개발일지 - 14일차: 랭킹 시스템 구현 (1) | 2024.03.13 |
개발일지 - 8일차: daily Check 추가 (4) | 2024.03.05 |
개발일지 - 3일차: CRUD 및 기본 틀 작성(+kotlin 공부) (0) | 2024.02.28 |
개발일지 - 1일차 : S.A. 작성 및 아이디어 회의 (0) | 2024.02.27 |