diff --git a/src/main/java/com/nooblol/board/controller/ArticleController.java b/src/main/java/com/nooblol/board/controller/ArticleController.java new file mode 100644 index 00000000..8b5d0403 --- /dev/null +++ b/src/main/java/com/nooblol/board/controller/ArticleController.java @@ -0,0 +1,114 @@ +package com.nooblol.board.controller; + +import com.nooblol.board.dto.ArticleDto; +import com.nooblol.board.dto.ArticleInsertRequestDto; +import com.nooblol.board.dto.ArticleUpdateRequestDto; +import com.nooblol.board.service.ArticleService; +import com.nooblol.global.annotation.UserLoginCheck; +import com.nooblol.global.dto.ResponseDto; +import com.nooblol.global.utils.ResponseUtils; +import com.nooblol.global.utils.SessionUtils; +import javax.servlet.http.HttpSession; +import javax.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequestMapping("/article") +@RequiredArgsConstructor +public class ArticleController { + + private final ArticleService articleService; + + /** + * articleId의 게시물 정보와 현재 요청한 사용자의 권한을 같이 Return한다 Session에 로그인정보가 없는 경우에는 게시물에 대한 정보 수정을 주는 권한을 + * Guest로 설정한다 + * + * @param articleId + * @param session + * @return + */ + @GetMapping("/{articleId}") + public ResponseDto getArticle( + @PathVariable int articleId, HttpSession session + ) { + ArticleDto article = articleService.getArticleInfo( + articleId, SessionUtils.getSessionUserId(session) + ); + + return ResponseUtils.makeToResponseOkDto(article); + } + + /** + * 게시물 등록 + * + * @param articleDto + * @return + */ + @UserLoginCheck + @PostMapping("/") + public ResponseDto insertArticle( + @Valid @RequestBody ArticleInsertRequestDto articleDto, HttpSession session + ) { + ArticleDto upsertArticle = new ArticleDto().builder() + .bbsId(articleDto.getBbsId()) + .articleTitle(articleDto.getArticleTitle()) + .articleContent(articleDto.getArticleContent()) + .articleReadCount(articleDto.getArticleReadCount()) + .status(articleDto.getStatus()) + .createdUserId(SessionUtils.getSessionUserId(session)) + .createdAt(articleDto.getCreatedAt()) + .updatedAt(articleDto.getUpdatedAt()) + .build(); + + boolean upsertResult = articleService.upsertArticle(upsertArticle, session, true); + + return ResponseUtils.makeToResponseOkDto(upsertResult); + } + + /** + * 게시물 수정 + * + * @param articleDto + * @return + */ + @UserLoginCheck + @PutMapping("/") + public ResponseDto updateArticle( + @Valid @RequestBody ArticleUpdateRequestDto articleDto, HttpSession session + ) { + ArticleDto upsertArticle = new ArticleDto().builder() + .articleId(articleDto.getArticleId()) + .bbsId(articleDto.getBbsId()) + .articleTitle(articleDto.getArticleTitle()) + .articleContent(articleDto.getArticleContent()) + .status(articleDto.getStatus()) + .build(); + + boolean upsertResult = articleService.upsertArticle(upsertArticle, session, false); + + return ResponseUtils.makeToResponseOkDto(upsertResult); + } + + /** + * 게시물 삭제 + * + * @param articleId + * @param session + * @return + */ + @UserLoginCheck + @DeleteMapping("/{articleId}") + public ResponseDto deleteArticle(@PathVariable int articleId, HttpSession session) { + return ResponseUtils.makeToResponseOkDto(articleService.deleteArticle(articleId, session)); + } +} diff --git a/src/main/java/com/nooblol/board/controller/ArticleStatusController.java b/src/main/java/com/nooblol/board/controller/ArticleStatusController.java new file mode 100644 index 00000000..f1f04e61 --- /dev/null +++ b/src/main/java/com/nooblol/board/controller/ArticleStatusController.java @@ -0,0 +1,61 @@ +package com.nooblol.board.controller; + +import com.nooblol.board.service.ArticleStatusService; +import com.nooblol.global.annotation.UserLoginCheck; +import com.nooblol.global.dto.ResponseDto; +import com.nooblol.global.utils.ResponseUtils; +import javax.servlet.http.HttpSession; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequestMapping("/article/status") +@RequiredArgsConstructor +public class ArticleStatusController { + + private final ArticleStatusService articleStatusService; + + /** + * 파라미터로 제공한 게시물의 추천, 비추천 갯수를 Return한다 + * + * @param articleId + * @return + */ + @GetMapping("/{articleId}") + public ResponseDto likeAndNotLikeArticle(@PathVariable int articleId) { + return ResponseUtils.makeToResponseOkDto(articleStatusService.likeAndNotListStatus(articleId)); + } + + /** + * 게시물 추천 + * + * @param articleId + * @param session + * @return + */ + @UserLoginCheck + @PostMapping("/like/{articleId}") + public ResponseDto likeArticle(@PathVariable int articleId, HttpSession session) { + return ResponseUtils.makeToResponseOkDto(articleStatusService.likeArticle(articleId, session)); + } + + /** + * 게시물 비추천 + * + * @param articleId + * @param session + * @return + */ + @UserLoginCheck + @PostMapping("/notLike/{articleId}") + public ResponseDto notLikeArticle(@PathVariable int articleId, HttpSession session) { + return ResponseUtils.makeToResponseOkDto( + articleStatusService.notLikeArticle(articleId, session)); + } +} diff --git a/src/main/java/com/nooblol/board/dto/ArticleDto.java b/src/main/java/com/nooblol/board/dto/ArticleDto.java new file mode 100644 index 00000000..ba072b55 --- /dev/null +++ b/src/main/java/com/nooblol/board/dto/ArticleDto.java @@ -0,0 +1,32 @@ +package com.nooblol.board.dto; + +import java.sql.Timestamp; +import java.time.LocalDateTime; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ArticleDto { + + /* + Integer로 변경하는 이유는 기본값 0이 들어감으로 인해서 Mybatis에서 NullCheck를 못하는 경우를 제외하기 위해 변경 + */ + + private Integer articleId; + private Integer bbsId; + private String articleTitle; + private int articleReadCount; + private String articleContent; + private Integer status; + private String createdUserId; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; + private String authMessage; +} diff --git a/src/main/java/com/nooblol/board/dto/ArticleInsertRequestDto.java b/src/main/java/com/nooblol/board/dto/ArticleInsertRequestDto.java new file mode 100644 index 00000000..17b26933 --- /dev/null +++ b/src/main/java/com/nooblol/board/dto/ArticleInsertRequestDto.java @@ -0,0 +1,23 @@ +package com.nooblol.board.dto; + +import java.time.LocalDateTime; +import javax.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ArticleInsertRequestDto extends ArticleRequestBaseDto { + + private String createdUserId; + private Integer articleReadCount = 0; + private LocalDateTime createdAt = LocalDateTime.now(); + private LocalDateTime updatedAt = LocalDateTime.now(); +} + diff --git a/src/main/java/com/nooblol/board/dto/ArticleRequestBaseDto.java b/src/main/java/com/nooblol/board/dto/ArticleRequestBaseDto.java new file mode 100644 index 00000000..b6f2ab73 --- /dev/null +++ b/src/main/java/com/nooblol/board/dto/ArticleRequestBaseDto.java @@ -0,0 +1,29 @@ +package com.nooblol.board.dto; + + +import com.nooblol.board.utils.ArticleMessage; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class ArticleRequestBaseDto { + + @NotNull(message = ArticleMessage.BBS_ID_NULL) + private Integer bbsId; + + @NotBlank(message = ArticleMessage.ARTICLE_TITLE_NULL) + private String articleTitle; + + @NotBlank(message = ArticleMessage.ARTICLE_CONTENT_NULL) + private String articleContent; + + @NotNull(message = ArticleMessage.ARTICLE_STATUS_NULL) + private Integer status; +} diff --git a/src/main/java/com/nooblol/board/dto/ArticleStatusDto.java b/src/main/java/com/nooblol/board/dto/ArticleStatusDto.java new file mode 100644 index 00000000..e1866831 --- /dev/null +++ b/src/main/java/com/nooblol/board/dto/ArticleStatusDto.java @@ -0,0 +1,26 @@ +package com.nooblol.board.dto; + +import com.nooblol.board.utils.ArticleLikeStatusEnum; +import com.nooblol.board.utils.ArticleStatusEnum; +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; + + private ArticleLikeStatusEnum likeType; + + private LocalDateTime createdAt = LocalDateTime.now(); +} diff --git a/src/main/java/com/nooblol/board/dto/ArticleUpdateRequestDto.java b/src/main/java/com/nooblol/board/dto/ArticleUpdateRequestDto.java new file mode 100644 index 00000000..08519aa7 --- /dev/null +++ b/src/main/java/com/nooblol/board/dto/ArticleUpdateRequestDto.java @@ -0,0 +1,25 @@ +package com.nooblol.board.dto; + +import com.nooblol.board.utils.ArticleMessage; +import java.time.LocalDateTime; +import javax.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ArticleUpdateRequestDto extends ArticleRequestBaseDto { + + @NotNull(message = ArticleMessage.ARTICLE_ID_NULL) + private Integer articleId; + + + private LocalDateTime updatedAt = LocalDateTime.now(); +} + diff --git a/src/main/java/com/nooblol/board/dto/LikeAndNotLikeResponseDto.java b/src/main/java/com/nooblol/board/dto/LikeAndNotLikeResponseDto.java new file mode 100644 index 00000000..af589573 --- /dev/null +++ b/src/main/java/com/nooblol/board/dto/LikeAndNotLikeResponseDto.java @@ -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; + +} diff --git a/src/main/java/com/nooblol/board/mapper/ArticleMapper.java b/src/main/java/com/nooblol/board/mapper/ArticleMapper.java new file mode 100644 index 00000000..f879a5e6 --- /dev/null +++ b/src/main/java/com/nooblol/board/mapper/ArticleMapper.java @@ -0,0 +1,22 @@ +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 +public interface ArticleMapper { + + ArticleDto selectArticleByArticleId(int articleId); + + void addReadCount(int articleId); + + int selectUserAuth(String userId); + + int upsertArticle(ArticleDto articleDto); + + String selectCreatedUserId(int articleId); + + int deleteArticleByArticleId(int articleId); +} diff --git a/src/main/java/com/nooblol/board/mapper/ArticleStatusMapper.java b/src/main/java/com/nooblol/board/mapper/ArticleStatusMapper.java new file mode 100644 index 00000000..2b744dd8 --- /dev/null +++ b/src/main/java/com/nooblol/board/mapper/ArticleStatusMapper.java @@ -0,0 +1,18 @@ +package com.nooblol.board.mapper; + +import com.nooblol.board.dto.ArticleStatusDto; +import com.nooblol.board.dto.LikeAndNotLikeResponseDto; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface ArticleStatusMapper { + + ArticleStatusDto selectArticleStatusByArticleIdAndUserId(ArticleStatusDto articleStatusDto); + + LikeAndNotLikeResponseDto selectArticleAllStatusByArticleId(int articleId); + + int insertArticleStatus(ArticleStatusDto articleStatusDto); + + int deleteArticleStatus(ArticleStatusDto articleStatusDto); + +} diff --git a/src/main/java/com/nooblol/board/service/ArticleService.java b/src/main/java/com/nooblol/board/service/ArticleService.java new file mode 100644 index 00000000..22e8c18f --- /dev/null +++ b/src/main/java/com/nooblol/board/service/ArticleService.java @@ -0,0 +1,54 @@ +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 { + + /** + * 받은 articleId로 조회수를 증가한 이후 게시물정보를 반환한다. + * + * @param articleId 조회해야 하는 게시물 ID + * @param userId 로그인을 한 경우, Session에 저장된 UserId + * @return + */ + ArticleDto getArticleInfo(int articleId, String userId); + + /** + * 해당 사용자가 실제 사용자인지확인후, 게시물에서 행동할 수 있는 권한을 Return한다 + * + * @param userId + * @return + */ + String getUserArticleAuth(String userId); + + /** + * 받은 articleId의 조회수를 1 증가시킨다 + * + * @param articleId + */ + void addReadCount(int articleId); + + /** + * 게시물의 삽입 또는 수정을 진행한다. + * + * @param articleDto + * @param session + * @param isInsert 삽입인 경우 True, Update인 경우 False + * @return + */ + boolean upsertArticle(ArticleDto articleDto, HttpSession session, boolean isInsert); + + + /** + * 게시물 삭제, 요청자가 관리자인 경우 또는 글 작성자인 경우에만 삭제를 진행한다. Delete를 진행하는 경우 관련 테이블에 대해서도 삭제가 이뤄지다 보니, + * Transaction으로 묶어 처리를 진행한다 + * + * @param articleId + * @param session + * @return + */ + boolean deleteArticle(int articleId, HttpSession session); + +} diff --git a/src/main/java/com/nooblol/board/service/ArticleStatusService.java b/src/main/java/com/nooblol/board/service/ArticleStatusService.java new file mode 100644 index 00000000..7ca2571d --- /dev/null +++ b/src/main/java/com/nooblol/board/service/ArticleStatusService.java @@ -0,0 +1,33 @@ +package com.nooblol.board.service; + +import com.nooblol.board.dto.LikeAndNotLikeResponseDto; +import javax.servlet.http.HttpSession; + +public interface ArticleStatusService { + + /** + * 게시물 추천 + * + * @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); +} diff --git a/src/main/java/com/nooblol/board/service/impl/ArticleServiceImpl.java b/src/main/java/com/nooblol/board/service/impl/ArticleServiceImpl.java new file mode 100644 index 00000000..dc9d0f2a --- /dev/null +++ b/src/main/java/com/nooblol/board/service/impl/ArticleServiceImpl.java @@ -0,0 +1,148 @@ +package com.nooblol.board.service.impl; + +import com.nooblol.board.dto.ArticleDto; +import com.nooblol.board.dto.ArticleStatusDto; +import com.nooblol.board.mapper.ArticleStatusMapper; +import com.nooblol.board.service.ArticleService; +import com.nooblol.board.mapper.ArticleMapper; +import com.nooblol.board.utils.ArticleAuthMessage; +import com.nooblol.global.exception.ExceptionMessage; +import com.nooblol.global.utils.SessionUtils; +import com.nooblol.user.utils.UserRoleStatus; +import javax.servlet.http.HttpSession; +import lombok.RequiredArgsConstructor; +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 +@Service +@RequiredArgsConstructor +public class ArticleServiceImpl implements ArticleService { + + private final ArticleMapper articleMapper; + + private final ArticleStatusMapper articleStatusMapper; + + @Override + public ArticleDto getArticleInfo(int articleId, String userId) { + addReadCount(articleId); + ArticleDto result = articleMapper.selectArticleByArticleId(articleId); + + if (ObjectUtils.isEmpty(result)) { + throw new IllegalArgumentException(ExceptionMessage.NO_DATA); + } + + result.setAuthMessage(getUserArticleAuth(userId)); + return result; + } + + @Override + public String getUserArticleAuth(String userId) { + if (StringUtils.isBlank(userId)) { + return ArticleAuthMessage.GUEST.name(); + } + + int userAuthData = articleMapper.selectUserAuth(userId); + if (userAuthData == UserRoleStatus.ADMIN.getRoleValue()) { + return ArticleAuthMessage.ADMIN.name(); + } + + return ArticleAuthMessage.USER.name(); + } + + @Override + public void addReadCount(int articleId) { + articleMapper.addReadCount(articleId); + } + + @Override + public boolean upsertArticle(ArticleDto articleDto, HttpSession session, boolean isInsert) { + //UserLoginCheck의 Annotation을 통해 무조건 Session로그인이 확인된 상황이기에, Role이 Null이 올 수 없음 + + boolean isUserAdminOrInsertArticle = + UserRoleStatus.isUserRoleAdmin(SessionUtils.getSessionUserRole(session)) || isInsert; + + if (isUserAdminOrInsertArticle) { + return isArticleUpsertSuccess(articleDto); + } + + //일반 사용자이면서, 게시물의 원작자 여부 확인 + boolean isNotCreatedUser = isNotArticleCreatedUser( + articleMapper.selectCreatedUserId(articleDto.getArticleId()), + SessionUtils.getSessionUserId(session) + ); + + if (isNotCreatedUser) { + throw new IllegalArgumentException(ExceptionMessage.FORBIDDEN); + } + + return isArticleUpsertSuccess(articleDto); + } + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public boolean deleteArticle(int articleId, HttpSession session) { + ArticleDto haveArticleData = articleMapper.selectArticleByArticleId(articleId); + + if (ObjectUtils.isEmpty(haveArticleData)) { + throw new IllegalArgumentException(ExceptionMessage.NO_DATA); + } + + boolean isUserAdmin = UserRoleStatus.isUserRoleAdmin(SessionUtils.getSessionUserRole(session)); + if (isUserAdmin) { + return isArticleDeleteSuccess(articleId); + } + + boolean isNotCreatedUser = isNotArticleCreatedUser( + haveArticleData.getCreatedUserId(), SessionUtils.getSessionUserId(session) + ); + + if (isNotCreatedUser) { + throw new IllegalArgumentException(ExceptionMessage.FORBIDDEN); + } + + return isArticleDeleteSuccess(articleId); + } + + /** + * Upsert가 정상적으로 진행된 경우 True를 Return한다. + * + * @param articleDto + * @return + */ + private boolean isArticleUpsertSuccess(ArticleDto articleDto) { + return articleMapper.upsertArticle(articleDto) > 0; + } + + /** + * 게시글을 작성한 사용자가 Session에 저장된 사용자가 아닌 경우 True를 Return한다. + * + * @param dbCreatedUserId 데이터가 없는 경우 빈값이 올 수 있기에 무조건 첫번쨰 파라미터는 DB의 CreatedUserId를 넣어야 한다. + * @param sessionUserId Session에 존재하는 로그인된 사용자 Id + * @return + */ + private boolean isNotArticleCreatedUser(String dbCreatedUserId, String sessionUserId) { + return StringUtils.isBlank(dbCreatedUserId) || !dbCreatedUserId.equals(sessionUserId); + } + + + /** + * 먼저 추천, 비추천에 대한 기록도 모두 삭제하며, + *
+ * 이후 게시글을 삭제하며, 정상적으로 삭제가 되면 True, 삭제된 건수가 없으면 False를 Return한다
+ *
+ * @param articleId
+ * @return
+ */
+ private boolean isArticleDeleteSuccess(int articleId) {
+ articleStatusMapper.deleteArticleStatus(
+ new ArticleStatusDto().builder().articleId(articleId).build()
+ );
+
+ return articleMapper.deleteArticleByArticleId(articleId) > 0;
+ }
+}
diff --git a/src/main/java/com/nooblol/board/service/impl/ArticleStatusServiceImpl.java b/src/main/java/com/nooblol/board/service/impl/ArticleStatusServiceImpl.java
new file mode 100644
index 00000000..62fc9990
--- /dev/null
+++ b/src/main/java/com/nooblol/board/service/impl/ArticleStatusServiceImpl.java
@@ -0,0 +1,98 @@
+package com.nooblol.board.service.impl;
+
+
+import com.nooblol.board.dto.ArticleStatusDto;
+import com.nooblol.board.dto.LikeAndNotLikeResponseDto;
+import com.nooblol.board.mapper.ArticleMapper;
+import com.nooblol.board.mapper.ArticleStatusMapper;
+import com.nooblol.board.service.ArticleStatusService;
+import com.nooblol.board.utils.ArticleLikeStatusEnum;
+import com.nooblol.global.exception.ExceptionMessage;
+import com.nooblol.global.utils.SessionUtils;
+import javax.servlet.http.HttpSession;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.util.ObjectUtils;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class ArticleStatusServiceImpl implements ArticleStatusService {
+
+ private final ArticleMapper articleMapper;
+
+ private final ArticleStatusMapper articleStatusMapper;
+
+ @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 articleStatusMapper.selectArticleAllStatusByArticleId(articleId);
+ }
+
+ 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)
+ .likeType(ArticleLikeStatusEnum.findLikeStatusType(type))
+ .build();
+
+ return articleStatusDto;
+ }
+
+ /**
+ * 추천, 비추천에 대한 프로세스, 해당 게시물에 대해 사용자가 좋아요가 없는 경우 Insert 이미 같은 타입(추천, 비추천)을 한경우는 삭제, 다른 타입인 경우는
+ * Exception이 발생한다
+ *
+ * @param requestArticleStatusDto
+ * @return
+ */
+ private boolean statusProcess(ArticleStatusDto requestArticleStatusDto) {
+ ArticleStatusDto IsHaveStatusData = articleStatusMapper.selectArticleStatusByArticleIdAndUserId(
+ requestArticleStatusDto);
+
+ if (ObjectUtils.isEmpty(IsHaveStatusData)) {
+ return articleStatusMapper.insertArticleStatus(requestArticleStatusDto) > 0;
+ }
+
+ if (IsHaveStatusData.getLikeType().isLikeStatus() !=
+ requestArticleStatusDto.getLikeType().isLikeStatus()) {
+ throw new IllegalArgumentException(ExceptionMessage.BAD_REQUEST);
+ }
+
+ return articleStatusMapper.deleteArticleStatus(requestArticleStatusDto) > 0;
+ }
+}
diff --git a/src/main/java/com/nooblol/board/utils/ArticleAuthMessage.java b/src/main/java/com/nooblol/board/utils/ArticleAuthMessage.java
new file mode 100644
index 00000000..1f548ba6
--- /dev/null
+++ b/src/main/java/com/nooblol/board/utils/ArticleAuthMessage.java
@@ -0,0 +1,6 @@
+package com.nooblol.board.utils;
+
+
+public enum ArticleAuthMessage {
+ GUEST, USER, ADMIN;
+}
diff --git a/src/main/java/com/nooblol/board/utils/ArticleLikeStatusEnum.java b/src/main/java/com/nooblol/board/utils/ArticleLikeStatusEnum.java
new file mode 100644
index 00000000..7a3ae323
--- /dev/null
+++ b/src/main/java/com/nooblol/board/utils/ArticleLikeStatusEnum.java
@@ -0,0 +1,31 @@
+package com.nooblol.board.utils;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+public enum ArticleLikeStatusEnum {
+
+ LIKE(true), NOT_LIKE(false);
+
+ ArticleLikeStatusEnum(boolean likeStatus) {
+ this.likeStatus = likeStatus;
+ }
+
+ boolean likeStatus;
+
+ public static ArticleLikeStatusEnum findLikeStatusType(boolean likeStatus) {
+ if (likeStatus) {
+ return LIKE;
+ }
+ return NOT_LIKE;
+ }
+
+
+ public static ArticleLikeStatusEnum findLikeStatusByInt(int num) {
+ if (num == 1) {
+ return LIKE;
+ }
+ return NOT_LIKE;
+ }
+}
diff --git a/src/main/java/com/nooblol/board/utils/ArticleLikeStatusEnumTypeHandler.java b/src/main/java/com/nooblol/board/utils/ArticleLikeStatusEnumTypeHandler.java
new file mode 100644
index 00000000..13770203
--- /dev/null
+++ b/src/main/java/com/nooblol/board/utils/ArticleLikeStatusEnumTypeHandler.java
@@ -0,0 +1,43 @@
+package com.nooblol.board.utils;
+
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import org.apache.ibatis.type.JdbcType;
+import org.apache.ibatis.type.TypeHandler;
+
+
+/*
+ReferenceList
+ https://umbum.dev/1122
+ https://exchangetuts.com/java-mybatis-enum-string-value-1640689684810781
+ */
+public class ArticleLikeStatusEnumTypeHandler implements TypeHandler
*
* @param jp
*/
@@ -49,8 +49,13 @@ public void memberLoginAndRoleAdminCheck(JoinPoint jp) throws Throwable {
HttpSession session = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest()
.getSession();
- if (Optional.ofNullable(SessionUtils.getSessionUserRole(session)).isEmpty()) {
+ //사용자 정보가 존재하지 않는 경우 GUEST로 설정
+ Integer userRole = Optional
+ .ofNullable(SessionUtils.getSessionUserRole(session))
+ .orElse(UserRoleStatus.GUEST.getRoleValue());
+
+ if (userRole.equals(UserRoleStatus.ADMIN.getRoleValue())) {
throw new IllegalArgumentException(ExceptionMessage.UNAUTHORIZED);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/nooblol/global/utils/ResponseUtils.java b/src/main/java/com/nooblol/global/utils/ResponseUtils.java
index b31d12dc..dce9ba33 100644
--- a/src/main/java/com/nooblol/global/utils/ResponseUtils.java
+++ b/src/main/java/com/nooblol/global/utils/ResponseUtils.java
@@ -1,8 +1,10 @@
package com.nooblol.global.utils;
import com.nooblol.global.dto.ResponseDto;
+import com.nooblol.global.exception.ExceptionMessage;
import java.util.List;
import org.springframework.http.HttpStatus;
+import org.springframework.util.ObjectUtils;
public class ResponseUtils {
@@ -20,5 +22,20 @@ public static
@@ -21,4 +23,8 @@ public enum UserRoleStatus {
public int getRoleValue() {
return roleValue;
}
+
+ public static boolean isUserRoleAdmin(int roleValue) {
+ return ADMIN.getRoleValue() == roleValue;
+ }
}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 3194b8fb..67f9f034 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -24,6 +24,13 @@ spring:
starttls:
enable: true
+ #NoHandlerException Setting
+ mvc:
+ throw-exception-if-no-handler-found: true
+ web:
+ resources:
+ add-mappings: false
+
#Embedded Tomcat Session TimeOut
server:
servlet:
@@ -37,6 +44,7 @@ mybatis:
jdbc-type-for-null: null
call-setters-on-nulls: true
multiple-result-sets-enabled: false
+ default-enum-type-handler: com.nooblol.board.utils.ArticleLikeStatusEnumTypeHandler
type-aliases-package: com.nooblol.*.*
mapper-locations: classpath:mybatis/mapper/*/*.xml
diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql
new file mode 100644
index 00000000..8344e15e
--- /dev/null
+++ b/src/main/resources/data.sql
@@ -0,0 +1,41 @@
+/*password : abc*/
+INSERT INTO users(user_id, user_email, user_name, user_password_hash, user_role, level, exp,
+ created_at, updated_at)
+VALUES ('test', 'test@test.com', 'test',
+ '3a81oZNherrMQXNJriBBMRLm+k6JqX6iCp7u5ktV05ohkpkqJ0/BqDa6PCOj/uu9RU1EI2Q86A4qmslPpUyknw==',
+ 1, 1, 0, now(), now());
+
+INSERT INTO users(user_id, user_email, user_name, user_password_hash, user_role, level, exp,
+ created_at, updated_at)
+VALUES ('test-admin-user', 'admin@test.com', 'admin',
+ '3a81oZNherrMQXNJriBBMRLm+k6JqX6iCp7u5ktV05ohkpkqJ0/BqDa6PCOj/uu9RU1EI2Q86A4qmslPpUyknw==',
+ 9, 1, 0, now(), now());
+
+INSERT INTO bbs_category(category_name, status, created_user_id, created_at, updated_user_id,
+ updated_at)
+VALUES ('Test Active Category1', 1, 'test-admin-user', now(), 'test-admin-user', now());
+
+INSERT INTO bbs (category_id, bbs_name, status, created_user_id, created_at, updated_user_id,
+ updated_at)
+VALUES (1, 'Test Active BBS', 1, 'test-admin-user', now(), 'test-admin-user', now());
+
+INSERT INTO bbs_articles(article_id, bbs_id, article_title, article_read_count, article_content,
+ status,
+ created_user_id, created_at, updated_at)
+VALUES (1, 1, 'Test Article Title - 1', 0, '내용이웨요', 1, 'test-admin-user', now(), now());
+
+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());
+
+
+
+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());
\ No newline at end of file
diff --git a/src/main/resources/mybatis/mapper/board/ArticleMapper.xml b/src/main/resources/mybatis/mapper/board/ArticleMapper.xml
new file mode 100644
index 00000000..1fe3d247
--- /dev/null
+++ b/src/main/resources/mybatis/mapper/board/ArticleMapper.xml
@@ -0,0 +1,63 @@
+
+
+