Skip to content

Commit 21c5a1b

Browse files
committed
#80 Feat: add user in notification enroll
1 parent 88cb942 commit 21c5a1b

File tree

9 files changed

+40
-31
lines changed

9 files changed

+40
-31
lines changed

src/main/java/com/memesphere/domain/chat/service/ChatService.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ public String postChatLike(Long chat_id, Long user_id) {
8282

8383
// 사용자가 좋아요 눌렀는지 확인
8484
Optional<ChatLike> existingLike = chatLikeRepository.findByChatAndUser(chat, user);
85-
System.out.println("좋아요" + existingLike.isPresent());
8685

8786
if (existingLike.isPresent()) {
8887
chatLikeRepository.delete(existingLike.get());

src/main/java/com/memesphere/domain/notification/controller/CoinNotificationController.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
import com.memesphere.domain.notification.dto.response.NotificationListResponse;
77
import com.memesphere.domain.notification.dto.response.NotificationResponse;
88
import com.memesphere.domain.notification.service.CoinNotificationService;
9+
import com.memesphere.global.jwt.CustomUserDetails;
910
import io.swagger.v3.oas.annotations.Operation;
1011
import io.swagger.v3.oas.annotations.tags.Tag;
1112
import lombok.RequiredArgsConstructor;
13+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
1214
import org.springframework.web.bind.annotation.*;
1315

1416
@Tag(name="알림", description = "알림 관련 API")
@@ -65,8 +67,9 @@ public ApiResponse<NotificationListResponse> getNotificationList() {
6567
- "is_rising": 상승(true) 또는 하락(false)
6668
- "is_on": 알림 on(true) 또는 off(false)
6769
```""")
68-
public ApiResponse<NotificationResponse> postNotification(@RequestBody NotificationRequest request) {
69-
return ApiResponse.onSuccess(coinNotificationService.addNotification(request));
70+
public ApiResponse<NotificationResponse> postNotification(@RequestBody NotificationRequest request,
71+
@AuthenticationPrincipal CustomUserDetails customUserDetails) {
72+
return ApiResponse.onSuccess(coinNotificationService.addNotification(request, customUserDetails.getUser()));
7073
}
7174

7275
@PatchMapping("/{notification-id}")

src/main/java/com/memesphere/domain/notification/converter/NotificationConverter.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@
55
import com.memesphere.domain.notification.dto.response.NotificationListResponse;
66
import com.memesphere.domain.notification.dto.response.NotificationResponse;
77
import com.memesphere.domain.notification.entity.Notification;
8+
import com.memesphere.domain.user.entity.User;
89

910
import java.util.List;
1011

1112
public class NotificationConverter {
1213

13-
public static Notification toNotification(NotificationRequest notificationRequest, MemeCoin memeCoin) {
14+
public static Notification toNotification(NotificationRequest notificationRequest, MemeCoin memeCoin, User user) {
1415
return Notification.builder()
1516
.memeCoin(memeCoin)
1617
.volatility(notificationRequest.getVolatility())
1718
.stTime(notificationRequest.getStTime())
1819
.isRising(notificationRequest.getIsRising())
20+
.user(user)
1921
.build();
2022
}
2123

src/main/java/com/memesphere/domain/notification/repository/EmitterRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.memesphere.domain.notification.repository;
22

3+
import org.springframework.data.jpa.repository.JpaRepository;
34
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
45
import org.yaml.snakeyaml.emitter.Emitter;
56

@@ -11,4 +12,5 @@ public interface EmitterRepository {
1112
void deleteById(String emitterId);
1213
Map<String, SseEmitter> findAllEmitterStartWithByUserId(String UserId);
1314
Map<String, Object> findAllEventCacheStartWithByUserId(String UserId);
15+
void saveEventCache(String emitterId, Object event);
1416
}

src/main/java/com/memesphere/domain/notification/repository/EmitterRepositoryImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,9 @@ public Map<String, Object> findAllEventCacheStartWithByUserId(String UserId) {
3939
.filter(entry -> entry.getKey().startsWith(UserId))
4040
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
4141
}
42+
43+
@Override
44+
public void saveEventCache(String emitterId, Object event) {
45+
eventCache.put(emitterId, event);
46+
}
4247
}

src/main/java/com/memesphere/domain/notification/service/CoinNotificationService.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
import com.memesphere.domain.notification.dto.request.NotificationRequest;
44
import com.memesphere.domain.notification.dto.response.NotificationListResponse;
55
import com.memesphere.domain.notification.dto.response.NotificationResponse;
6+
import com.memesphere.domain.user.entity.User;
67

78
public interface CoinNotificationService {
89
NotificationListResponse findNotificationList();
9-
NotificationResponse addNotification(NotificationRequest notificationRequest);
10+
NotificationResponse addNotification(NotificationRequest notificationRequest, User user);
1011
String modifyNotification(Long notificationId);
1112
NotificationListResponse removeNotification(Long notificationId);
1213
}

src/main/java/com/memesphere/domain/notification/service/CoinNotificationServiceImpl.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.memesphere.domain.memecoin.entity.MemeCoin;
44
import com.memesphere.domain.memecoin.repository.MemeCoinRepository;
55
import com.memesphere.domain.notification.entity.Notification;
6+
import com.memesphere.domain.user.entity.User;
67
import com.memesphere.global.apipayload.code.status.ErrorStatus;
78
import com.memesphere.global.apipayload.exception.GeneralException;
89
import com.memesphere.domain.notification.converter.NotificationConverter;
@@ -44,11 +45,11 @@ public NotificationListResponse findNotificationList() {
4445

4546
// 알림 등록 API
4647
@Override
47-
public NotificationResponse addNotification(NotificationRequest notificationRequest) {
48+
public NotificationResponse addNotification(NotificationRequest notificationRequest, User user) {
4849
MemeCoin memeCoin = memeCoinRepository.findByName(notificationRequest.getName())
4950
.orElseThrow(() -> new GeneralException(ErrorStatus.MEMECOIN_NOT_FOUND));
5051

51-
Notification notification = NotificationConverter.toNotification(notificationRequest, memeCoin);
52+
Notification notification = NotificationConverter.toNotification(notificationRequest, memeCoin, user);
5253
notificationRepository.save(notification);
5354

5455
NotificationResponse notificationResponse = NotificationConverter.toNotificationCreateResponse(notification, memeCoin);
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package com.memesphere.domain.notification.service;
22

3+
import com.memesphere.domain.notification.entity.Notification;
34
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
45

56
public interface PushNotificationService {
67
SseEmitter subscribe(Long userId, String lastEventId);
7-
void send(Long userId);
8+
void send(Notification notification, Long userId);
89
}

src/main/java/com/memesphere/domain/notification/service/PushNotificationServiceImpl.java

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -53,43 +53,27 @@ public SseEmitter subscribe(Long userId, String lastEventId) {
5353
// 최초 연결 더미데이터가 없으면 503 에러가 나므로 더미 데이터 생성
5454
sendToClient(emitter, emitterId, "EventStream Created. [userId=" + userId + "]");
5555

56-
send(userId);
57-
56+
// 클라이언트가 미수신한 Event 목록이 존재할 경우 전송하여 Event 유실을 예방
5857
if (!lastEventId.isEmpty()) {
5958
Map<String, Object> events = emitterRepository.findAllEventCacheStartWithByUserId(String.valueOf(userId));
6059
events.entrySet().stream()
6160
.filter(entry -> lastEventId.compareTo(entry.getKey()) < 0)
6261
.forEach(entry -> sendToClient(emitter, entry.getKey(), entry.getValue()));
6362
}
64-
return emitter;
65-
}
66-
67-
@Override
68-
public void send(Long userId) {
6963

7064
List<Notification> notifications = notificationRepository.findAllByUserId(userId); // 사용자가 등록한 알림 전부 가져오기
7165

72-
if (notifications.isEmpty()) {
73-
return; // 저장된 알림이 없는 경우 아무것도 반환하지 않음
74-
}
75-
7666
// 변동성을 초과하는 알림 필터링
7767
List<Notification> filteredNotifications = notifications.stream()
7868
.filter(notification -> isVolatilityExceeded(notification))
7969
.collect(Collectors.toList());
8070

81-
if (filteredNotifications.isEmpty()) {
82-
return; // 기준을 충족하는 변동성이 없으면 전송하지 않음
83-
}
84-
85-
// 실시간 알림 전송
86-
Map<String, SseEmitter> sseEmitters = emitterRepository.findAllEmitterStartWithByUserId(String.valueOf(userId));
87-
88-
sseEmitters.forEach((key, emitter) -> {
89-
filteredNotifications.forEach(notification -> {
90-
sendToClient(emitter, key, "변동성 초과 알림");
71+
if (!filteredNotifications.isEmpty()) {
72+
notifications.forEach(notification -> {
73+
send(notification, userId);
9174
});
92-
});
75+
}
76+
return emitter;
9377
}
9478

9579
private void sendToClient(SseEmitter emitter, String emitterId, Object data) {
@@ -106,6 +90,18 @@ private void sendToClient(SseEmitter emitter, String emitterId, Object data) {
10690
}
10791
}
10892

93+
@Override
94+
public void send(Notification notification, Long userId) {
95+
96+
// 실시간 알림 전송 - 로그인 한 유저의 SseEmitter 모두 가져오기
97+
Map<String, SseEmitter> sseEmitters = emitterRepository.findAllEmitterStartWithByUserId(String.valueOf(userId));
98+
99+
sseEmitters.forEach((key, emitter) -> {
100+
emitterRepository.saveEventCache(key, notification);
101+
sendToClient(emitter, key, NotificationConverter.toNotificationCreateResponse(notification, notification.getMemeCoin()));
102+
});
103+
}
104+
109105
private boolean isVolatilityExceeded(Notification notification) {
110106
MemeCoin memeCoin = notification.getMemeCoin();
111107
if (memeCoin == null) {
@@ -120,7 +116,6 @@ private boolean isVolatilityExceeded(Notification notification) {
120116
Integer count = notification.getStTime() / 10; //몇 번 가져올 것인지 결정
121117
Pageable pageable = (Pageable) PageRequest.of(0, count, Sort.by(Sort.Direction.DESC, "createdAt"));
122118
List<ChartData> lastNData = chartDataRepository.findByMemeCoinOrderByRecordedTimeDesc(memeCoin, pageable);
123-
System.out.println("lastNData: " + lastNData + ", count: " + lastNData.size());
124119

125120
if (lastNData.size() < count) {
126121
return false; // 비교할 데이터가 부족하면 알림을 보내지 않음

0 commit comments

Comments
 (0)