개발 기록
Server-Sent Events를 이용한 실시간 댓글 알림 본문
https://velog.io/@dhk22/TIL-Day
참고한 블로그
다 썼는데 날아감;
피드에 댓글을 달면 피드 작성자에게 댓글 알림이 가는 기능을 처음에는 웹소켓으로 했었다. 알림만 가면 되므로 양방향 통신이 필요없을 것 같아 sse로 코드 변경함.
sse : 이벤트가 [서버 -> 클라이언트] 방향으로만 흐르는 단방향 통신
프론트 - 클라이언트에서 서버로 연결
$(document).ready(function () {
//로그인이 되어있다면 sse 연결
if (localStorage.getItem('token') != null) {
let eventSource = new EventSource(`http://localhost:8080/sub/` + userOwn);
//sse 연결 이벤트
eventSource.addEventListener("sse", function (event) {
console.log(event.data);
})
//댓글을 작성했을때 실행되는 이벤트
eventSource.addEventListener("addComment", function (event) {
let message = event.data;
alert(message);
})
eventSource.addEventListener("error", function (event) {
eventSource.close()
})
}
백엔드
: 컨트롤러 - 서버에서는 EventSource를 통해 날아오는 요청을 처리할 컨트롤러가 필요
@RequiredArgsConstructor
@Slf4j
@RestController
public class SseApiController {
private final NotificationService notificationService;
@CrossOrigin
@GetMapping(value = "/sub/{userId}")
public SseEmitter subscribe(@PathVariable String userId) {
return notificationService.subscribe(userId);
}
}
:서비스
1. sse 연결
@RequiredArgsConstructor
@Service
public class NotificationService {
public static Map<String, SseEmitter> sseEmitters = new ConcurrentHashMap<>();
public final FeedRepository feedRepository;
public SseEmitter subscribe(String userId) {
SseEmitter sseEmitter = new SseEmitter();
try {
// 연결!!
sseEmitter.send(SseEmitter.event().id(userId).name("sse").data("연결완료!"));
} catch (IOException e) {
throw new ApiRequestException("연결 오류!");
}
// userId값을 key값으로 해서 SseEmitter를 저장
sseEmitters.put(userId, sseEmitter);
sseEmitter.onTimeout(() -> sseEmitters.remove(userId));
sseEmitter.onCompletion(() -> sseEmitters.remove(userId));
sseEmitter.onError((e) -> sseEmitters.remove(userId));
return sseEmitter;
}
-> 피드페이지에 접속하게되면 보내준 data내용이 콘솔창에 뜨게됨 !
2. 데이터 전송
public class NotificationService {
// ...
//댓글이 달리면 피드 작성자에게 알림 생성해서 보내기.
@Transactional
public void send(Long feedId, String contents, User user) {
//해당 피드 작성자 id 찾기
Feed feed = feedRepository.findById(feedId).orElseThrow(
() -> new ApiRequestException("해당하는 피드가 없습니다.")
);
String userId = feed.getUser().getKakaoId();
String commentUsername = user.getUsername();
if (sseEmitters.containsKey(userId)) {
SseEmitter sseEmitter = sseEmitters.get(userId);
try {
//데이터 전송
sseEmitter.send(SseEmitter.event().name("addComment").data( commentUsername + "님이 작성하신 피드에 댓글을 달았습니다 " + ": "+ contents));
} catch (Exception e) {
sseEmitters.remove(userId);
}
}
}
}
이 메소드를 댓글 생성 로직에 넣어주면 댓글 생성시 같이 실행됨 !
완성 !
'TIL' 카테고리의 다른 글
220116 DTO 생성자 (완전 멍청 실수) (0) | 2022.01.16 |
---|---|
220108 TIL (2) | 2022.01.08 |
[JPA] LazyInitializationException: could not initialize proxy - no Session (0) | 2022.01.07 |
220106-0107 모의면접 후기 (0) | 2022.01.06 |
211224 til (스케줄러) (0) | 2021.12.24 |
Comments