Skip to content

Commit

Permalink
[COZY-234] 방 입장 시 알림, 스케줄러 알림 전송 비동기로 처리 (#94)
Browse files Browse the repository at this point in the history
* [COZY-234] feat : 방 입장 시 알림 전송

* [COZY-234] fix : 비동기 문제 해결 완료
  • Loading branch information
momuzzi authored Aug 29, 2024
1 parent b9e57a2 commit eebca19
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.cozymate.cozymate_server.domain.fcm.dto;

import com.cozymate.cozymate_server.domain.member.Member;
import com.cozymate.cozymate_server.domain.room.Room;
import java.util.List;
import lombok.Getter;

Expand All @@ -10,25 +11,36 @@ public class FcmPushContentDto {
private Member member;
private String roleContent;
private List<String> todoContents;
private Room room;

private FcmPushContentDto(Member member, Room room) {
this.member = member;
this.room = room;
roleContent = null;
todoContents = null;
}

private FcmPushContentDto(Member member) {
this.member = member;
roleContent = null;
todoContents = null;
room = null;
}

// 투두 내용 리스트로 전부 줘야하는 경우, 00시 투드 리스트 스케줄러
private FcmPushContentDto(Member member, List<String> todoContents) {
this.member = member;
this.todoContents = todoContents;
roleContent = null;
room = null;
}

// 롤 내용 하나만 줘야하는 경우, 21시 미완료 Role 한개만 리마인더 스케줄러
private FcmPushContentDto(Member member, String roleContent) {
this.member= member;
this.roleContent = roleContent;
todoContents = null;
room = null;
}

private FcmPushContentDto() {
Expand All @@ -46,6 +58,10 @@ public static FcmPushContentDto create(Member member, List<String> todoContents)
return new FcmPushContentDto(member, todoContents);
}

public static FcmPushContentDto create(Member member, Room room) {
return new FcmPushContentDto(member, room);
}

// 방이 열렸어요 -> 에서 사용합니다!
public static FcmPushContentDto create() {
return new FcmPushContentDto();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.cozymate.cozymate_server.domain.member.Member;
import com.cozymate.cozymate_server.domain.notificationlog.enums.NotificationType;
import com.cozymate.cozymate_server.domain.room.Room;
import java.util.List;
import lombok.Getter;

Expand Down Expand Up @@ -134,5 +135,25 @@ public static GroupWithOutMeTargetDto create(Member me, List<Member> memberList,
}
}

@Getter
public static class GroupRoomNameWithOutMeTargetDto {

private final Member me;
private final List<Member> memberList;
private final Room room;
private final NotificationType notificationType;

private GroupRoomNameWithOutMeTargetDto(Member me, List<Member> memberList, Room room,
NotificationType notificationType) {
this.me = me;
this.memberList = memberList;
this.room = room;
this.notificationType = notificationType;
}

public static GroupRoomNameWithOutMeTargetDto create(Member me, List<Member> memberList,
Room room, NotificationType notificationType) {
return new GroupRoomNameWithOutMeTargetDto(me, memberList, room, notificationType);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.cozymate.cozymate_server.domain.fcm.Fcm;
import com.cozymate.cozymate_server.domain.fcm.dto.FcmPushContentDto;
import com.cozymate.cozymate_server.domain.fcm.dto.FcmPushTargetDto.GroupRoomNameWithOutMeTargetDto;
import com.cozymate.cozymate_server.domain.fcm.dto.FcmPushTargetDto.GroupWithOutMeTargetDto;
import com.cozymate.cozymate_server.domain.fcm.repository.FcmRepository;
import com.cozymate.cozymate_server.domain.member.Member;
Expand All @@ -11,10 +12,10 @@
import com.cozymate.cozymate_server.domain.fcm.dto.FcmPushTargetDto.GroupTargetDto;
import com.cozymate.cozymate_server.domain.fcm.dto.FcmPushTargetDto.OneTargetReverseDto;
import com.cozymate.cozymate_server.domain.fcm.dto.FcmPushTargetDto.OneTargetDto;
import com.cozymate.cozymate_server.domain.room.Room;
import com.google.firebase.messaging.FirebaseMessaging;
import com.google.firebase.messaging.FirebaseMessagingException;
import com.google.firebase.messaging.Message;
import com.google.firebase.messaging.Notification;
import java.util.HashMap;
import java.util.List;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -260,4 +261,78 @@ private String getContent(Member member, NotificationType notificationType,
return notificationType.generateContent(
FcmPushContentDto.create(member, todoContents));
}
















/**
* 방 입장 시 : 방에 속한 메이트 모두에게 [방이름]에 [닉네임]님이 뛰어들어왔어요! 알림 전송
*/
public void sendNotification(GroupRoomNameWithOutMeTargetDto target) {
List<Member> memberList = target.getMemberList(); // 알림을 받을 멤버 리스트
Member me = target.getMe(); // 알림 내용에 들어갈 멤버 (의 이름)
Room room = target.getRoom(); // 알림 내용에 들어갈 방 (의 이름)

memberList.forEach(member -> {
sendNotificationToMember(me, room, member, target.getNotificationType());
});
}

private void sendNotificationToMember(Member contentMember, Room room, Member recipientMember,
NotificationType notificationType) {
List<Message> messages = createMessage(contentMember, room, recipientMember, notificationType);

messages.forEach(message -> {
try {
firebaseMessaging.send(message);
} catch (FirebaseMessagingException e) {
log.error("cannot send to member push message. error info : {}", e.getMessage());
}
});

NotificationLog notificationLog = NotificationLog.builder()
.member(recipientMember)
.category(notificationType.getCategory())
.content(getContent(contentMember, room, notificationType))
.build();

notificationLogRepository.save(notificationLog);
}

private List<Message> createMessage(Member contentMember, Room room, Member recipientMember, NotificationType notificationType) {
List<Fcm> fcmList = fcmRepository.findByMember(recipientMember);

List<Message> messages = fcmList.stream()
.map(fcm -> {
String token = fcm.getToken();
String content = getContent(contentMember, room, notificationType);

HashMap<String, String> messageMap = new HashMap<>();
messageMap.put("title", NOTIFICATION_TITLE);
messageMap.put("body", content);

return Message.builder()
.putAllData(messageMap)
.setToken(token)
.build();
}).toList();

return messages;
}

private String getContent(Member member, Room room, NotificationType notificationType) {
return notificationType.generateContent(FcmPushContentDto.create(member, room));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,7 @@ Optional<Mate> findByMemberIdAndEntryStatusAndRoomStatusIn(Long memberId,
List<Mate> findByRoom(Room room);

Optional<Mate> findByMember(Member member);

@Query("select m from Mate m join fetch m.member")
List<Mate> findFetchAll();
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@ public String generateContent(FcmPushContentDto fcmPushContentDto) {
+ builder.toString();
}
},

JOIN_ROOM(NotificationCategory.COZY_HOME) {
@Override
public String generateContent(FcmPushContentDto fcmPushContentDto) {
return getNicknameShowFormat(fcmPushContentDto.getRoom().getName()) + "에 "
+ getNicknameShowFormat(fcmPushContentDto.getMember().getNickname())
+"님이 뛰어들어왔어요!";
}
}
;

private NotificationCategory category;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.cozymate.cozymate_server.domain.room.service;

import com.cozymate.cozymate_server.domain.fcm.dto.FcmPushTargetDto.GroupRoomNameWithOutMeTargetDto;
import com.cozymate.cozymate_server.domain.fcm.dto.FcmPushTargetDto.GroupWithOutMeTargetDto;
import com.cozymate.cozymate_server.domain.feed.Feed;
import com.cozymate.cozymate_server.domain.feed.converter.FeedConverter;
import com.cozymate.cozymate_server.domain.feed.repository.FeedRepository;
Expand All @@ -11,6 +13,7 @@
import com.cozymate.cozymate_server.domain.mate.repository.MateRepository;
import com.cozymate.cozymate_server.domain.member.Member;
import com.cozymate.cozymate_server.domain.member.repository.MemberRepository;
import com.cozymate.cozymate_server.domain.notificationlog.enums.NotificationType;
import com.cozymate.cozymate_server.domain.post.Post;
import com.cozymate.cozymate_server.domain.post.repository.PostRepository;
import com.cozymate.cozymate_server.domain.postcomment.PostCommentRepository;
Expand All @@ -33,6 +36,7 @@
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

@Service
Expand All @@ -57,6 +61,7 @@ public class RoomCommandService {
private final FriendRepository friendRepository;
private final RoomQueryService roomQueryService;
private final RoomLogCommandService roomLogCommandService;
private final ApplicationEventPublisher eventPublisher;

public RoomCreateResponse createRoom(RoomCreateRequest request, Member member) {
Member creator = memberRepository.findById(member.getId())
Expand Down Expand Up @@ -107,6 +112,20 @@ public void joinRoom(Long roomId, Long memberId) {
room.isRoomFull();
roomRepository.save(room);

// Room의 Mate들을 찾아온다
List<Mate> findRoomMates = mateRepository.findByRoom(room);

List<Member> memberList = findRoomMates.stream()
.map(Mate::getMember)
.filter(findMember -> !findMember.getId().equals(member.getId()))
.toList();

// 알림 내용에는 현재 코드 상 member의 이름이 담겨야하고, 현재 코드 상의 room의 이름도 담긴다
// 알림을 받는 대상은 방에 있는 메이트들이다.
// 넘겨야 할 파라미터 = member, room, memberList(알림 받을 대상 멤버 리스트), NotificationType
eventPublisher.publishEvent(GroupRoomNameWithOutMeTargetDto.create(member, memberList, room,
NotificationType.JOIN_ROOM));

}

public void deleteRoom(Long roomId, Long memberId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import java.time.LocalDate;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface TodoRepository extends JpaRepository<Todo, Long> {

Expand All @@ -14,10 +16,13 @@ public interface TodoRepository extends JpaRepository<Todo, Long> {

Integer countAllByRoomIdAndMateIdAndTimePoint(Long roomId, Long mateId, LocalDate timePoint);

List<Todo> findByTimePoint(LocalDate today);
@Query("select t from Todo t join fetch t.mate m join fetch m.member where t.timePoint = :today")
List<Todo> findByTimePoint(@Param("today") LocalDate today);

List<Todo> findByTimePointAndRoleIsNotNull(LocalDate today);
@Query("select t from Todo t join fetch t.mate m join fetch m.member where t.timePoint = :today and t.role is not null and t.completed is false")
List<Todo> findByTimePointAndRoleIsNotNullCompletedFalse(@Param("today") LocalDate today);

boolean existsByMateAndTimePointAndCompletedFalse(Mate mate, LocalDate timePoint);
List<Todo>findByTimePointAndRoleIsNotNull(LocalDate today);

boolean existsByMateAndTimePointAndCompletedFalse(Mate mate, LocalDate timePoint);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.cozymate.cozymate_server.global.event;

import com.cozymate.cozymate_server.domain.fcm.dto.FcmPushTargetDto.GroupRoomNameWithOutMeTargetDto;
import com.cozymate.cozymate_server.domain.fcm.dto.FcmPushTargetDto.GroupWithOutMeTargetDto;
import com.cozymate.cozymate_server.domain.fcm.service.FcmPushService;
import com.cozymate.cozymate_server.domain.fcm.dto.FcmPushTargetDto.GroupTargetDto;
Expand Down Expand Up @@ -51,4 +52,9 @@ public void sendNotification(OneTargetDto oneTargetDto) {
public void sendNotification(GroupWithOutMeTargetDto groupWithOutMeTargetDto) {
fcmPushService.sendNotification(groupWithOutMeTargetDto);
}

@TransactionalEventListener
public void sendNotification(GroupRoomNameWithOutMeTargetDto groupRoomNameWithOutMeTargetDto) {
fcmPushService.sendNotification(groupRoomNameWithOutMeTargetDto);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Component
@RequiredArgsConstructor
@Transactional
Expand All @@ -42,7 +44,8 @@ public class NotificationScheduler {
private final RoomRepository roomRepository;
private final RoleRepository roleRepository;

@Scheduled(cron = "0 0 0 * * *")
// 매일 자정 반복 (해당하는 날 역할을 Todo에 추가) 작업 자정에 먼저하고 나서 시작하도록 30초로 설정
@Scheduled(cron = "30 0 0 * * *")
public void sendDailyNotification() {
LocalDate today = LocalDate.now();
List<Todo> todoList = todoRepository.findByTimePoint(today);
Expand All @@ -62,10 +65,10 @@ public void sendDailyNotification() {
});
}

@Scheduled(cron = "0 0 22 * * *")
@Scheduled(cron = "0 0 21 * * *")
public void sendReminderRoleNotification() {
LocalDate today = LocalDate.now();
List<Todo> todoList = todoRepository.findByTimePointAndRoleIsNotNull(today);
List<Todo> todoList = todoRepository.findByTimePointAndRoleIsNotNullCompletedFalse(today);

Map<Member, Todo> todoMap = todoList.stream()
.filter(todo -> !todo.isCompleted())
Expand All @@ -92,7 +95,7 @@ public void addReminderRoleRoomLog() {

@Scheduled(cron = "0 0 12 L * ?")
public void sendMonthlyNotification() {
List<Mate> mates = mateRepository.findAll();
List<Mate> mates = mateRepository.findFetchAll();

List<Member> memberList = mates.stream()
.map(Mate::getMember)
Expand Down

0 comments on commit eebca19

Please sign in to comment.