SSE를 통해 알림 기능 구현
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/notification")
public class NotificationController {
private final NotificationService notificationService;
public static Map<Long, SseEmitter> sseEmitters = new ConcurrentHashMap<>();
@GetMapping( "/subscribe")
public SseEmitter notification(@AuthMember Member member) {
SseEmitter sseEmitter = notificationService.subscribe(member.getId());
return sseEmitter;
}
}
@Service
@RequiredArgsConstructor
public class NotificationService {
public SseEmitter subscribe(Long memberId) {
SseEmitter sseEmitter = new SseEmitter(Long.MAX_VALUE);
try{
sseEmitter.send(SseEmitter.event().name("connect"));
} catch (IOException e) {
throw new BisException(ErrorCode.INTERNAL_SERVER_ERROR);
}
NotificationController.sseEmitters.put(memberId, sseEmitter);
sseEmitter.onCompletion(()-> NotificationController.sseEmitters.remove(memberId));
sseEmitter.onTimeout(()-> NotificationController.sseEmitters.remove(memberId));
sseEmitter.onError((e)-> NotificationController.sseEmitters.remove(memberId));
return sseEmitter;
}
public void notifyInviting(Long memberId, String clubTitle){
if(NotificationController.sseEmitters.containsKey(memberId)){
SseEmitter sseEmitterReceiver = NotificationController.sseEmitters.get(memberId);
try{
sseEmitterReceiver.send(SseEmitter
.event()
.name("invitedClub")
.data(clubTitle+"에 초대되었습니다."));
} catch (IOException e){
NotificationController.sseEmitters.remove(memberId);
}
}
}
public void notifyMessage(Long memberId){
if(NotificationController.sseEmitters.containsKey(memberId)){
SseEmitter sseEmitterReceiver = NotificationController.sseEmitters.get(memberId);
try{
sseEmitterReceiver.send(SseEmitter
.event()
.name("message")
.data("채팅메세지가 도착했습니다."));
} catch (IOException e){
NotificationController.sseEmitters.remove(memberId);
}
}
}
}
알림 기능은 두 군데에 사용되고 있다. 첫 번째는 클럽에 초대되었을 때와, 채팅 메시지가 도착했을 때다.
MemberService의 클럽초대 메서드 끝에 notifyInviting 메서드를 추가해 주면 SseEmitter에 이벤트를 발생시키고 데이터로 해당 알림 내용을 보낸다.
function connectSse(){
const eventSource = new EventSource(`/api/notification/subscribe`);
eventSource.addEventListener("invitedClub", function (event) {
console.log(event.data);
const data = event.data;
(async () => {
//브라우저 알림
const showNotification = () => {
const notification = new Notification('메세지', {
body: data
});
setTimeout(() => {
notification.close();
}, 10 * 1000);
notification.addEventListener('click', () => {
window.open(data.url, 'blank');
});
}
let granted = false;
if (Notification.permission === 'granted') {
granted = true;
} else if (Notification.permission !== 'denied') {
let permission = await Notification.requestPermission();
granted = permission === 'granted';
}
if (granted) {
showNotification();
}
})();
})
프런트에서는 해당 이벤트가 발생할 시 알림을 띄워주는 코드를 작성해 준다.
'개발일지' 카테고리의 다른 글
MySQL 성능 개선 프로젝트 2 (0) | 2024.09.03 |
---|---|
MySQL 성능 개선 프로젝트 1 (0) | 2024.09.02 |
20240118 (0) | 2024.01.18 |
20240116 (0) | 2024.01.17 |
20240115 (0) | 2024.01.15 |