게시글 좋아요 기능 설게 - ttasjwi/board-system GitHub Wiki
게시글 좋아요/싫어요 기능 개요
- 사용자는 게시글에 좋아요/싫어요 할 수 있다.
- 사용자 당 한번씩 가능하다.
- 좋아요/싫어요 하면 좋아요수, 싫어요수가 1 증가한다.
- 게시글 카테고리 정책상 좋아요/싫어요 불가능하다면 불가능하다.
데이터베이스 테이블 설계
좋아요 테이블
CREATE TABLE IF NOT EXISTS article_likes(
article_like_id BIGINT NOT NULL PRIMARY KEY,
article_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
created_at DATETIME NOT NULL,
CONSTRAINT uq_article_id_and_user_id UNIQUE (article_id, user_id)
);
- article_like_id : 식별자
- article_id : 게시글 식별자
- user_id : 사용자 식별자 (누가?)
- created_at: 언제 좋아요했는 지
- 유니크 제약 : (article_id, user_id)
싫어요 테이블
CREATE TABLE IF NOT EXISTS article_dislikes(
article_dislike_id BIGINT NOT NULL PRIMARY KEY,
article_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
created_at DATETIME NOT NULL,
CONSTRAINT uq_article_id_and_user_id UNIQUE (article_id, user_id)
);
- article_dislike_id : id
- article_id : 게시글 id
- user_id : 사용자 id (누가?)
- created_at : 언제 싫어요 했는 지
- 유니크 제약 : (article_id, user_id)
좋아요 수 테이블
CREATE TABLE IF NOT EXISTS article_like_counts(
article_id BIGINT NOT NULL PRIMARY KEY,
like_count BIGINT NOT NULL
);
- article_id : 게시글 id
- like_count : 좋아요 수
싫어요 수 테이블
CREATE TABLE IF NOT EXISTS article_dislike_counts(
article_id BIGINT NOT NULL PRIMARY KEY,
dislike_count BIGINT NOT NULL
);
- article_id : 게시글 id
- dislike_count : 싫어요 수
좋아요 수 테이블을 별도로 분리한 이유
모듈
- 게시글에 대한 좋아요/싫어요 기능을 모듈로 별도 분리하였다. (향후 서비스를 독립시키는 것을 가정)
- 서비스가 따로 분리될 경우, '게시판 서비스', '게시글 서비스' 에 대해 의존이 발생할 수 있다.
- 게시글 카테고리 의존 : 좋아요 가능 여부에 대한 정책 조회가 필요하다. 이 '게시판 서비스'에서 관리된다.
- 게시글 의존 : 대상 게시글의 존재 여부, 게시글의 기본 메타데이터 조회가 필요하다. '게시글 서비스'에서 관리된다.
좋아요(싫어요) 생성 흐름
싫어요 기능은 구조적으로 흐름은 동일하기 때문에 생략한다.
@Transactional
fun like(command: ArticleLikeCreateCommand): ArticleLike {
// 게시글 조회
val article = getArticleOrThrow(command.articleId)
// 게시글 카테고리 조회
val articleCategory = getArticleCategoryOrThrow(article.articleCategoryId)
// 카테고리 정책 확인 (좋아요 금지를 하진 않았는지...?)
checkAllowLike(command.articleId, articleCategory)
// 좋아요 존재 확인 (이미 좋아요했다면, 예외 발생)
checkDuplicateLike(command.articleId, command.likeUser.userId)
// 좋아요 생성 및 저장
val articleLike = createArticleLikeAndSave(command)
// 좋아요수 증가, 수정 반영
upsertArticleLikeCount(command.articleId)
return articleLike
}
- 게시글 조회 : 대상 게시글을 조회해온다.
- 게시글 카테고리 조회 : 게시글의 카테고리 정보를 조회해온다.
- 카테고리 정책 확인 : 카테고리 정책 상, 일반 사용자의 좋아요가 허용되지 않으면 예외 발생
- 중복 좋아요 확인 : 이미 좋아요했는 지 확인
- 좋아요 생성 및 저장
- 좋아요 수 증가, 수정 반영
좋아요(싫어요) 취소 흐름
@Transactional
fun cancelLike(command: ArticleLikeCancelCommand) {
// 게시글 존재여부 확인
checkArticleExists(command.articleId)
// 좋아요 존재 여부 확인
checkArticleLikeExists(command.articleId, command.user.userId)
// 좋아요 제거
removeArticleLike(command.articleId, command.user.userId)
// 좋아요수 감소, 수정 반영
decreaseArticleLikeCount(command.articleId)
}
- 게시글 존재 여부 확인
- 게시글에 대한 좋아요 존재 여부 확인
- 좋아요 제거
- 좋아요수 감소, 수정 반영
좋아요(싫어요)수 조회
override fun readLikeCount(articleId: Long): ArticleLikeCountReadResponse {
checkArticleExists(articleId)
val articleLikeCount = articleLikeCountPersistencePort.findByIdOrNull(articleId)
return ArticleLikeCountReadResponse(
articleId = articleId.toString(),
likeCount = articleLikeCount?.likeCount ?: 0L
)
}
- 게시글 존재여부 확인 : 대상 게시글이 없을 경우 예외를 발생시킨다.
- 좋아요 수 조회 : 데이터베이스를 통해 좋아요 수를 조회해온다.
- 좋아요수가 저장되어 있지 않다면, 아무도 좋아요를 한 게시글이 아니므로 0을 반환한다.
- 좋아요수가 저장되어 있다면, 그 값을 반환한다.