본문 바로가기
Project

팀 프로젝트 3. Trello 2일차: 댓글 생성시 card의 모든 worker 에게 알림 보내기

by 우 석 2024. 3. 19.

팀 프로젝트 2일 차 내가 맡은 구현부는 card에서 사용자들이 댓글로 대화할 수 있는 기능에, 댓글이 생성되면 해당 card의 모든 worker에게 알림을 보내는 기능 구현이다.

 

댓글을 작성하는 CRUD 기능구현 설명은 블로그 내용에서 생략하고, 알림을 보내는 기능 위주로 설명하겠다.

 

특정 카드에 댓글이 추가될 때 작업자에게 알림을 보내는 메서드로,  CommentService에서 구현한 해당 카드에 대한 가장 최근의 댓글을 가져온 후, 카드에 연결된 worker들을 찾는다. 작업자 목록을 순회하면서 각 작업자에게 SSE (Server-Sent Events) Emitter를 사용하여 알림을 전송한다. 알림을 보낸 후에는 알림 정보를 데이터베이스에 저장하고, 작업자의 알림 수를 증가한다. 만약 예외가 발생한 경우 해당 작업자의 SSE Emitter를 제거한다.

// NotificationService.java

@Transactional
public void notifyComment(Long cardId) {

    // 카드에 대한 가장 최근의 댓글을 찾습니다.
    Comment receiveComment = commentService.findLatestComment(cardId);

    // 해당 카드에 연결된 작업자 목록을 가져옵니다.
    List<Long> workers = workerRepository.findByCardId(cardId);

    // 작업자 목록을 순회합니다.
    for (Long workerId : workers) {

        // 작업자에 대한 SSE (Server-Sent Events) Emitter가 있는지 확인합니다.
        if (NotificationController.sseEmitters.containsKey(workerId)) {
            // 작업자에 대한 SSE Emitter를 가져옵니다.
            SseEmitter sseEmitter = NotificationController.sseEmitters.get(workerId);
            try {
                // 댓글에 대한 이벤트 데이터를 구성합니다.
                Map<String, String> eventData = new HashMap<>();
                eventData.put("sender", receiveComment.getNickname() + " 님이 댓글을 작성했습니다.");
                eventData.put("contents", receiveComment.getComment());

                // SSE Emitter를 통해 이벤트를 전송합니다.
                sseEmitter.send(SseEmitter.event().name("addComment").data(eventData));

                // 알림 객체를 생성하고 저장합니다.
                Notification notification = Notification.builder()
                    .cardId(cardId)
                    .userId(workerId)
                    .sender(receiveComment.getNickname())
                    .contents(receiveComment.getComment())
                    .build();

                notificationRepository.save(notification);

                // 작업자의 알림 수를 증가시킵니다.
                notificationCounts.put(workerId,
                    notificationCounts.getOrDefault(workerId, 0) + 1);

                // 알림 수를 SSE Emitter를 통해 전송합니다.
                sseEmitter.send(SseEmitter.event().name("notificationCount")
                    .data(notificationCounts.get(workerId)));

            } catch (IOException e) {
                // 예외가 발생한 경우 해당 작업자의 SSE Emitter를 제거합니다.
                NotificationController.sseEmitters.remove(workerId);
            }
        }
    }
}

 

 

worker들의 id를 가져오기 위해 Qdsl로 작성했다.

// WorkerRepositoryCustomImpl.java
@Override
public List<Long> findByCardId(Long cardId) {
    QWorker worker = QWorker.worker;

    return jpaQueryFactory.select(worker.user_id)
        .from(worker)
        .where(worker.card_id.eq(cardId))
        .fetch();
	}

 

 

notifyComment(Long cardId) 메서드를 CommentController의 createComment 메서드에 적용하여, 댓글 생성시 알림을 보낼 수 있다.

// CommentController.java

@RestController
@RequiredArgsConstructor
@RequestMapping("/cards/{cardId}/comments")
public class CommentController {

    private final CommentService commentService;
    private final NotificationService notificationService;

    @PostMapping
    public ResponseEntity<Void> createComment(
        @PathVariable Long cardId,
        @RequestBody CommentRequestDto commentRequestDto,
        @AuthenticationPrincipal UserDetailsImpl userDetails
    ) {
        commentService.createComment(cardId, commentRequestDto, userDetails.getUser());
        notificationService.notifyComment(cardId); // 알림 메서드 적용
        return ResponseEntity.status(HttpStatus.CREATED).build();
    }
    ...
 }