Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.sesac.boheommong.domain.bookmark.swagger.*;
import com.sesac.boheommong.domain.insurance.entity.InsuranceProduct;
import com.sesac.boheommong.domain.insurance.repository.InsuranceProductRepository;
import com.sesac.boheommong.domain.notification.service.NotificationService;
import com.sesac.boheommong.domain.user.entity.User;
import com.sesac.boheommong.domain.user.repository.UserRepository;
import com.sesac.boheommong.global.exception.BaseException;
Expand All @@ -25,6 +26,7 @@ public class BookmarkServiceImpl implements BookmarkService {
private final BookmarkRepository bookmarkRepository;
private final UserRepository userRepository;
private final InsuranceProductRepository insuranceProductRepository;
private final NotificationService notificationService;

/**
* 특정 상품이 북마크되었는지 여부 조회
Expand Down Expand Up @@ -86,10 +88,21 @@ public void addOrCancelBookmark(String loginEmail, Long productId) {
// (A) 이미 북마크가 존재하면 -> 물리 삭제
bookmarkRepository.delete(optionalBookmark.get());
// 실제 DB row가 삭제되므로 중복키 충돌 안 남.
notificationService.publishNotification(
user.getUserId(), // 알림 수신자 ID
"북마크가 해제되었습니다.", // 알림 내용
"/mypage/bookmark" // 클릭 시 이동할 URL (예시)
);
} else {
// (B) 없으면 -> 새 북마크 생성
Bookmark bookmark = Bookmark.create(user, product);
bookmarkRepository.save(bookmark);

notificationService.publishNotification(
user.getUserId(),
"북마크가 추가되었습니다.",
"/mypage/bookmark"
);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.sesac.boheommong.domain.notification.enums.NotificationType;
import com.sesac.boheommong.domain.notification.service.NotificationService;
import com.sesac.boheommong.domain.notification.swagger.*;
import com.sesac.boheommong.global.exception.BaseException;
import com.sesac.boheommong.global.exception.error.ErrorCode;
import com.sesac.boheommong.global.jwt.service.TokenProvider;
import com.sesac.boheommong.global.response.Response;
import jakarta.servlet.http.HttpServletRequest;
Expand All @@ -27,13 +29,17 @@ public class NotificationController {
@SubscribeNotification
@GetMapping("/subscribe")
public SseEmitter subscribe(
HttpServletRequest request,
@RequestParam("token") String token, // <-- 추가
@RequestHeader(value = "Last-Event-ID", required = false, defaultValue = "") String lastEventId
) {
// 1) 로그인 이메일 추출
String loginEmail = tokenProvider.getUserLoginEmail(request);
// (1) 토큰 검증 & 로그인 이메일 추출
if (!tokenProvider.validToken(token)) {
throw BaseException.from(ErrorCode.TOKEN_EXPIRED);
}
// Overload한 getUserLoginEmail(token) 호출
String loginEmail = tokenProvider.getUserLoginEmail(token);

// 2) Service 호출
// (2) SSE 구독
return notificationService.subscribe(loginEmail, lastEventId);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ public SseEmitter subscribe(String loginEmail, String lastEventId) {
emitter.onTimeout(() -> emitterRepository.deleteById(emitterId));

// 최초 연결 시 더미데이터가 없으면 503 오류가 발생하기 때문에 해당 더미 데이터 생성
sendToClient(emitter,emitterId, "EventStream Created. [userId=" + userId + "]");
Response<Map<String, String>> dummy = Response.success(
Map.of("message", "EventStream Created. [userId=" + userId + "]")
);
sendToClient(emitter, emitterId, dummy);

// SSE의 자동 재연결 기능 때문에 재연결시 lastEventId를 기준으로 이후의 이벤트들만 전송
if (!lastEventId.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public enum ErrorCode {
// user
USER_NOT_FOUND("USER-0000", "해당 회원이 존재하지 않습니다.", ErrorDisplayType.POPUP),
INVALID_PERMISSION("USER-0001", "허용된 접근이 아닙니다.", ErrorDisplayType.POPUP),
TOKEN_EXPIRED("USER-0002", "유효하지 않은 토큰입니다.", ErrorDisplayType.POPUP),

// user health
USER_HEALTH_ALREADY_EXISTS("HEALTH-0001", "해당 유저의 건강정보가 이미 존재합니다.", ErrorDisplayType.POPUP),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ public String getUserLoginEmail(HttpServletRequest request) {
return null;
}

public String getUserLoginEmail(String token) {
Claims claims = getClaims(token); // 아래의 getClaims(token)
return claims.getSubject(); // subject = loginEmail
}

// 토큰의 클레임 반환
public Claims getClaims(String token) {
return Jwts.parser()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.sesac.boheommong.infra.redis;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.sesac.boheommong.domain.notification.entity.Notification;
import com.sesac.boheommong.domain.notification.enums.NotificationType;
import lombok.*;
Expand All @@ -9,6 +10,7 @@
@NoArgsConstructor
@AllArgsConstructor
@Builder
@JsonIgnoreProperties(ignoreUnknown = true)
public class NotificationMessage {

// 알림 ID (이미 DB에 저장된 경우)
Expand Down