Skip to content

Commit 2efc53d

Browse files
authored
Merge pull request #240 from prgrms-web-devcourse-final-project/Refactor/234
Refactor: 알림 도메인 리팩토링 (#234)
2 parents 69ed889 + 91a0dbe commit 2efc53d

16 files changed

+429
-1075
lines changed
Lines changed: 4 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
package com.back.domain.notification.controller;
22

3-
import com.back.domain.notification.dto.NotificationCreateRequest;
43
import com.back.domain.notification.dto.NotificationResponse;
54
import com.back.domain.notification.dto.NotificationListResponse;
65
import com.back.domain.notification.entity.Notification;
7-
import com.back.domain.notification.entity.NotificationSettingType;
86
import com.back.domain.notification.service.NotificationService;
9-
import com.back.domain.studyroom.entity.Room;
107
import com.back.domain.studyroom.repository.RoomRepository;
118
import com.back.domain.user.entity.User;
129
import com.back.domain.user.repository.UserRepository;
@@ -37,116 +34,7 @@ public class NotificationController {
3734
private final UserRepository userRepository;
3835
private final RoomRepository roomRepository;
3936

40-
@Operation(
41-
summary = "알림 전송",
42-
description = "USER/ROOM/COMMUNITY/SYSTEM 타입별 알림 생성 및 전송\n\n" +
43-
"- USER: 개인 알림 (actorId, targetId 필수)\n" +
44-
"- ROOM: 스터디룸 알림 (actorId, targetId(roomId) 필수)\n" +
45-
"- COMMUNITY: 커뮤니티 알림 (actorId, targetId 필수)\n" +
46-
"- SYSTEM: 시스템 전체 알림 (actorId, targetId 불필요)"
47-
)
48-
@PostMapping
49-
public ResponseEntity<RsData<NotificationResponse>> createNotification(
50-
@Parameter(hidden = true) @AuthenticationPrincipal CustomUserDetails userDetails,
51-
@RequestBody NotificationCreateRequest request) {
52-
53-
log.info("알림 전송 요청 - 타입: {}, 제목: {}", request.targetType(), request.title());
54-
55-
// targetType 검증
56-
if (!isValidTargetType(request.targetType())) {
57-
throw new CustomException(ErrorCode.NOTIFICATION_INVALID_TARGET_TYPE);
58-
}
59-
60-
// SYSTEM이 아닌 경우 필수 필드 검증
61-
if (!"SYSTEM".equals(request.targetType())) {
62-
if (request.actorId() == null) {
63-
throw new CustomException(ErrorCode.NOTIFICATION_MISSING_ACTOR);
64-
}
65-
if (request.targetId() == null) {
66-
throw new CustomException(ErrorCode.NOTIFICATION_MISSING_TARGET);
67-
}
68-
}
69-
70-
Notification notification = switch (request.targetType()) {
71-
case "USER" -> {
72-
// 수신자 조회
73-
User receiver = userRepository.findById(request.targetId())
74-
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
75-
76-
// 발신자 조회
77-
User actor = userRepository.findById(request.actorId())
78-
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
79-
80-
// 개인 알림 생성
81-
yield notificationService.createPersonalNotification(
82-
receiver,
83-
actor,
84-
request.title(),
85-
request.message(),
86-
request.redirectUrl(),
87-
NotificationSettingType.SYSTEM
88-
);
89-
}
90-
case "ROOM" -> {
91-
// 스터디룸 조회
92-
Room room = roomRepository.findById(request.targetId())
93-
.orElseThrow(() -> new CustomException(ErrorCode.ROOM_NOT_FOUND));
94-
95-
// 발신자 조회
96-
User actor = userRepository.findById(request.actorId())
97-
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
98-
99-
// 스터디룸 알림 생성
100-
yield notificationService.createRoomNotification(
101-
room,
102-
actor,
103-
request.title(),
104-
request.message(),
105-
request.redirectUrl(),
106-
NotificationSettingType.ROOM_NOTICE
107-
);
108-
}
109-
case "COMMUNITY" -> {
110-
// 수신자 조회 (리뷰/게시글 작성자)
111-
User receiver = userRepository.findById(request.targetId())
112-
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
113-
114-
// 발신자 조회 (댓글/좋아요 작성자)
115-
User actor = userRepository.findById(request.actorId())
116-
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
117-
118-
// 커뮤니티 알림 생성
119-
yield notificationService.createCommunityNotification(
120-
receiver,
121-
actor,
122-
request.title(),
123-
request.message(),
124-
request.redirectUrl(),
125-
NotificationSettingType.POST_COMMENT
126-
);
127-
}
128-
case "SYSTEM" -> {
129-
// 시스템 알림은 발신자/수신자 없음
130-
yield notificationService.createSystemNotification(
131-
request.title(),
132-
request.message(),
133-
request.redirectUrl()
134-
);
135-
}
136-
default -> throw new CustomException(ErrorCode.NOTIFICATION_INVALID_TARGET_TYPE);
137-
};
138-
139-
NotificationResponse response = NotificationResponse.from(notification);
140-
141-
return ResponseEntity.ok(RsData.success("알림 전송 성공", response));
142-
}
143-
144-
@Operation(
145-
summary = "알림 목록 조회",
146-
description = "사용자의 알림 목록 조회 (페이징)\n\n" +
147-
"- unreadOnly=true: 읽지 않은 알림만\n" +
148-
"- unreadOnly=false: 모든 알림"
149-
)
37+
@Operation(summary = "알림 목록 조회")
15038
@GetMapping
15139
public ResponseEntity<RsData<NotificationListResponse>> getNotifications(
15240
@Parameter(hidden = true) @AuthenticationPrincipal CustomUserDetails userDetails,
@@ -157,13 +45,10 @@ public ResponseEntity<RsData<NotificationListResponse>> getNotifications(
15745
log.info("알림 목록 조회 - 유저 ID: {}, 읽지 않은 것만: {}", userDetails.getUserId(), unreadOnly);
15846

15947
Pageable pageable = PageRequest.of(page, size);
160-
Page<Notification> notifications;
16148

162-
if (unreadOnly) {
163-
notifications = notificationService.getUnreadNotifications(userDetails.getUserId(), pageable);
164-
} else {
165-
notifications = notificationService.getUserNotifications(userDetails.getUserId(), pageable);
166-
}
49+
Page<Notification> notifications = notificationService.getNotifications(
50+
userDetails.getUserId(), pageable, unreadOnly
51+
);
16752

16853
long unreadCount = notificationService.getUnreadCount(userDetails.getUserId());
16954

@@ -221,14 +106,4 @@ public ResponseEntity<RsData<Void>> markAllAsRead(
221106

222107
return ResponseEntity.ok(RsData.success("전체 알림 읽음 처리 성공"));
223108
}
224-
225-
// ==================== 헬퍼 메서드 ====================
226-
227-
private boolean isValidTargetType(String targetType) {
228-
return targetType != null &&
229-
(targetType.equals("USER") ||
230-
targetType.equals("ROOM") ||
231-
targetType.equals("COMMUNITY") ||
232-
targetType.equals("SYSTEM"));
233-
}
234109
}

src/main/java/com/back/domain/notification/dto/NotificationCreateRequest.java

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/main/java/com/back/domain/notification/dto/NotificationListResponse.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import org.springframework.data.domain.Page;
66

77
import java.util.List;
8+
import java.util.Set;
89

910
/**
1011
* 알림 목록 응답 DTO
@@ -27,9 +28,13 @@ public static NotificationListResponse from(
2728
long unreadCount,
2829
NotificationService notificationService) {
2930

31+
// 현재 페이지의 알림들에 대해 읽음 처리된 ID 목록을 한 번에 조회
32+
Set<Long> readNotificationIds = notificationService.getReadNotificationIds(userId, notifications.getContent());
33+
3034
List<NotificationItemDto> items = notifications.getContent().stream()
3135
.map(notification -> {
32-
boolean isRead = notificationService.isNotificationRead(notification.getId(), userId);
36+
// DB 조회가 아닌 메모리에서 읽음 여부를 빠르게 확인
37+
boolean isRead = readNotificationIds.contains(notification.getId());
3338
return NotificationItemDto.from(notification, isRead);
3439
})
3540
.toList();

src/main/java/com/back/domain/notification/event/community/CommunityNotificationEventListener.java

Lines changed: 8 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@
22

33
import com.back.domain.notification.entity.NotificationSettingType;
44
import com.back.domain.notification.service.NotificationService;
5-
import com.back.domain.user.entity.User;
6-
import com.back.domain.user.repository.UserRepository;
7-
import com.back.global.exception.CustomException;
8-
import com.back.global.exception.ErrorCode;
95
import lombok.RequiredArgsConstructor;
106
import lombok.extern.slf4j.Slf4j;
117
import org.springframework.context.event.EventListener;
@@ -18,7 +14,6 @@
1814
public class CommunityNotificationEventListener {
1915

2016
private final NotificationService notificationService;
21-
private final UserRepository userRepository;
2217

2318
// 댓글 작성 시 - 게시글 작성자에게 알림
2419
@EventListener
@@ -28,15 +23,9 @@ public void handleCommentCreated(CommentCreatedEvent event) {
2823
event.getPostId(), event.getCommentId(), event.getActorId());
2924

3025
try {
31-
User actor = userRepository.findById(event.getActorId())
32-
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
33-
34-
User receiver = userRepository.findById(event.getReceiverId())
35-
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
36-
3726
notificationService.createCommunityNotification(
38-
receiver,
39-
actor,
27+
event.getReceiverId(),
28+
event.getActorId(),
4029
event.getTitle(),
4130
event.getContent(),
4231
"/posts/" + event.getPostId(),
@@ -58,15 +47,9 @@ public void handleReplyCreated(ReplyCreatedEvent event) {
5847
event.getParentCommentId(), event.getReplyId(), event.getActorId());
5948

6049
try {
61-
User actor = userRepository.findById(event.getActorId())
62-
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
63-
64-
User receiver = userRepository.findById(event.getReceiverId())
65-
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
66-
6750
notificationService.createCommunityNotification(
68-
receiver,
69-
actor,
51+
event.getReceiverId(),
52+
event.getActorId(),
7053
event.getTitle(),
7154
event.getContent(),
7255
"/posts/" + event.getPostId() + "#comment-" + event.getParentCommentId(),
@@ -88,15 +71,9 @@ public void handlePostLiked(PostLikedEvent event) {
8871
event.getPostId(), event.getActorId());
8972

9073
try {
91-
User actor = userRepository.findById(event.getActorId())
92-
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
93-
94-
User receiver = userRepository.findById(event.getReceiverId())
95-
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
96-
9774
notificationService.createCommunityNotification(
98-
receiver,
99-
actor,
75+
event.getReceiverId(),
76+
event.getActorId(),
10077
event.getTitle(),
10178
event.getContent(),
10279
"/posts/" + event.getPostId(),
@@ -118,15 +95,9 @@ public void handleCommentLiked(CommentLikedEvent event) {
11895
event.getCommentId(), event.getActorId());
11996

12097
try {
121-
User actor = userRepository.findById(event.getActorId())
122-
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
123-
124-
User receiver = userRepository.findById(event.getReceiverId())
125-
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
126-
12798
notificationService.createCommunityNotification(
128-
receiver,
129-
actor,
99+
event.getReceiverId(),
100+
event.getActorId(),
130101
event.getTitle(),
131102
event.getContent(),
132103
"/posts/" + event.getPostId() + "#comment-" + event.getCommentId(),

src/main/java/com/back/domain/notification/event/study/StudyNotificationEventListener.java

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
public class StudyNotificationEventListener {
1919

2020
private final NotificationService notificationService;
21-
private final UserRepository userRepository;
2221

2322
// 학습 기록 등록 시 - 본인에게 알림
2423
@EventListener
@@ -28,11 +27,8 @@ public void handleStudyRecordCreated(StudyRecordCreatedEvent event) {
2827
event.getUserId(), event.getDuration());
2928

3029
try {
31-
User user = userRepository.findById(event.getUserId())
32-
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
33-
3430
notificationService.createSelfNotification(
35-
user,
31+
event.getUserId(),
3632
event.getTitle(),
3733
event.getContent(),
3834
"/study/records/" + event.getStudyRecordId(),
@@ -55,11 +51,8 @@ public void handleDailyGoalAchieved(DailyGoalAchievedEvent event) {
5551
event.getCompletedPlans(), event.getTotalPlans());
5652

5753
try {
58-
User user = userRepository.findById(event.getUserId())
59-
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
60-
6154
notificationService.createSelfNotification(
62-
user,
55+
event.getUserId(),
6356
event.getTitle(),
6457
event.getContent(),
6558
"/study/plans?date=" + event.getAchievedDate(),

0 commit comments

Comments
 (0)