From 08e3b9571b488fc257047056691c818bb86aa1d3 Mon Sep 17 00:00:00 2001 From: Jaewon Lee <58386334+jaewonLeeKOR@users.noreply.github.com> Date: Wed, 11 Sep 2024 00:10:24 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20#126=20=EB=B9=84=EC=A6=88=EB=8B=88?= =?UTF-8?q?=EC=8A=A4=20=EB=A1=9C=EC=A7=81=EA=B3=BC=20=EC=9B=90=EA=B2=A9=20?= =?UTF-8?q?=EC=95=8C=EB=A6=BC=20=EB=B0=9C=EC=86=A1=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/apns/dto/ApnsClientRequest.java | 10 +++--- .../config/apns/service/ApnsServiceImpl.java | 1 + .../board/service/BoardServiceImpl.java | 21 +++++++----- .../service/BoardCommentServiceImpl.java | 11 +++++++ .../entity/BoardSubscribeMember.java | 24 ++++++++++++++ .../BoardSubscribeMemberRepository.java | 13 ++++++++ .../service/BoardSubscribeMemberService.java | 12 +++++++ .../BoardSubscribeMemberServiceImpl.java | 33 +++++++++++++++++++ 8 files changed, 113 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/server/capple/domain/boardSubscribeMember/entity/BoardSubscribeMember.java create mode 100644 src/main/java/com/server/capple/domain/boardSubscribeMember/reposiotry/BoardSubscribeMemberRepository.java create mode 100644 src/main/java/com/server/capple/domain/boardSubscribeMember/service/BoardSubscribeMemberService.java create mode 100644 src/main/java/com/server/capple/domain/boardSubscribeMember/service/BoardSubscribeMemberServiceImpl.java diff --git a/src/main/java/com/server/capple/config/apns/dto/ApnsClientRequest.java b/src/main/java/com/server/capple/config/apns/dto/ApnsClientRequest.java index eb804673..a4c57f98 100644 --- a/src/main/java/com/server/capple/config/apns/dto/ApnsClientRequest.java +++ b/src/main/java/com/server/capple/config/apns/dto/ApnsClientRequest.java @@ -11,9 +11,9 @@ public class ApnsClientRequest { @ToString public static class SimplePushBody { private Aps aps; - - public SimplePushBody(String title, String subTitle, String body, Integer badge, String threadId, String targetContentId) { - this.aps = new Aps(new Aps.Alert(title, subTitle, body), badge, threadId, targetContentId); + @Builder + public SimplePushBody(String title, String subTitle, String body, Integer badge, String sound, String threadId, String targetContentId) { + this.aps = new Aps(new Aps.Alert(title, subTitle, body), badge, sound, threadId, targetContentId); } @ToString @@ -23,6 +23,8 @@ public SimplePushBody(String title, String subTitle, String body, Integer badge, public static class Aps { private Alert alert; private Integer badge; + @Schema(defaultValue = "default") + private String sound; // Library/Sounds 폴더 내의 파일 이름 @JsonProperty("thread-id") private String threadId; @JsonProperty("target-content-id") @@ -58,7 +60,7 @@ public static class Aps { private Integer badge; // 앱 아이콘에 표시할 뱃지 숫자 @Schema(defaultValue = "default") private String sound; // Library/Sounds 폴더 내의 파일 이름 - @Schema(defaultValue = "thread-id") + @JsonProperty("thread-id") private String threadId; // 알림 그룹화를 위한 thread id (UNNotificationContent 객체의 threadIdentifier와 일치해야 함) private String category; // 알림 그룹화를 위한 category, (UNNotificationCategory 식별자와 일치해야 함) @Schema(defaultValue = "0") diff --git a/src/main/java/com/server/capple/config/apns/service/ApnsServiceImpl.java b/src/main/java/com/server/capple/config/apns/service/ApnsServiceImpl.java index 81acd50b..592c102a 100644 --- a/src/main/java/com/server/capple/config/apns/service/ApnsServiceImpl.java +++ b/src/main/java/com/server/capple/config/apns/service/ApnsServiceImpl.java @@ -58,6 +58,7 @@ public Boolean sendApns(T request, List deviceToken) { deviceToken.parallelStream() .forEach(token -> { + if (token.isBlank()) return; tmpWebClient .method(HttpMethod.POST) .uri(token) diff --git a/src/main/java/com/server/capple/domain/board/service/BoardServiceImpl.java b/src/main/java/com/server/capple/domain/board/service/BoardServiceImpl.java index ad3bd6c4..2498871e 100644 --- a/src/main/java/com/server/capple/domain/board/service/BoardServiceImpl.java +++ b/src/main/java/com/server/capple/domain/board/service/BoardServiceImpl.java @@ -6,7 +6,9 @@ import com.server.capple.domain.board.mapper.BoardMapper; import com.server.capple.domain.board.repository.BoardHeartRedisRepository; import com.server.capple.domain.board.repository.BoardRepository; +import com.server.capple.domain.boardSubscribeMember.service.BoardSubscribeMemberService; import com.server.capple.domain.member.entity.Member; +import com.server.capple.domain.notifiaction.service.NotificationService; import com.server.capple.global.exception.RestApiException; import com.server.capple.global.exception.errorCode.BoardErrorCode; import lombok.RequiredArgsConstructor; @@ -24,6 +26,8 @@ public class BoardServiceImpl implements BoardService { private final BoardRepository boardRepository; private final BoardHeartRedisRepository boardHeartRedisRepository; private final BoardMapper boardMapper; + private final NotificationService notificationService; + private final BoardSubscribeMemberService boardSubscribeMemberService; @Override public BoardResponse.BoardCreate createBoard(Member member, BoardType boardType, String content) { @@ -33,6 +37,7 @@ public BoardResponse.BoardCreate createBoard(Member member, BoardType boardType, } else { throw new RestApiException(BoardErrorCode.BOARD_BAD_REQUEST); } + boardSubscribeMemberService.createBoardSubscribeMember(member, board); return boardMapper.toBoardCreate(board); } @@ -49,8 +54,8 @@ public BoardResponse.BoardsGetByBoardType getBoardsByBoardType(BoardType boardTy throw new RestApiException(BoardErrorCode.BOARD_BAD_REQUEST); } return boardMapper.toBoardsGetByBoardType(boards.stream() - .map(board -> boardMapper.toBoardsGetByBoardTypeBoardInfo(board, boardHeartRedisRepository.getBoardHeartsCount(board.getId()))) - .toList() + .map(board -> boardMapper.toBoardsGetByBoardTypeBoardInfo(board, boardHeartRedisRepository.getBoardHeartsCount(board.getId()))) + .toList() ); } @@ -62,6 +67,7 @@ public BoardResponse.BoardDelete deleteBoard(Member member, Long boardId) { } board.delete(); + boardSubscribeMemberService.deleteBoardSubscribeMemberByBoardId(boardId); return boardMapper.toBoardDelete(board); } @@ -69,23 +75,22 @@ public BoardResponse.BoardDelete deleteBoard(Member member, Long boardId) { public BoardResponse.BoardsSearchByKeyword searchBoardsByKeyword(String keyword) { List boards = boardRepository.findBoardsByKeyword(keyword); return boardMapper.toBoardsSearchByKeyword(boards.stream() - .map(board -> boardMapper.toBoardsSearchByKeywordBoardInfo(board, boardHeartRedisRepository.getBoardHeartsCount(board.getId()))) - .toList()); + .map(board -> boardMapper.toBoardsSearchByKeywordBoardInfo(board, boardHeartRedisRepository.getBoardHeartsCount(board.getId()))) + .toList()); } @Override public BoardResponse.BoardToggleHeart toggleBoardHeart(Member member, Long boardId) { Board board = findBoard(boardId); - System.out.println(boardHeartRedisRepository.getBoardHeartCreateAt(board.getId(), member.getId())); - - Boolean isLiked = boardHeartRedisRepository.toggleBoardHeart(member.getId(), board.getId()); + boolean isLiked = boardHeartRedisRepository.toggleBoardHeart(member.getId(), board.getId()); + if (isLiked) notificationService.sendBoardHeartNotification(member.getId(), board); return new BoardResponse.BoardToggleHeart(boardId, isLiked); } @Override public Board findBoard(Long boardId) { return boardRepository.findById(boardId) - .orElseThrow(() -> new RestApiException(BoardErrorCode.BOARD_NOT_FOUND)); + .orElseThrow(() -> new RestApiException(BoardErrorCode.BOARD_NOT_FOUND)); } diff --git a/src/main/java/com/server/capple/domain/boardComment/service/BoardCommentServiceImpl.java b/src/main/java/com/server/capple/domain/boardComment/service/BoardCommentServiceImpl.java index 1890632b..9be22805 100644 --- a/src/main/java/com/server/capple/domain/boardComment/service/BoardCommentServiceImpl.java +++ b/src/main/java/com/server/capple/domain/boardComment/service/BoardCommentServiceImpl.java @@ -11,8 +11,10 @@ import com.server.capple.domain.boardComment.mapper.BoardCommentMapper; import com.server.capple.domain.boardComment.repository.BoardCommentHeartRedisRepository; import com.server.capple.domain.boardComment.repository.BoardCommentRepository; +import com.server.capple.domain.boardSubscribeMember.service.BoardSubscribeMemberService; import com.server.capple.domain.member.entity.Member; import com.server.capple.domain.member.service.MemberService; +import com.server.capple.domain.notifiaction.service.NotificationService; import com.server.capple.global.exception.RestApiException; import com.server.capple.global.exception.errorCode.CommentErrorCode; import lombok.RequiredArgsConstructor; @@ -30,6 +32,8 @@ public class BoardCommentServiceImpl implements BoardCommentService { private final BoardCommentRepository boardCommentRepository; private final BoardCommentHeartRedisRepository boardCommentHeartRedisRepository; private final BoardCommentMapper boardCommentMapper; + private final NotificationService notificationService; + private final BoardSubscribeMemberService boardSubscribeMemberService; @Override @Transactional @@ -39,6 +43,8 @@ public BoardCommentId createBoardComment(Member member, Long boardId, BoardComme BoardComment boardComment = boardCommentRepository.save( boardCommentMapper.toBoardCommentEntity(loginMember, board, request.getComment())); + notificationService.sendBoardCommentNotification(loginMember.getId(), board, boardComment); // 게시글 댓글 알림 + boardSubscribeMemberService.createBoardSubscribeMember(loginMember, board); // 알림 리스트 추가 return new BoardCommentId(boardComment.getId()); } @@ -69,6 +75,11 @@ public BoardCommentId deleteBoardComment(Member member, Long commentId) { public BoardCommentHeart heartBoardComment(Member member, Long commentId) { Boolean isLiked = boardCommentHeartRedisRepository. toggleBoardCommentHeart(commentId, member.getId()); + if(isLiked) { + BoardComment boardComment = boardCommentRepository.findById(commentId).get(); + if(!boardComment.getMember().getId().equals(member.getId())) + notificationService.sendBoardCommentHeartNotification(member.getId(), boardComment.getBoard(), boardComment); + } return new BoardCommentHeart(commentId, isLiked); } diff --git a/src/main/java/com/server/capple/domain/boardSubscribeMember/entity/BoardSubscribeMember.java b/src/main/java/com/server/capple/domain/boardSubscribeMember/entity/BoardSubscribeMember.java new file mode 100644 index 00000000..41ae5622 --- /dev/null +++ b/src/main/java/com/server/capple/domain/boardSubscribeMember/entity/BoardSubscribeMember.java @@ -0,0 +1,24 @@ +package com.server.capple.domain.boardSubscribeMember.entity; + +import com.server.capple.domain.board.entity.Board; +import com.server.capple.domain.member.entity.Member; +import jakarta.persistence.*; +import lombok.*; + +@Getter +@Entity +@AllArgsConstructor +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class BoardSubscribeMember { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @ManyToOne + @JoinColumn(name = "member_id", nullable = false) + private Member member; + + @ManyToOne + @JoinColumn(name = "board_id", nullable = false) + private Board board; +} diff --git a/src/main/java/com/server/capple/domain/boardSubscribeMember/reposiotry/BoardSubscribeMemberRepository.java b/src/main/java/com/server/capple/domain/boardSubscribeMember/reposiotry/BoardSubscribeMemberRepository.java new file mode 100644 index 00000000..8267aa3f --- /dev/null +++ b/src/main/java/com/server/capple/domain/boardSubscribeMember/reposiotry/BoardSubscribeMemberRepository.java @@ -0,0 +1,13 @@ +package com.server.capple.domain.boardSubscribeMember.reposiotry; + +import com.server.capple.domain.boardSubscribeMember.entity.BoardSubscribeMember; +import com.server.capple.domain.member.entity.Member; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface BoardSubscribeMemberRepository extends JpaRepository { + Boolean existsByMemberIdAndBoardId(Long memberId, Long boardId); + List findBoardSubscribeMembersByBoardId(Long boardId); + void deleteBoardSubscribeMemberByBoardId(Long boardId); +} diff --git a/src/main/java/com/server/capple/domain/boardSubscribeMember/service/BoardSubscribeMemberService.java b/src/main/java/com/server/capple/domain/boardSubscribeMember/service/BoardSubscribeMemberService.java new file mode 100644 index 00000000..b1d37e67 --- /dev/null +++ b/src/main/java/com/server/capple/domain/boardSubscribeMember/service/BoardSubscribeMemberService.java @@ -0,0 +1,12 @@ +package com.server.capple.domain.boardSubscribeMember.service; + +import com.server.capple.domain.board.entity.Board; +import com.server.capple.domain.member.entity.Member; + +import java.util.List; + +public interface BoardSubscribeMemberService { + void createBoardSubscribeMember(Member member, Board board); + List findBoardSubscribeMembers(Long boardId); + void deleteBoardSubscribeMemberByBoardId(Long boardId); +} diff --git a/src/main/java/com/server/capple/domain/boardSubscribeMember/service/BoardSubscribeMemberServiceImpl.java b/src/main/java/com/server/capple/domain/boardSubscribeMember/service/BoardSubscribeMemberServiceImpl.java new file mode 100644 index 00000000..a9c5fb24 --- /dev/null +++ b/src/main/java/com/server/capple/domain/boardSubscribeMember/service/BoardSubscribeMemberServiceImpl.java @@ -0,0 +1,33 @@ +package com.server.capple.domain.boardSubscribeMember.service; + +import com.server.capple.domain.board.entity.Board; +import com.server.capple.domain.boardSubscribeMember.entity.BoardSubscribeMember; +import com.server.capple.domain.boardSubscribeMember.reposiotry.BoardSubscribeMemberRepository; +import com.server.capple.domain.member.entity.Member; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class BoardSubscribeMemberServiceImpl implements BoardSubscribeMemberService { + private final BoardSubscribeMemberRepository boardSubscribeMemberRepository; + @Override + public void createBoardSubscribeMember(Member member, Board board) { + if(boardSubscribeMemberRepository.existsByMemberIdAndBoardId(member.getId(), board.getId())) { + return; + } + boardSubscribeMemberRepository.save(BoardSubscribeMember.builder().member(member).board(board).build()); + } + + @Override + public List findBoardSubscribeMembers(Long boardId) { + return boardSubscribeMemberRepository.findBoardSubscribeMembersByBoardId(boardId).stream().map(BoardSubscribeMember::getMember).toList(); + } + + @Override + public void deleteBoardSubscribeMemberByBoardId(Long boardId) { + boardSubscribeMemberRepository.deleteBoardSubscribeMemberByBoardId(boardId); + } +}