From a0113cc952b4da6a500b32794bf7e06fc660bf3e Mon Sep 17 00:00:00 2001 From: Geunsik Kim <93639883+600gramSik@users.noreply.github.com> Date: Tue, 18 Jun 2024 16:51:04 +0900 Subject: [PATCH] =?UTF-8?q?[REFACTOR]=20=EB=8C=93=EA=B8=80&=EC=A2=8B?= =?UTF-8?q?=EC=95=84=EC=9A=94=20=EA=B0=9C=EC=88=98=20Redis=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EB=B0=8F=20=EB=8C=80=EB=8C=93=EA=B8=80=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=ED=95=B4=EA=B2=B0(#117)=20(#125)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ♻️refactor: 좋아요 redis 적용(#117) * ♻️refactor: 대댓글 구조 변경 및 댓글 수 레디스에 적용(#117) * ♻️refactor: 대댓글 구조 변경 및 댓글 수 레디스에 적용 및 좋아요 레디스 적용(#117) * ♻️refactor: service 측 오류 수정(#117) * ♻️refactor: redisUtil 부분 boardSaveLikeCount & boardGetLikeCount 추가 및 적용(#117) * ♻️refactor: tacticPositionDetail 피드백에 맞게 수정(#117) * ♻️refactor: MyTeam 개별 조회 시, 해당 팀에 속해있지 않는 상황에 대한 예외처리 로직 추가(#117) * ♻️refactor: MyTeam 개별 조회 시, 해당 팀에 속해있지 않는 상황에 대한 예외처리(controller 수정)(#117) * ♻️refactor: MyTeamList 조회 시, 본인이 방장인 팀과 팀원인 팀 둘다 조회되게 수정 완료 및 팀 개별 조회 시 본인 팀이 아닐 시 예외처리 추가(#117) * ♻️refactor: 좋아요 레디스 적용 수정(getLikeCount -> boardGetLikeCount 추가)(#117) * ♻️refactor: 댓글 갯수 redis 적용 완료(#117) * ♻️refactor: 코드 최종 정리(#117) * ♻️refactor: TacticService에서 필요없는 코드 정리(#117) * ♻️refactor: BoardResponseDto에서 댓글, 좋아요 갯수 수정(#117) * ♻️refactor: BoardResponseDto가 불필요하여 BoardResponseDto -> BoardListDto로 변경 후 코드 간소화 함(#117) * ♻️refactor: 변경된 경로 수정(#117) * ♻️refactor: RedisConfig에서 필요없는 메서드 제거(#117) --- http/AccountsTest.http | 5 ++- .../board/controller/BoardController.java | 17 ++++---- .../dto/response/BoardDetailResponseDto.java | 41 ++++++------------- .../board/dto/response/BoardListDto.java | 37 +++++++++++++++++ .../board/dto/response/BoardResponseDto.java | 32 --------------- .../dto/response/CommentResponseDto.java | 3 ++ .../BnagFer/domain/board/entity/Like.java | 4 +- .../repository/BoardCommentRepository.java | 1 + .../board/service/BoardQueryService.java | 27 ++++++++---- .../domain/board/service/BoardService.java | 33 ++++++++++----- .../myteam/controller/TeamController.java | 9 +++- .../dto/response/GetTeamResponseDto.java | 30 +++++++------- .../BnagFer/domain/myteam/entity/Team.java | 3 ++ .../domain/myteam/entity/TeamMember.java | 1 + .../repository/TeamMembersRepository.java | 3 ++ .../myteam/repository/TeamRepository.java | 7 +++- .../myteam/service/TeamMembersService.java | 3 +- .../myteam/service/TeamQueryService.java | 36 +++++++++------- .../tactic/entity/TacticPositionDetail.java | 1 + .../domain/tactic/service/TacticService.java | 24 ++++++++++- .../BnagFer/global/config/RedisConfig.java | 1 + .../BnagFer/global/util/RedisUtil.java | 35 ++++++++++------ 22 files changed, 218 insertions(+), 135 deletions(-) create mode 100644 src/main/java/com/capstone/BnagFer/domain/board/dto/response/BoardListDto.java delete mode 100644 src/main/java/com/capstone/BnagFer/domain/board/dto/response/BoardResponseDto.java diff --git a/http/AccountsTest.http b/http/AccountsTest.http index 99187fb1..9a3bcd83 100644 --- a/http/AccountsTest.http +++ b/http/AccountsTest.http @@ -9,11 +9,14 @@ Content-Type: application/json "passwordCheck": "test1234!!" } + ### 로그인 + POST {{api}}/accounts/login Content-Type: application/json { "email": "test1234@naver.com", - "password": "test1234!!" + "password": "test1234!!", + "fcmToken": "String" } diff --git a/src/main/java/com/capstone/BnagFer/domain/board/controller/BoardController.java b/src/main/java/com/capstone/BnagFer/domain/board/controller/BoardController.java index 09415497..46b09d35 100644 --- a/src/main/java/com/capstone/BnagFer/domain/board/controller/BoardController.java +++ b/src/main/java/com/capstone/BnagFer/domain/board/controller/BoardController.java @@ -5,7 +5,7 @@ import com.capstone.BnagFer.domain.board.dto.request.CreateCommentRequestDto; import com.capstone.BnagFer.domain.board.dto.request.UpdateCommentRequestDto; import com.capstone.BnagFer.domain.board.dto.response.BoardDetailResponseDto; -import com.capstone.BnagFer.domain.board.dto.response.BoardResponseDto; +import com.capstone.BnagFer.domain.board.dto.response.BoardListDto; import com.capstone.BnagFer.domain.board.dto.response.CommentResponseDto; import com.capstone.BnagFer.domain.board.dto.response.CreateBoardResponseDto; import com.capstone.BnagFer.domain.board.service.BoardQueryService; @@ -31,34 +31,37 @@ public class BoardController { private final BoardService boardService; private final BoardQueryService boardQueryService; + + @GetMapping //게시판 리스트 조회 @Operation(summary = "게시판 목록 조회", description = "전체 게시판 목록을 조회합니다. 페이징 적용, 생성 날짜 기준 내림차순 정렬.") @GetMapping public ApiResponse> getBoardsList( + @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "10") int size) { Pageable pageable = PageRequest.of(page, size); - Page boardsList = boardQueryService.getBoards(pageable); + Page boardsList = boardQueryService.getBoards(pageable); return onSuccess(boardsList); } @Operation(summary = "개별 게시물 조회", description = "단일 게시물의 내용을 조회합니다.") @GetMapping("/{boardId}") - public ApiResponse getBoard (@PathVariable Long boardId) { - BoardResponseDto board = boardQueryService.getBoard(boardId); + public ApiResponse getBoard (@PathVariable Long boardId) { + BoardDetailResponseDto board = boardQueryService.getBoard(boardId); return ApiResponse.onSuccess(board); } @Operation(summary = "내 게시물 목록 조회", description = "자신이 작성한 게시글 목록 조회. 페이징 적용, 생성 날짜 기준 내림차순 정렬.") @GetMapping("/myboards") - public ApiResponse> getMyBoardsList( + public ApiResponse> getMyBoardsList( @LoginUser User user, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "10") int size) { Pageable pageable = PageRequest.of(page, size); - Page myBoardsList = boardQueryService.getMyBoards(user, pageable); + Page myBoardsList = boardQueryService.getMyBoards(user, pageable); return onSuccess(myBoardsList); } @@ -99,7 +102,7 @@ public ApiResponse deleteBoard(@PathVariable Long boardId, @LoginUser Us @Operation(summary = "게시글 좋아요 & 좋아요 취소", description = "게시글에 좋아요를 누르는 기능. 한번 더누르면 좋아요 취소.") @PostMapping("/{boardId}/like") - public ApiResponse likeBoard(@PathVariable Long boardId, @LoginUser User user) { + public ApiResponse likeButton(@PathVariable Long boardId, @LoginUser User user) { return boardService.likeButton(boardId, user); } diff --git a/src/main/java/com/capstone/BnagFer/domain/board/dto/response/BoardDetailResponseDto.java b/src/main/java/com/capstone/BnagFer/domain/board/dto/response/BoardDetailResponseDto.java index bdde23d4..1cb23bdd 100644 --- a/src/main/java/com/capstone/BnagFer/domain/board/dto/response/BoardDetailResponseDto.java +++ b/src/main/java/com/capstone/BnagFer/domain/board/dto/response/BoardDetailResponseDto.java @@ -15,18 +15,20 @@ public record BoardDetailResponseDto( String writerNickName, String boardTitle, String boardContent, - List commentContent, - int likeCount + List commentList, + Long likeCount, + Long commentCount ) { - public static BoardDetailResponseDto from(Board board) { + public static BoardDetailResponseDto from(Board board, Long likeCount, Long commentCount) { return BoardDetailResponseDto.builder() .id(board.getId()) .writerId(board.getUser().getId()) .writerNickName(board.getUser().getProfile().getNickname()) .boardTitle(board.getBoardTitle()) .boardContent(board.getBoardContent()) - .commentContent(board.getComments()) - .likeCount(board.getLikes().size()) + .commentList(CommentList.from(board.getComments())) + .likeCount(likeCount) + .commentCount(commentCount) .build(); } @Builder @@ -37,7 +39,8 @@ public record CommentList( String nickName, String commentText, LocalDateTime createdAt, - LocalDateTime updatedAt + LocalDateTime updatedAt, + List children ) { public static CommentList from(Comment comment) { return CommentList.builder() @@ -48,32 +51,12 @@ public static CommentList from(Comment comment) { .commentText(comment.getCommentText()) .createdAt(comment.getCreatedAt()) .updatedAt(comment.getUpdatedAt()) + .children(comment.getChildren().stream().map(CommentList::from).collect(Collectors.toList())) + //최상위 댓글로만 자식 댓글이 달릴 수 있게! .build(); } public static List from(List comments) { - return comments.stream().map(CommentList::from).collect(Collectors.toList()); - } - } - @Builder - public record BoardList( - Long id, - Long userId, - String writerNickName, - String boardTitle, - int likeCount - - ) { - public static BoardList from(Board board) { - return BoardList.builder() - .id(board.getId()) - .userId(board.getUser().getId()) - .writerNickName(board.getUser().getProfile().getNickname()) - .boardTitle(board.getBoardTitle()) - .likeCount(board.getLikes().size()) - .build(); - } - public static List from(List boards) { - return boards.stream().map(BoardList::from).collect(Collectors.toList()); + return comments.stream().filter(c -> c.getParent() == null).map(CommentList::from).collect(Collectors.toList()); } } diff --git a/src/main/java/com/capstone/BnagFer/domain/board/dto/response/BoardListDto.java b/src/main/java/com/capstone/BnagFer/domain/board/dto/response/BoardListDto.java new file mode 100644 index 00000000..62bd03da --- /dev/null +++ b/src/main/java/com/capstone/BnagFer/domain/board/dto/response/BoardListDto.java @@ -0,0 +1,37 @@ +package com.capstone.BnagFer.domain.board.dto.response; + +import com.capstone.BnagFer.domain.board.entity.Board; +import lombok.Builder; + +import java.util.List; +import java.util.stream.Collectors; + +@Builder +public record BoardListDto( + Long id, + Long userId, + String writerNickName, + String boardTitle, + Long likeCount, + Long commentCount + +) { + public static BoardListDto from(Board board, Long commentCount, Long likeCount) { + return BoardListDto.builder() + .id(board.getId()) + .userId(board.getUser().getId()) + .writerNickName(board.getUser().getProfile().getNickname()) + .boardTitle(board.getBoardTitle()) + .likeCount(likeCount) + .commentCount(commentCount) + .build(); + } + public static BoardListDto from(Board board) { + return from(board, 0L, 0L); + } + public static List from(List boards) { + return boards.stream().map(board -> from(board, 0L, 0L)).collect(Collectors.toList()); + } +} + + diff --git a/src/main/java/com/capstone/BnagFer/domain/board/dto/response/BoardResponseDto.java b/src/main/java/com/capstone/BnagFer/domain/board/dto/response/BoardResponseDto.java deleted file mode 100644 index dea31449..00000000 --- a/src/main/java/com/capstone/BnagFer/domain/board/dto/response/BoardResponseDto.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.capstone.BnagFer.domain.board.dto.response; - -import com.capstone.BnagFer.domain.board.entity.Board; -import com.capstone.BnagFer.domain.board.entity.Comment; - -import java.time.LocalDateTime; -import java.util.List; - -public record BoardResponseDto( - Long id, - Long writerId, - String writerNickName, - String boardTitle, - String boardContent, - int likeCount, - LocalDateTime createdAt, - LocalDateTime updatedAt - -) { - public static BoardResponseDto from(Board board) { - return new BoardResponseDto( - board.getId(), - board.getUser().getId(), - board.getUser().getProfile().getNickname(), - board.getBoardTitle(), - board.getBoardContent(), - board.getLikes().size(), - board.getCreatedAt(), - board.getUpdatedAt() - ); - } -} diff --git a/src/main/java/com/capstone/BnagFer/domain/board/dto/response/CommentResponseDto.java b/src/main/java/com/capstone/BnagFer/domain/board/dto/response/CommentResponseDto.java index 9570127b..014b640c 100644 --- a/src/main/java/com/capstone/BnagFer/domain/board/dto/response/CommentResponseDto.java +++ b/src/main/java/com/capstone/BnagFer/domain/board/dto/response/CommentResponseDto.java @@ -4,6 +4,8 @@ import lombok.Builder; import java.time.LocalDateTime; +import java.util.List; + public record CommentResponseDto( Long id, Long boardId, @@ -24,4 +26,5 @@ public static CommentResponseDto from(Comment comment) { comment.getUpdatedAt() ); } + } diff --git a/src/main/java/com/capstone/BnagFer/domain/board/entity/Like.java b/src/main/java/com/capstone/BnagFer/domain/board/entity/Like.java index 76a8918f..f1f74590 100644 --- a/src/main/java/com/capstone/BnagFer/domain/board/entity/Like.java +++ b/src/main/java/com/capstone/BnagFer/domain/board/entity/Like.java @@ -15,11 +15,11 @@ public class Like extends BaseEntity { @Column(name = "like_id", nullable = false) private Long id; - @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @ManyToOne(optional = false, fetch = FetchType.LAZY) @JoinColumn(name = "user_id") private User user; - @ManyToOne(fetch = FetchType.LAZY) + @ManyToOne(optional = false, fetch = FetchType.LAZY) @JoinColumn(name = "board_id") private Board board; diff --git a/src/main/java/com/capstone/BnagFer/domain/board/repository/BoardCommentRepository.java b/src/main/java/com/capstone/BnagFer/domain/board/repository/BoardCommentRepository.java index 999c6d73..e5e2aadc 100644 --- a/src/main/java/com/capstone/BnagFer/domain/board/repository/BoardCommentRepository.java +++ b/src/main/java/com/capstone/BnagFer/domain/board/repository/BoardCommentRepository.java @@ -6,4 +6,5 @@ @Repository public interface BoardCommentRepository extends JpaRepository { + long countByBoardId(Long boardId); } diff --git a/src/main/java/com/capstone/BnagFer/domain/board/service/BoardQueryService.java b/src/main/java/com/capstone/BnagFer/domain/board/service/BoardQueryService.java index 7847af2d..79f28663 100644 --- a/src/main/java/com/capstone/BnagFer/domain/board/service/BoardQueryService.java +++ b/src/main/java/com/capstone/BnagFer/domain/board/service/BoardQueryService.java @@ -4,11 +4,12 @@ import com.capstone.BnagFer.domain.accounts.exception.AccountsExceptionHandler; import com.capstone.BnagFer.domain.accounts.repository.UserJpaRepository; import com.capstone.BnagFer.domain.board.dto.response.BoardDetailResponseDto; -import com.capstone.BnagFer.domain.board.dto.response.BoardResponseDto; +import com.capstone.BnagFer.domain.board.dto.response.BoardListDto; import com.capstone.BnagFer.domain.board.entity.Board; import com.capstone.BnagFer.domain.board.exception.BoardExceptionHandler; import com.capstone.BnagFer.domain.board.repository.BoardRepository; import com.capstone.BnagFer.global.common.ErrorCode; +import com.capstone.BnagFer.global.util.RedisUtil; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -22,18 +23,19 @@ public class BoardQueryService { private final BoardRepository boardRepository; + private final RedisUtil redisUtil; private final UserJpaRepository userJpaRepository; - - public Page getBoards(Pageable pageable) { + public Page getBoards(Pageable pageable) { Page boards = boardRepository.findAll(pageable); - return boards.map(BoardDetailResponseDto.BoardList::from); + return boards.map(BoardListDto::from); } - public Page getMyBoards(User user, Pageable pageable) { + public Page getMyBoards(User user, Pageable pageable) { Page boards = getBoardsByUser(user, pageable); - return boards.map(BoardDetailResponseDto.BoardList::from); + return boards.map(BoardListDto::from); } + public BoardDetailResponseDto getBoard(Long boardId) { public Page getUserBoards(Long userId, Pageable pageable) { User user = userJpaRepository.findById(userId) .orElseThrow(() -> new AccountsExceptionHandler(ErrorCode.USER_NOT_FOUND)); @@ -43,7 +45,18 @@ public Page getUserBoards(Long userId, Pageabl public BoardResponseDto getBoard(Long boardId) { Board board = boardRepository.findById(boardId).orElseThrow(() -> new BoardExceptionHandler(ErrorCode.BOARD_NOT_FOUND)); - return BoardResponseDto.from(board); + Long likeCount = redisUtil.boardGetLikeCount(boardId); + + if (likeCount == null) { + likeCount = (long) board.getLikes().size(); + redisUtil.boardSaveLikeCount(boardId, likeCount); + } + Long commentCount = redisUtil.boardGetCommentCount(boardId); + if(commentCount == null){ + commentCount = (long) board.getComments().size(); + redisUtil.boardSaveCommentCount(boardId, commentCount); + } + return BoardDetailResponseDto.from(board, likeCount, commentCount); } public Page getBoardsByUser(User user, Pageable pageable) { diff --git a/src/main/java/com/capstone/BnagFer/domain/board/service/BoardService.java b/src/main/java/com/capstone/BnagFer/domain/board/service/BoardService.java index 21a38563..8b0dd08f 100644 --- a/src/main/java/com/capstone/BnagFer/domain/board/service/BoardService.java +++ b/src/main/java/com/capstone/BnagFer/domain/board/service/BoardService.java @@ -1,6 +1,7 @@ package com.capstone.BnagFer.domain.board.service; import com.capstone.BnagFer.domain.accounts.entity.User; +import com.capstone.BnagFer.domain.accounts.jwt.util.RedisUtil; import com.capstone.BnagFer.domain.accounts.service.account.AccountsCommonService; import com.capstone.BnagFer.domain.board.dto.request.BoardRequestDto; import com.capstone.BnagFer.domain.board.dto.request.CreateCommentRequestDto; @@ -17,6 +18,7 @@ import com.capstone.BnagFer.global.common.ApiResponse; import com.capstone.BnagFer.global.common.ErrorCode; import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Optional; @@ -29,6 +31,8 @@ public class BoardService { private final AccountsCommonService accountsCommonService; private final BoardLikeRepository boardLikeRepository; private final BoardCommentRepository boardCommentRepository; + private final RedisUtil redisUtil; + private final StringRedisTemplate stringRedisTemplate; public CreateBoardResponseDto createBoard(BoardRequestDto request, User user) { accountsCommonService.checkUserProfile(user); @@ -53,50 +57,59 @@ public void deleteBoard(Long boardId, User user) { } boardRepository.deleteById(boardId); } - public ApiResponse likeButton(Long boardId, User user) { + Board board = boardRepository.findById(boardId).orElseThrow(() -> new BoardExceptionHandler(ErrorCode.BOARD_NOT_FOUND)); + Optional like = boardLikeRepository.findByUserAndBoard(user, board); - if(like.isPresent()) { + + long likeCount = redisUtil.boardGetLikeCount(boardId); + + if (like.isPresent()) { boardLikeRepository.delete(like.get()); + likeCount--; + redisUtil.boardSaveLikeCount(boardId, likeCount); return ApiResponse.CANCELED_LIKE(); - } - else { + } else { boardLikeRepository.save(new Like(user, board)); + likeCount++; + redisUtil.boardSaveLikeCount(boardId, likeCount); return ApiResponse.SUCCESS_LIKE(); } } - public CommentResponseDto createComment(Long boardId, CreateCommentRequestDto request, User user, Long parentCommentId) { Board board = boardRepository.findById(boardId).orElseThrow(() -> new BoardExceptionHandler(ErrorCode.BOARD_NOT_FOUND)); + long commentCount = redisUtil.boardGetCommentCount(boardId); Comment parent = null; if (parentCommentId != null) { parent = boardCommentRepository.findById(parentCommentId).orElseThrow(() -> new BoardExceptionHandler(ErrorCode.COMMENT_NOT_FOUND)); } - Comment comment = request.toEntity(user, board, parent); - accountsCommonService.checkUserProfile(user); boardCommentRepository.save(comment); + commentCount++; + redisUtil.boardSaveCommentCount(boardId, commentCount); return CommentResponseDto.from(comment); } public CommentResponseDto updateComment(Long commentId, UpdateCommentRequestDto request, User user) { Comment comment = boardCommentRepository.findById(commentId).orElseThrow(() -> new BoardExceptionHandler(ErrorCode.COMMENT_NOT_FOUND)); - if(!comment.getUser().getId().equals(user.getId())) throw new BoardExceptionHandler(ErrorCode.USER_NOT_MATCHED); - comment.updateComment(request); Comment updatedComment = boardCommentRepository.save(comment); return CommentResponseDto.from(updatedComment); } - public void deleteComment(Long commentId, User user) { Comment comment = boardCommentRepository.findById(commentId).orElseThrow(() -> new BoardExceptionHandler(ErrorCode.COMMENT_NOT_FOUND)); + long boardId = comment.getBoard().getId(); + long commentCount = redisUtil.boardGetCommentCount(boardId); + long childCnt = comment.getChildren().size(); if(!comment.getUser().getId().equals(user.getId())) { throw new BoardExceptionHandler(ErrorCode.USER_NOT_MATCHED); } boardCommentRepository.deleteById(commentId); + commentCount -=(childCnt + 1L); + redisUtil.boardSaveCommentCount(boardId, commentCount); } } diff --git a/src/main/java/com/capstone/BnagFer/domain/myteam/controller/TeamController.java b/src/main/java/com/capstone/BnagFer/domain/myteam/controller/TeamController.java index 8ecee54a..6ec54bca 100644 --- a/src/main/java/com/capstone/BnagFer/domain/myteam/controller/TeamController.java +++ b/src/main/java/com/capstone/BnagFer/domain/myteam/controller/TeamController.java @@ -31,8 +31,8 @@ public class TeamController { @Operation(summary = "내 팀정보 조회") @GetMapping("/{teamId}") - public ApiResponse getMyTeam(@PathVariable Long teamId) { - GetTeamResponseDto myTeam = teamQueryService.getMyTeamById(teamId); + public ApiResponse getMyTeam(@PathVariable Long teamId, @LoginUser User user) { + GetTeamResponseDto myTeam = teamQueryService.getMyTeamById(teamId, user); return ApiResponse.onSuccess(myTeam); } @@ -86,11 +86,16 @@ public ApiResponse> getMyTactic(@ teamTacticService.deallocateMyTactic(teamId, tacticId, user); return ApiResponse.noContent(); } + @GetMapping("/{teamId}/{positionDetailId}") + public ApiResponse getIndividualDetail(@PathVariable Long teamId, Long positionDetailId) { + GetTeamResponseDto.getIndividualDetail positionDetail = teamQueryService .getIndividualDetail(teamId, positionDetailId); + @Operation(summary = "포지션 세부 설명", description = "11개의 포지션 버튼을 눌러 포지션의 세부 설명을 확인하는 기능") @GetMapping("/{teamId}/{memberId}/positionDetail") public ApiResponse> getIndividualDetail(@PathVariable Long teamId, @PathVariable Long memberId, @LoginUser User user) { List positionDetail = teamQueryService .getIndividualDetail(teamId, memberId, user); + return ApiResponse.onSuccess(positionDetail); } diff --git a/src/main/java/com/capstone/BnagFer/domain/myteam/dto/response/GetTeamResponseDto.java b/src/main/java/com/capstone/BnagFer/domain/myteam/dto/response/GetTeamResponseDto.java index b87e9c2b..b2394582 100644 --- a/src/main/java/com/capstone/BnagFer/domain/myteam/dto/response/GetTeamResponseDto.java +++ b/src/main/java/com/capstone/BnagFer/domain/myteam/dto/response/GetTeamResponseDto.java @@ -5,10 +5,13 @@ import com.capstone.BnagFer.domain.tactic.dto.TacticResponse; import com.capstone.BnagFer.domain.tactic.entity.Position; import com.capstone.BnagFer.domain.tactic.entity.TacticPositionDetail; +import com.google.firebase.database.annotations.Nullable; import lombok.*; + import java.time.LocalDateTime; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; @Builder @@ -69,34 +72,33 @@ public static List from(List teamMembers) { public record TeamList( Long teamId, String teamName, + Long teamMemberId, String leaderNickName - ) - { - public static TeamList from(Team team) { + ) { + public static TeamList from(Team team, TeamMember teamMember) { return TeamList.builder() .teamId(team.getId()) .teamName(team.getTeamName()) + .teamMemberId(teamMember.getId()) .leaderNickName(team.getLeader().getProfile().getNickname()) .build(); } - public static List from(List teams) { - return teams.stream().map(TeamList::from).collect(Collectors.toList()); - } } @Builder public record getIndividualDetail( - Long detailId, - Position position, - String positionDescription, + Long teamId, + Long tacticPositionDetailId, String memberNickName ) { - public static getIndividualDetail from(TacticPositionDetail tacticPositionDetail, TeamMember teamMember) { + public static getIndividualDetail from(Team team, TacticPositionDetail tacticPositionDetail, @Nullable TeamMember teamMember) { return getIndividualDetail.builder() - .detailId(tacticPositionDetail.getDetailId()) - .position(tacticPositionDetail.getPosition()) - .memberNickName(teamMember.getUser().getProfile().getNickname()) - .positionDescription(tacticPositionDetail.getPositionDescription()) + .teamId(team.getId()) + .tacticPositionDetailId(tacticPositionDetail.getDetailId()) + .memberNickName(teamMember != null && teamMember.getUser() != null && teamMember.getUser().getProfile() != null + ? teamMember.getUser().getProfile().getNickname() + : null) .build(); + } } } diff --git a/src/main/java/com/capstone/BnagFer/domain/myteam/entity/Team.java b/src/main/java/com/capstone/BnagFer/domain/myteam/entity/Team.java index 7065d1fd..9d7c33fb 100644 --- a/src/main/java/com/capstone/BnagFer/domain/myteam/entity/Team.java +++ b/src/main/java/com/capstone/BnagFer/domain/myteam/entity/Team.java @@ -3,6 +3,7 @@ import com.capstone.BnagFer.domain.myteam.dto.request.CUTeamRequestDto; import com.capstone.BnagFer.domain.tactic.entity.Tactic; import com.capstone.BnagFer.global.common.BaseEntity; +import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; import lombok.*; import java.util.List; @@ -31,6 +32,7 @@ public class Team extends BaseEntity { //팀 맴버 @OneToMany(mappedBy = "team", cascade = CascadeType.ALL) + @JsonIgnore private List teamMembers; //전술 @@ -40,6 +42,7 @@ public class Team extends BaseEntity { //캘린더 @OneToMany(mappedBy = "team") + @JsonIgnore private List calendarEvents; public void updateLeader(User updateLeader) { diff --git a/src/main/java/com/capstone/BnagFer/domain/myteam/entity/TeamMember.java b/src/main/java/com/capstone/BnagFer/domain/myteam/entity/TeamMember.java index fd91c030..aed48d8f 100644 --- a/src/main/java/com/capstone/BnagFer/domain/myteam/entity/TeamMember.java +++ b/src/main/java/com/capstone/BnagFer/domain/myteam/entity/TeamMember.java @@ -2,6 +2,7 @@ import com.capstone.BnagFer.domain.accounts.entity.User; import com.capstone.BnagFer.domain.tactic.entity.Position; +import com.capstone.BnagFer.domain.tactic.entity.TacticPositionDetail; import com.capstone.BnagFer.global.common.BaseEntity; import jakarta.persistence.*; import lombok.*; diff --git a/src/main/java/com/capstone/BnagFer/domain/myteam/repository/TeamMembersRepository.java b/src/main/java/com/capstone/BnagFer/domain/myteam/repository/TeamMembersRepository.java index a40a76d0..4694bcc8 100644 --- a/src/main/java/com/capstone/BnagFer/domain/myteam/repository/TeamMembersRepository.java +++ b/src/main/java/com/capstone/BnagFer/domain/myteam/repository/TeamMembersRepository.java @@ -4,6 +4,7 @@ import com.capstone.BnagFer.domain.myteam.entity.Team; import com.capstone.BnagFer.domain.myteam.entity.TeamMember; import com.capstone.BnagFer.domain.tactic.entity.Position; +import com.capstone.BnagFer.domain.tactic.entity.TacticPositionDetail; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -24,4 +25,6 @@ public interface TeamMembersRepository extends JpaRepository { TeamMember findByTeamAndPosition(Team team, Position position); boolean existsByTeamAndId(Team team, Long id); + + List findByUser(User user); } \ No newline at end of file diff --git a/src/main/java/com/capstone/BnagFer/domain/myteam/repository/TeamRepository.java b/src/main/java/com/capstone/BnagFer/domain/myteam/repository/TeamRepository.java index 9275f575..38212a37 100644 --- a/src/main/java/com/capstone/BnagFer/domain/myteam/repository/TeamRepository.java +++ b/src/main/java/com/capstone/BnagFer/domain/myteam/repository/TeamRepository.java @@ -1,9 +1,14 @@ package com.capstone.BnagFer.domain.myteam.repository; - import com.capstone.BnagFer.domain.myteam.entity.Team; +import com.capstone.BnagFer.domain.myteam.entity.TeamMember; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.util.List; @Repository public interface TeamRepository extends JpaRepository { + @Query("SELECT t FROM Team t JOIN t.teamMembers tm WHERE tm IN :teamMembers") + List findByTeamMembers(@Param("teamMembers") List teamMembers); } diff --git a/src/main/java/com/capstone/BnagFer/domain/myteam/service/TeamMembersService.java b/src/main/java/com/capstone/BnagFer/domain/myteam/service/TeamMembersService.java index c55f0377..ba36b155 100644 --- a/src/main/java/com/capstone/BnagFer/domain/myteam/service/TeamMembersService.java +++ b/src/main/java/com/capstone/BnagFer/domain/myteam/service/TeamMembersService.java @@ -14,6 +14,7 @@ import com.capstone.BnagFer.domain.myteam.repository.TeamMembersRepository; import com.capstone.BnagFer.domain.myteam.repository.TeamRepository; import com.capstone.BnagFer.domain.tactic.entity.Position; +import com.capstone.BnagFer.domain.tactic.repository.TacticPositionDetailRepository; import com.capstone.BnagFer.global.common.ErrorCode; import com.capstone.BnagFer.global.common.exception.CustomException; import lombok.RequiredArgsConstructor; @@ -29,6 +30,7 @@ public class TeamMembersService { private final TeamMembersRepository teamMembersRepository; private final UserJpaRepository userJpaRepository; private final TeamRepository teamRepository; + private final TacticPositionDetailRepository tacticPositionDetailRepository; public TeamMembersResponseDto inviteTeamMembers(TeamMemberRequestDto request, User user) { @@ -124,5 +126,4 @@ public void deallocatePosition(Long teamId, Long memberId, User user) { } else throw new TeamMemberExceptionHandler(ErrorCode.CANNOT_ALLOCATE); } - } \ No newline at end of file diff --git a/src/main/java/com/capstone/BnagFer/domain/myteam/service/TeamQueryService.java b/src/main/java/com/capstone/BnagFer/domain/myteam/service/TeamQueryService.java index eefb115d..f0e17568 100644 --- a/src/main/java/com/capstone/BnagFer/domain/myteam/service/TeamQueryService.java +++ b/src/main/java/com/capstone/BnagFer/domain/myteam/service/TeamQueryService.java @@ -7,40 +7,46 @@ import com.capstone.BnagFer.domain.myteam.repository.TeamMembersRepository; import com.capstone.BnagFer.domain.myteam.repository.TeamRepository; import com.capstone.BnagFer.domain.tactic.entity.TacticPositionDetail; +import com.capstone.BnagFer.domain.tactic.repository.TacticPositionDetailRepository; import com.capstone.BnagFer.global.common.ErrorCode; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.List; - @Service @RequiredArgsConstructor @Transactional(readOnly = true) public class TeamQueryService { private final TeamRepository teamRepository; + private final TacticPositionDetailRepository tacticPositionDetailRepository; private final TeamMembersRepository teamMembersRepository; - public GetTeamResponseDto getMyTeamById(Long teamId) { + public GetTeamResponseDto getMyTeamById(Long teamId, User user) { Team team = teamRepository.findById(teamId).orElseThrow(() ->new TeamExceptionHandler(ErrorCode.TEAM_NOT_FOUND)); + if(!user.getTeam().contains(team)) { + throw new TeamExceptionHandler(ErrorCode.NO_AUTHORIZATION); + } return GetTeamResponseDto.from(team); } - public List getMyTeamList(User user) { - List teams = user.getTeam(); - return GetTeamResponseDto.TeamList.from(teams); +public List getMyTeamList(User user) { + List teamMembers = teamMembersRepository.findByUser(user); + List teamLists = new ArrayList<>(); + for (TeamMember teamMember : teamMembers) { + Team team = teamMember.getTeam(); + teamLists.add(GetTeamResponseDto.TeamList.from(team, teamMember)); } - - public List getIndividualDetail(Long teamId, Long memberId, User user) { + return teamLists; +} + public GetTeamResponseDto.getIndividualDetail getIndividualDetail(Long teamId, Long tacticPositionDetailId) { Team team = teamRepository.findById(teamId).orElseThrow(() ->new TeamExceptionHandler(ErrorCode.TEAM_NOT_FOUND)); - TeamMember teamMember = teamMembersRepository.findById(memberId).orElseThrow(() ->new TeamExceptionHandler(ErrorCode.CANNOT_FIND_TEAMMEMBER)); + TacticPositionDetail tacticPositionDetail = tacticPositionDetailRepository.findById(tacticPositionDetailId).orElseThrow(() -> new TeamExceptionHandler(ErrorCode.DETAIL_NOT_FOUND)); List tacticPositionDetails = team.getTactic().getTacticPositionDetails(); - List individualDetails = new ArrayList<>(); - - for (TacticPositionDetail tacticDetail : tacticPositionDetails) { - GetTeamResponseDto.getIndividualDetail individualDetail = - GetTeamResponseDto.getIndividualDetail.from(tacticDetail, teamMember); - individualDetails.add(individualDetail); + TeamMember byTeamAndPosition = teamMembersRepository.findByTeamAndPosition(team, tacticPositionDetail.getPosition()); + if(tacticPositionDetails.contains(tacticPositionDetail)) { + return GetTeamResponseDto.getIndividualDetail.from(team, tacticPositionDetail, byTeamAndPosition); } - return individualDetails; + else + return GetTeamResponseDto.getIndividualDetail.from(team, tacticPositionDetail, null); } } diff --git a/src/main/java/com/capstone/BnagFer/domain/tactic/entity/TacticPositionDetail.java b/src/main/java/com/capstone/BnagFer/domain/tactic/entity/TacticPositionDetail.java index e406e46d..a40a9d3a 100644 --- a/src/main/java/com/capstone/BnagFer/domain/tactic/entity/TacticPositionDetail.java +++ b/src/main/java/com/capstone/BnagFer/domain/tactic/entity/TacticPositionDetail.java @@ -1,5 +1,6 @@ package com.capstone.BnagFer.domain.tactic.entity; +import com.capstone.BnagFer.domain.myteam.entity.TeamMember; import com.capstone.BnagFer.domain.tactic.dto.DetailUpdateRequest; import jakarta.persistence.*; import lombok.*; diff --git a/src/main/java/com/capstone/BnagFer/domain/tactic/service/TacticService.java b/src/main/java/com/capstone/BnagFer/domain/tactic/service/TacticService.java index 29b7fb12..a8d0ca02 100644 --- a/src/main/java/com/capstone/BnagFer/domain/tactic/service/TacticService.java +++ b/src/main/java/com/capstone/BnagFer/domain/tactic/service/TacticService.java @@ -1,5 +1,4 @@ package com.capstone.BnagFer.domain.tactic.service; - import com.capstone.BnagFer.domain.accounts.entity.User; import com.capstone.BnagFer.global.util.RedisUtil; import com.capstone.BnagFer.domain.accounts.service.account.AccountsCommonService; @@ -19,7 +18,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Optional; - @Service @RequiredArgsConstructor @Transactional @@ -145,6 +143,28 @@ public void deleteComment(Long commentId, User user) { redisUtil.saveCommentCount(tacticId, commentCount); } +public ApiResponse likeButton(Long tacticId, User user) { + + Tactic tactic = tacticRepository.findById(tacticId).orElseThrow(() -> new TacticExceptionHandler(ErrorCode.TACTIC_NOT_FOUND)); + + Optional like = likeRepository.findByUserAndTactic(user, tactic); + + long likeCount = redisUtil.getLikeCount(tacticId); + + if (like.isPresent()) { + likeRepository.delete(like.get()); + likeCount--; + redisUtil.saveLikeCount(tacticId, likeCount); + return ApiResponse.CANCELED_LIKE(); + } else { + likeRepository.save(new TacticLike(user, tactic)); + likeCount++; + redisUtil.saveLikeCount(tacticId, likeCount); + return ApiResponse.SUCCESS_LIKE(); + } +} + + public ApiResponse likeButton(Long tacticId, User user) { Tactic tactic = tacticRepository.findById(tacticId).orElseThrow(() -> new TacticExceptionHandler(ErrorCode.TACTIC_NOT_FOUND)); diff --git a/src/main/java/com/capstone/BnagFer/global/config/RedisConfig.java b/src/main/java/com/capstone/BnagFer/global/config/RedisConfig.java index 8f99a22e..216da1c5 100644 --- a/src/main/java/com/capstone/BnagFer/global/config/RedisConfig.java +++ b/src/main/java/com/capstone/BnagFer/global/config/RedisConfig.java @@ -6,6 +6,7 @@ import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration diff --git a/src/main/java/com/capstone/BnagFer/global/util/RedisUtil.java b/src/main/java/com/capstone/BnagFer/global/util/RedisUtil.java index 3979521e..6cf71761 100644 --- a/src/main/java/com/capstone/BnagFer/global/util/RedisUtil.java +++ b/src/main/java/com/capstone/BnagFer/global/util/RedisUtil.java @@ -1,15 +1,11 @@ package com.capstone.BnagFer.global.util; - import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; - import java.util.concurrent.TimeUnit; - @Component @RequiredArgsConstructor public class RedisUtil { - private final RedisTemplate redisTemplate; public void save(String key, Object val, Long time, TimeUnit timeUnit) { @@ -20,15 +16,33 @@ public void saveLikeCount(Long tacticId, Long likeCount) { redisTemplate.opsForValue().set("tactic:" + tacticId + ":likeCount", likeCount.toString()); } - public void saveCommentCount(Long tacticId, Long commentCount){ - redisTemplate.opsForValue().set("tactic:" + tacticId + ":commentCount", commentCount.toString()); - } - public Long getLikeCount(Long tacticId) { String likeCountStr = (String) redisTemplate.opsForValue().get("tactic:" + tacticId + ":likeCount"); return likeCountStr != null ? Long.valueOf(likeCountStr) : null; } + public void boardSaveLikeCount(Long boardId, Long likeCount) { + redisTemplate.opsForValue().set("board:" + boardId + ":likeCount", likeCount.toString()); + } + + public Long boardGetLikeCount(Long boardId) { + String likeCountStr = (String) redisTemplate.opsForValue().get("board:" + boardId + ":likeCount"); + return likeCountStr != null ? Long.valueOf(likeCountStr) : null; + } + + public void boardSaveCommentCount(Long boardId, Long commentCount) { + redisTemplate.opsForValue().set("board:" + boardId + ":commentCount", commentCount.toString()); + } + + public Long boardGetCommentCount(Long boardId){ + String commentCountStr = (String) redisTemplate.opsForValue().get("board:" + boardId + ":commentCount"); + return commentCountStr != null ? Long.valueOf(commentCountStr) : null; + } + + public void saveCommentCount(Long tacticId, Long commentCount){ + redisTemplate.opsForValue().set("tactic:" + tacticId + ":commentCount", commentCount.toString()); + } + public Long getCommentCount(Long tacticId){ String commentCountStr = (String) redisTemplate.opsForValue().get("tactic:" + tacticId + ":commentCount"); return commentCountStr != null ? Long.valueOf(commentCountStr) : null; @@ -50,7 +64,6 @@ public void saveFCMToken(String userEmail, String fcmToken) { redisTemplate.opsForValue().set(userEmail, fcmToken); redisTemplate.expire(userEmail, 30, TimeUnit.DAYS); } - public String getFCMToken(String userEmail) { Object tokenObj = redisTemplate.opsForValue().get(userEmail); if (tokenObj != null) { @@ -59,9 +72,7 @@ public String getFCMToken(String userEmail) { return null; } } - public void removeFCMToken(String userEmail) { redisTemplate.delete(userEmail); } -} - +} \ No newline at end of file