Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#43 ] 게시글의 추천, 비추천 기능 구현 #54

Merged
merged 3 commits into from
Sep 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions src/main/java/com/nooblol/board/controller/ArticleController.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,41 @@ public ResponseDto deleteArticle(
return CommonUtils.makeToResponseOkDto(deleteResult);
}


/**
* 파라미터로 제공한 게시물의 추천, 비추천 갯수를 Return한다
*
* @param articleId
* @return
*/
@GetMapping("/status/{articleId}")
public ResponseDto likeAndNotLikeArticle(@PathVariable int articleId) {
return CommonUtils.makeToResponseOkDto(articleService.likeAndNotListStatus(articleId));
}

/**
* 게시물 추천
*
* @param articleId
* @param session
* @return
*/
@UserLoginCheck
@GetMapping("/like/{articleId}")
public ResponseDto likeArticle(@PathVariable int articleId, HttpSession session) {
return CommonUtils.makeToResponseOkDto(articleService.likeArticle(articleId, session));
}

/**
* 게시물 비추천
*
* @param articleId
* @param session
* @return
*/
@UserLoginCheck
@GetMapping("/notLike/{articleId}")
public ResponseDto notLikeArticle(@PathVariable int articleId, HttpSession session) {
return CommonUtils.makeToResponseOkDto(articleService.notLikeArticle(articleId, session));
}
}
30 changes: 30 additions & 0 deletions src/main/java/com/nooblol/board/dto/ArticleStatusDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.nooblol.board.dto;

import java.time.LocalDateTime;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ArticleStatusDto {

private int articleId;

private String userId;

//True : 추천 , False : 비추천
private boolean type;

private LocalDateTime createdAt;


public void setCreatedAtNow() {
setCreatedAt(LocalDateTime.now());
}
}
19 changes: 19 additions & 0 deletions src/main/java/com/nooblol/board/dto/LikeAndNotLikeResponseDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.nooblol.board.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class LikeAndNotLikeResponseDto {

private int likeCnt;
private int notLikeCnt;

}
32 changes: 32 additions & 0 deletions src/main/java/com/nooblol/board/mapper/ArticleMapper.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.nooblol.board.mapper;

import com.nooblol.board.dto.ArticleDto;
import com.nooblol.board.dto.ArticleStatusDto;
import com.nooblol.board.dto.LikeAndNotLikeResponseDto;
import org.apache.ibatis.annotations.Mapper;

@Mapper
Expand All @@ -19,4 +21,34 @@ public interface ArticleMapper {
String selectCreatedUserId(int articleId);

int deleteArticleByArticleId(int articleId);

/**
* 특정 사용자가 해당글에 추천, 비추천 를 하였는지 확인하기 위함.
*
* @param articleStatusDto
* @return
*/
ArticleStatusDto selectArticleStatusByArticleIdAndUserId(ArticleStatusDto articleStatusDto);

/**
* 파라미터로 제공한 게시물의 총 추천, 비추천 수를 Return한다
*
* @param articleId
* @return
*/
LikeAndNotLikeResponseDto selectArticleAllStatusByArticleId(int articleId);

int insertArticleStatus(ArticleStatusDto articleStatusDto);

/**
* 게시물의 추천, 비추천 에 대한 데이터를 삭제한다.
* <p>
* int의 Default값은 0이 들어가나 articleId의 경우에는 1부터 사용하기 떄문에 ArticleId를 설정안하면 아무 데이터도 삭제가 되지 않기 떄문에 문제가
* 없다.
*
* @param articleStatusDto
* @return
*/
int deleteArticleStatue(ArticleStatusDto articleStatusDto);

}
28 changes: 28 additions & 0 deletions src/main/java/com/nooblol/board/service/ArticleService.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.nooblol.board.service;

import com.nooblol.board.dto.ArticleDto;
import com.nooblol.board.dto.LikeAndNotLikeResponseDto;
import javax.servlet.http.HttpSession;

