프로젝트 기간: 2024.11 - 2024.12
역할: 백엔드
언어: Java
프레임워크: SpringBoot
참고문헌: 스프링 부트와 AWS로 혼자 구현하는 웹 서비스
담당 구현 기능:
- 책 실습 내용 기반 게시판 CRUD 서비스
- 좋아요 기능
기능 소개
- 좋아요 하트 버튼 최초 클릭 시(좋아요 등록 시) Like_Table에 좋아요가 등록되고 해당 좋아요의 liked값이 true가 된다.
- 좋아요 취소 시 Like_Table에 등록되었던 좋아요의 liked값이 false가 된다.
- 다시 해당 글에 좋아요를 클릭 시 좋아요의 liked값이 true가 된다.
핵심 코드
1. 테이블 매핑
- ERD기반 Posts, Like_Table, User테이블 매핑
- Posts, Like_table 1:N mapping
- User, Like_table 1:N mapping
- User, Posts 1:N mapping
//posts에게 참조함
public class User extends BaseTimeEntity {
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
//한 명의 유저 여러 개의 게시글
private List<Posts> posts=new ArrayList<>();
//POSTS 담을 arraylist 필요
//user로부터 참조받음
public class Posts extends BaseTimeEntity{
@ManyToOne(fetch = FetchType.LAZY)
//여러 개의 게시글 한 명의 유저
//fetch: user가 로드될 때 posts 리스트 즉시 로드되지 않음. 필요할 때 로드됨
@JoinColumn(name="user_id")
//참조할 때 컬럼명
private User user;
// user 가져오기
2. 좋아요 기능
- LikeService
- toggleLike: 좋아요를 클릭하면 Like_Table의 liked 값을 true↔false로 바꾸는 기능
- isLiked: 현재 좋아요 상태 확인
package com.jojoldu.book.springboot.service.like;
import com.jojoldu.book.springboot.domain.posts.Posts;
import com.jojoldu.book.springboot.domain.user.User;
import com.jojoldu.book.springboot.domain.like.Like_Table;
import com.jojoldu.book.springboot.domain.like.LikeRepository;
import com.jojoldu.book.springboot.service.posts.PostsService;
import com.jojoldu.book.springboot.service.user.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@RequiredArgsConstructor
@Service
public class LikeService {
private final LikeRepository likeRepository;
private final PostsService postsService;
private final UserService userService;
@Transactional
public Long toggleLike(Long post_id, String username) {
Posts posts = postsService.findById(post_id).toEntity();
User user = userService.findByUsername(username).toEntity();
Like_Table likeEntity = likeRepository.findByPostsAndUser(posts, user)
.orElse(null);
if (likeEntity == null) {
likeEntity = Like_Table.builder()
.posts(posts)
.user(user)
.liked(true) // 처음에는 false로 생성됨
.build();
likeRepository.save(likeEntity);
} else {
likeEntity.update(!likeEntity.isLiked());
}
return likeEntity.getLike_id();
}
// 좋아요 상태 확인
public boolean isLiked(Long post_id, String username) {
Posts post = postsService.findById(post_id).toEntity();
User user = userService.findByUsername(username).toEntity();
Like_Table likeEntity = likeRepository.findByPostsAndUser(post, user)
.orElse(null);
return likeEntity != null && likeEntity.isLiked();
}
}
- PostsApiController
//좋아요 상태 확인 ------
@GetMapping("/{id}/like")
public boolean getLikeStatus(@PathVariable Long id) {
SessionUser sessionUser = (SessionUser) httpSession.getAttribute("user");
if (sessionUser != null) {
String username = sessionUser.getName();
return likeService.isLiked(id, username);
}
return false; //로그인 X
}
@PutMapping("/{id}/like")
public ResponseEntity<Long> toggleLike(@PathVariable Long id) {
String username = null;
SessionUser sessionUser = (SessionUser) httpSession.getAttribute("user");
if (sessionUser != null) {
username = sessionUser.getName();
}
Long likeId = likeService.toggleLike(id, username);
// 상태 변경 후 like_id 반환
return ResponseEntity.ok(likeId);
}
트러블슈팅
- 좋아요 취소 에러
- 상황: 첫 번째 좋아요 정상 등록, 첫 번째 좋아요 정상 취소, 두 번째 좋아요 정상 등록, 두 번째 좋아요 취소 에러
Hibernate: select like_table0_.like_id as like_id1_0_0_, like_table0_.created_date as created_2_0_0_, like_table0_.modified_date as modified3_0_0_, like_table0_.post_id as post_id4_0_0_, like_table0_.user_id as user_id5_0_0_ from like_table like_table0_ where like_table0_.like_id=?
2024-12-04 03:12:29.548 ERROR 39685 --- [nio-8080-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: 해당 좋아요가 없습니다. id=1] with root cause
java.lang.IllegalArgumentException: 해당 좋아요가 없습니다. id=1
- 에러 발생 이유 추측
- 좋아요 등록이랑 취소가 경로가 둘다 "/api/v1/posts" 뒤에 추가적으로 붙은 게 없어서 중간에 혼동이 생겼을 가능성
→ 좋아요 등록 메소드 post로 변경하고 경로도 /api/v1/posts/{id}/like, /api/v1/posts/{id}/unlike로 각각 수정한 뒤에 실행해도 같은 오류 발생 - Like_Table과 Post 테이블 간의 참조 관계로 인한 오류
- index.mustache에서 좋아요 버튼 id = 게시글 id로 사용 중, 즉 data-like-id가 게시글 번호와 같은 변수를 가리키고 있어서 문제가 발생할 가능성도 있음
- 좋아요 등록이랑 취소가 경로가 둘다 "/api/v1/posts" 뒤에 추가적으로 붙은 게 없어서 중간에 혼동이 생겼을 가능성
- 우회하여 해결한 방법
- like_table에 boolean liked값 추가해서 true false로 좋아요 여부 구분
- 좋아요 등록, 취소 모두 PUT 사용
깃허브 주소
'Project' 카테고리의 다른 글
[React]대학생을 위한 설문조사 중개 서비스, 썰매 (0) | 2025.01.30 |
---|---|
[AWS, Angular]두부 생산 불량품 검출 시스템 (0) | 2025.01.28 |
[AWS]AWS 이용해 AI 챗봇 만들기: 텔레그램에서 chat-GPT와 대화하는 법 (0) | 2023.09.16 |