나는 현재 치과 기록 및 커뮤니티로 치아 건강을 관리하는 서비스 투스데이 백엔드 개발 중 커뮤니티 기능 대부문을 맡아서 개발하고 있다.
그런데, 커뮤니티 기능을 모두 개발하고 전체 api 테스트를 해보던 와중 좋아요 취소 부분에서 에러가 발생했다.
"timestamp": "2024-07-14T04:00:10.191+00:00",
"status": 500,
"error": "Internal Server Error",
"trace": "org.springframework.dao.IncorrectResultSizeDataAccessException: query did not return a unique result: 2; nested exception is javax.persistence.NonUniqueResultException: query did not return a unique result: 2\\r\\n\\tat org.springframework.orm.jpa.
내용을 보니 query did not return a unique result 하나만 정의되어있어야 하는 값이 중복되어 있는 것 같다.
db를 살펴보니 역시나 한 명의 유저가 하나의 게시글에 좋아요를 두번 눌러 버렸다.
직전에 좋아요 등록 테스트를 할 때 같은 정보로 2번 눌렸고 아무런 저항 없이 새로운 좋아요가 생성되어 버린 것이다.
@PostMapping("/api/community/{postId}/like")
public ResponseEntity<String> like(@PathVariable Long postId,
HttpServletRequest request) {
String token = request.getHeader("Authorization").replace("Bearer ", "");
Long userId = JwtUtil.getUserIdFromToken(token);
User user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("User not found"));
Post post = postRepository.findById(postId);
PostLike like = new PostLike();
like.setUser(user);
like.setPost(post);
likeService.save(like);
return ResponseEntity.ok("Like successful");
}
@DeleteMapping("/api/community/{postId}/like")
public ResponseEntity<String> unlike(@PathVariable Long postId, HttpServletRequest request) {
String token = request.getHeader("Authorization").replace("Bearer ", "");
Long userId = JwtUtil.getUserIdFromToken(token);
Post post = postRepository.findById(postId);
PostLike like = likeService.findByPostIdAndUserId(postId, userId);
if(like!=null) {
likeService.delete(like);
return ResponseEntity.ok("Like Delete successful");
} else {
return ResponseEntity.ok("Like not found");
}
}
내가 작성한 좋아요 등록, 취소 api이다.
public PostLike findByPostIdAndUserId(long postId, long userId) {
try {
return em.createQuery("select pl from PostLike pl where pl.post.id=:postId and pl.user.id=:userId", PostLike.class)
.setParameter("postId", postId)
.setParameter("userId", userId).getSingleResult();
} catch (NoResultException e) {
return null;
}
}
당연하게도 유저 한 명당 게시글 하나에 좋아요를 한번만 누를 수 있다고 생각하였고 postId와 userId를 사용해서 좋아요를 찾아내고 삭제하도록 설계하였다.
그리고 위와 같이 좋아요가 2개 이상 생성되어 있으니 삭제할 수 없는 문제가 발생한 것이다.
생각해보니 좋아요는 등록/취소 api를 따로 설계하지 말고
하나의 api만으로 좋아요가 눌려있다면 → 취소, 좋아요가 눌려있지않다면 → 등록 이렇게 로직을 짜주면 될 것 같았다.
@PostMapping("/api/community/{postId}/like")
public ResponseEntity<String> like(@PathVariable Long postId, HttpServletRequest request) {
String token = request.getHeader("Authorization").replace("Bearer ", "");
Long userId = JwtUtil.getUserIdFromToken(token);
User user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("User not found"));
Post post = postRepository.findById(postId);
PostLike isLiked = likeService.findByPostIdAndUserId(postId, userId);
if (isLiked == null) {
PostLike postLike = new PostLike();
postLike.setPost(post);
postLike.setUser(user);
likeService.save(postLike);
return ResponseEntity.ok("Like successful");
}
else {
likeService.delete(isLiked);
return ResponseEntity.ok("Like Deleted successful");
}
}
성공하였다!
'프로젝트' 카테고리의 다른 글
[공모전][제3회 DGB금융그룹 IT's DGB iM Challenger] 대한민국 디지털 인재 양성 프로젝트 < 발대식 및 본선 대회 > 회고 (1) | 2025.01.27 |
---|---|
JPA 페이징 처리 기법에 대해, 어느 방법이 내 프로젝트에 적격일까? (1) | 2024.09.07 |
[투스데이] 데이터베이스 외래 키 제약 조건 오류 해결 (1) | 2024.08.07 |
[마잇(MyEat)] 주요 기능 정리, 도메인 모델 설계 (0) | 2024.04.12 |
[마잇(MyEat)] jpa 연관관계 공부하기 (0) | 2024.04.06 |