public interface ArticleService {
Expand Down Expand Up @@ -48,10 +49,37 @@ public interface ArticleService {

/**
* 게시물 삭제, 요청자가 관리자인 경우 또는 글 작성자인 경우에만 삭제를 진행한다.
* Delete를 진행하는 경우 관련 테이블에 대해서도 삭제가 이뤄지다 보니, Transaction으로 묶어 처리를 진행한다
*
* @param articleId
* @param session
* @return
*/
boolean deleteArticle(int articleId, HttpSession session);

/**
* 게시물 추천
*
* @param articleId
* @param session 한개의 Article에 한번만 추천또는 비추천이 가능하며, 재요청이 들어온 경우 Delete처리를 하기위함.
* @return
*/
boolean likeArticle(int articleId, HttpSession session);

/**
* 게시물 비추천
*
* @param articleId
* @param session 한개의 Article에 한번만 추천또는 비추천이 가능하며, 재요청이 들어온 경우 Delete처리를 하기위함.
* @return
*/
boolean notLikeArticle(int articleId, HttpSession session);

/**
* 해당 ArticleId의 좋아요 갯수와 싫어요 갯수를 Return한다.
*
* @param articleId
* @return
*/
LikeAndNotLikeResponseDto likeAndNotListStatus(int articleId);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.nooblol.board.service.impl;

import com.nooblol.board.dto.ArticleDto;
import com.nooblol.board.dto.ArticleStatusDto;
import com.nooblol.board.dto.LikeAndNotLikeResponseDto;
import com.nooblol.board.service.ArticleService;
import com.nooblol.board.mapper.ArticleMapper;
import com.nooblol.board.utils.ArticleAuthMessage;
Expand All @@ -12,6 +14,8 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

@Slf4j
Expand All @@ -23,7 +27,7 @@ public class ArticleServiceImpl implements ArticleService {

@Override
public ArticleDto getArticleInfo(int articleId, String userId) {
articleMapper.addReadCount(articleId);
addReadCount(articleId);
ArticleDto result = articleMapper.selectArticleByArticleId(articleId);

if (ObjectUtils.isEmpty(result)) {
Expand Down Expand Up @@ -79,6 +83,7 @@ public int getNewArticleId() {
}

@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public boolean deleteArticle(int articleId, HttpSession session) {
ArticleDto haveArticleData = articleMapper.selectArticleByArticleId(articleId);

Expand All @@ -101,6 +106,35 @@ public boolean deleteArticle(int articleId, HttpSession session) {
return isArticleDeleteSuccess(articleId);
}

@Override
public boolean likeArticle(int articleId, HttpSession session) {
validatedNotHaveArticle(articleId);

ArticleStatusDto requestArticleStatusDto =
createArticleStatusDto(
articleId, SessionUtils.getSessionUserId(session), true
);

return statusProcess(requestArticleStatusDto);
}

@Override
public boolean notLikeArticle(int articleId, HttpSession session) {
validatedNotHaveArticle(articleId);

ArticleStatusDto requestArticleStatusDto =
createArticleStatusDto(
articleId, SessionUtils.getSessionUserId(session), false
);

return statusProcess(requestArticleStatusDto);
}

@Override
public LikeAndNotLikeResponseDto likeAndNotListStatus(int articleId) {
return articleMapper.selectArticleAllStatusByArticleId(articleId);
}

/**
* Upsert가 정상적으로 진행된 경우 True를 Return한다.
*
Expand Down Expand Up @@ -128,12 +162,65 @@ private boolean isUserAdmin(int userRole) {
}

/**
* 게시글을 삭제하며, 정상적으로 삭제가 되면 True, 삭제된 건수가 없으면 False를 Return한다
* 먼저 추천, 비추천에 대한 기록도 모두 삭제하며,
* <p>
* 이후 게시글을 삭제하며, 정상적으로 삭제가 되면 True, 삭제된 건수가 없으면 False를 Return한다
*
* @param articleId
* @return
*/
private boolean isArticleDeleteSuccess(int articleId) {
articleMapper.deleteArticleStatue(
new ArticleStatusDto().builder().articleId(articleId).build()
);

return articleMapper.deleteArticleByArticleId(articleId) == 0 ? false : true;
}


private boolean isNotArticleInDb(int articleId) {
return ObjectUtils.isEmpty(articleMapper.selectArticleByArticleId(articleId));
}

private void validatedNotHaveArticle(int articleId) {
if (isNotArticleInDb(articleId)) {
throw new IllegalArgumentException(ExceptionMessage.BAD_REQUEST);
}
}

private ArticleStatusDto createArticleStatusDto(int articleId, String userId, boolean type) {
ArticleStatusDto articleStatusDto = new ArticleStatusDto().builder()
.articleId(articleId)
.userId(userId)
.type(type)
.build();

articleStatusDto.setCreatedAtNow();

return articleStatusDto;
}

/**
* 추천, 비추천에 대한 프로세스, 해당 게시물에 대해 사용자가 좋아요가 없는 경우 Insert 이미 같은 타입(추천, 비추천)을 한경우는 삭제, 다른 타입인 경우는
* Exception이 발생한다
*
* @param requestArticleStatusDto
* @return
*/
private boolean statusProcess(ArticleStatusDto requestArticleStatusDto) {
ArticleStatusDto IsHaveStatusData = articleMapper.selectArticleStatusByArticleIdAndUserId(
requestArticleStatusDto);

if (ObjectUtils.isEmpty(IsHaveStatusData)) {
return articleMapper.insertArticleStatus(requestArticleStatusDto) > 0 ? true : false;
}

if (IsHaveStatusData.isType() != requestArticleStatusDto.isType()) {
throw new IllegalArgumentException(ExceptionMessage.BAD_REQUEST);
}

return articleMapper.deleteArticleStatue(requestArticleStatusDto) > 0 ? true : false;
}


}
13 changes: 12 additions & 1 deletion src/main/resources/data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,15 @@ VALUES (1, 1, 'Test Article Title - 1', 0, '내용이웨요', 1, 'test-admin-use
INSERT INTO bbs_articles(article_id, bbs_id, article_title, article_read_count, article_content,
status,
created_user_id, created_at, updated_at)
VALUES (2, 1, 'Test Article Title - 22', 0, '내용이웨요22', 1, 'test', now(), now());
VALUES (2, 1, 'Test Article Title - 22', 0, '내용이웨요22', 1, 'test', now(), now());



INSERT INTO bbs_articles_status (article_id, user_id, type, created_at)
VALUES (1, 'test', true, now());

INSERT INTO bbs_articles_status (article_id, user_id, type, created_at)
VALUES (1, 'test2', true, now());

INSERT INTO bbs_articles_status (article_id, user_id, type, created_at)
VALUES (1, 'test3', false, now());
37 changes: 37 additions & 0 deletions src/main/resources/mybatis/mapper/board/ArticleMapper.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,41 @@
WHERE article_id = #{articleId}
</delete>

<select id="selectArticleStatusByArticleIdAndUserId" parameterType="ArticleStatusDto"
resultType="ArticleStatusDto">
SELECT article_id, user_id, type, created_at
FROM bbs_articles_status
WHERE article_id = #{articleId}
AND user_id = #{userId}
</select>

<select id="selectArticleAllStatusByArticleId" parameterType="int"
resultType="LikeAndNotLikeResponseDto">
SELECT (SELECT count(user_id)
FROM bbs_articles_status
WHERE article_id = #{articleId}
AND type = 1) as likeCnt,
(SELECT count(user_id)
FROM bbs_articles_status
WHERE article_id = #{articleId}
AND type = 0) as notLikeCnt
FROM DUAL;

</select>

<insert id="insertArticleStatus" parameterType="ArticleStatusDto">
INSERT INTO bbs_articles_status(article_id, user_id, type, created_at)
VALUES (#{articleId}, #{userId}, #{type}, #{createdAt})
</insert>


<delete id="deleteArticleStatue" parameterType="ArticleStatusDto">
DELETE
FROM bbs_articles_status
WHERE article_id = #{articleId}
<if test="userId != null and userId != ''">
AND user_id = #{userId}
</if>
</delete>

</mapper>
6 changes: 4 additions & 2 deletions src/main/resources/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,14 @@ CREATE TABLE `bbs_articles`
`updated_at` datetime
);

/*
22. 09. 09 BBSID컬럼 삭제 : articleId로 추적이 가능하기 떄문에 해당 테이블에서는 꼭 필요하지 않다 판단.
*/
CREATE TABLE `bbs_articles_status`
(
`article_id` int,
`bbs_id` varchar(255),
`user_id` varchar(255),
`type` tinyint,
`type` tinyint(1),
`created_at` datetime DEFAULT (now())
);

Expand Down
Loading