Skip to content

Commit efbd00f

Browse files
loseminhonamgigun
authored andcommitted
Feat : RoomMember 엔티티 필드 제거 기반 redis 연동 (#144) (#145)
* refactor: RoomMember 엔티티에서 실시간 상태 필드 제거, redis로 이관 * feat:제거 기반 redis 연동 테스트 완료
1 parent 0feb4b4 commit efbd00f

File tree

7 files changed

+127
-31
lines changed

7 files changed

+127
-31
lines changed

src/main/java/com/back/domain/studyroom/controller/RoomController.java

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public ResponseEntity<RsData<RoomResponse>> createRoom(
6464
currentUserId
6565
);
6666

67-
RoomResponse response = RoomResponse.from(room);
67+
RoomResponse response = roomService.toRoomResponse(room);
6868

6969
return ResponseEntity
7070
.status(HttpStatus.CREATED)
@@ -139,9 +139,7 @@ public ResponseEntity<RsData<Map<String, Object>>> getRooms(
139139
Pageable pageable = PageRequest.of(page, size);
140140
Page<Room> rooms = roomService.getJoinableRooms(pageable);
141141

142-
List<RoomResponse> roomList = rooms.getContent().stream()
143-
.map(RoomResponse::from)
144-
.collect(Collectors.toList());
142+
List<RoomResponse> roomList = roomService.toRoomResponseList(rooms.getContent());
145143

146144
Map<String, Object> response = new HashMap<>();
147145
response.put("rooms", roomList);
@@ -175,11 +173,7 @@ public ResponseEntity<RsData<RoomDetailResponse>> getRoomDetail(
175173
Room room = roomService.getRoomDetail(roomId, currentUserId);
176174
List<RoomMember> members = roomService.getRoomMembers(roomId, currentUserId);
177175

178-
List<RoomMemberResponse> memberResponses = members.stream()
179-
.map(RoomMemberResponse::from)
180-
.collect(Collectors.toList());
181-
182-
RoomDetailResponse response = RoomDetailResponse.of(room, memberResponses);
176+
RoomDetailResponse response = roomService.toRoomDetailResponse(room, members);
183177

184178
return ResponseEntity
185179
.status(HttpStatus.OK)
@@ -201,12 +195,7 @@ public ResponseEntity<RsData<List<MyRoomResponse>>> getMyRooms() {
201195

202196
List<Room> rooms = roomService.getUserRooms(currentUserId);
203197

204-
List<MyRoomResponse> roomList = rooms.stream()
205-
.map(room -> MyRoomResponse.of(
206-
room,
207-
roomService.getUserRoomRole(room.getId(), currentUserId)
208-
))
209-
.collect(Collectors.toList());
198+
List<MyRoomResponse> roomList = roomService.toMyRoomResponseList(rooms, currentUserId);
210199

211200
return ResponseEntity
212201
.status(HttpStatus.OK)
@@ -313,9 +302,7 @@ public ResponseEntity<RsData<Map<String, Object>>> getPopularRooms(
313302
Pageable pageable = PageRequest.of(page, size);
314303
Page<Room> rooms = roomService.getPopularRooms(pageable);
315304

316-
List<RoomResponse> roomList = rooms.getContent().stream()
317-
.map(RoomResponse::from)
318-
.collect(Collectors.toList());
305+
List<RoomResponse> roomList = roomService.toRoomResponseList(rooms.getContent());
319306

320307
Map<String, Object> response = new HashMap<>();
321308
response.put("rooms", roomList);

src/main/java/com/back/domain/studyroom/dto/MyRoomResponse.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ public class MyRoomResponse {
2020
private RoomRole myRole;
2121
private LocalDateTime createdAt;
2222

23-
public static MyRoomResponse of(Room room, RoomRole myRole) {
23+
public static MyRoomResponse of(Room room, long currentParticipants, RoomRole myRole) {
2424
return MyRoomResponse.builder()
2525
.roomId(room.getId())
2626
.title(room.getTitle())
2727
.description(room.getDescription() != null ? room.getDescription() : "")
28-
.currentParticipants(room.getCurrentParticipants())
28+
.currentParticipants((int) currentParticipants) // Redis에서 조회한 실시간 값
2929
.maxParticipants(room.getMaxParticipants())
3030
.status(room.getStatus())
3131
.myRole(myRole)

src/main/java/com/back/domain/studyroom/dto/RoomDetailResponse.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ public class RoomDetailResponse {
2525
private LocalDateTime createdAt;
2626
private List<RoomMemberResponse> members;
2727

28-
public static RoomDetailResponse of(Room room, List<RoomMemberResponse> members) {
28+
public static RoomDetailResponse of(Room room, long currentParticipants, List<RoomMemberResponse> members) {
2929
return RoomDetailResponse.builder()
3030
.roomId(room.getId())
3131
.title(room.getTitle())
3232
.description(room.getDescription() != null ? room.getDescription() : "")
3333
.isPrivate(room.isPrivate())
3434
.maxParticipants(room.getMaxParticipants())
35-
.currentParticipants(room.getCurrentParticipants())
35+
.currentParticipants((int) currentParticipants) // Redis에서 조회한 실시간 값
3636
.status(room.getStatus())
3737
.allowCamera(room.isAllowCamera())
3838
.allowAudio(room.isAllowAudio())

src/main/java/com/back/domain/studyroom/dto/RoomResponse.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ public class RoomResponse {
1919
private String createdBy;
2020
private LocalDateTime createdAt;
2121

22-
public static RoomResponse from(Room room) {
22+
public static RoomResponse from(Room room, long currentParticipants) {
2323
return RoomResponse.builder()
2424
.roomId(room.getId())
2525
.title(room.getTitle())
2626
.description(room.getDescription() != null ? room.getDescription() : "")
27-
.currentParticipants(room.getCurrentParticipants())
27+
.currentParticipants((int) currentParticipants) // Redis에서 조회한 실시간 값
2828
.maxParticipants(room.getMaxParticipants())
2929
.status(room.getStatus())
3030
.createdBy(room.getCreatedBy().getNickname())

src/main/java/com/back/domain/studyroom/service/RoomService.java

Lines changed: 80 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public class RoomService {
4040
private final RoomMemberRepository roomMemberRepository;
4141
private final UserRepository userRepository;
4242
private final StudyRoomProperties properties;
43+
private final com.back.global.websocket.service.WebSocketSessionManager sessionManager;
4344

4445
/**
4546
* 방 생성 메서드
@@ -67,7 +68,7 @@ public Room createRoom(String title, String description, boolean isPrivate,
6768
RoomMember hostMember = RoomMember.createHost(savedRoom, creator);
6869
roomMemberRepository.save(hostMember);
6970

70-
savedRoom.incrementParticipant();
71+
// savedRoom.incrementParticipant(); // Redis로 이관 - DB 업데이트 제거
7172

7273
log.info("방 생성 완료 - RoomId: {}, Title: {}, CreatorId: {}",
7374
savedRoom.getId(), title, creatorId);
@@ -125,14 +126,15 @@ public RoomMember joinRoom(Long roomId, String password, Long userId) {
125126
RoomMember member = existingMember.get();
126127
// TODO: Redis에서 온라인 여부 확인하도록 변경
127128
// 현재는 기존 멤버 재입장 허용
129+
// room.incrementParticipant(); // Redis로 이관 - DB 업데이트 제거
128130
room.incrementParticipant();
129131
return member;
130132
}
131133

132134
RoomMember newMember = RoomMember.createVisitor(room, user);
133135
RoomMember savedMember = roomMemberRepository.save(newMember);
134136

135-
room.incrementParticipant();
137+
// room.incrementParticipant(); // Redis로 이관 - DB 업데이트 제거
136138

137139
log.info("방 입장 완료 - RoomId: {}, UserId: {}, Role: {}",
138140
roomId, userId, newMember.getRole());
@@ -166,7 +168,7 @@ public void leaveRoom(Long roomId, Long userId) {
166168
handleHostLeaving(room, member);
167169
} else {
168170
// TODO: Redis에서 제거하도록 변경
169-
room.decrementParticipant();
171+
// room.decrementParticipant(); // Redis로 이관 - DB 업데이트 제거
170172
}
171173

172174
log.info("방 퇴장 완료 - RoomId: {}, UserId: {}", roomId, userId);
@@ -183,7 +185,7 @@ private void handleHostLeaving(Room room, RoomMember hostMember) {
183185
if (otherOnlineMembers.isEmpty()) {
184186
room.terminate();
185187
// TODO: Redis에서 제거하도록 변경
186-
room.decrementParticipant();
188+
// room.decrementParticipant(); // Redis로 이관 - DB 업데이트 제거
187189
} else {
188190
RoomMember newHost = otherOnlineMembers.stream()
189191
.filter(m -> m.getRole() == RoomRole.SUB_HOST)
@@ -195,7 +197,7 @@ private void handleHostLeaving(Room room, RoomMember hostMember) {
195197
if (newHost != null) {
196198
newHost.updateRole(RoomRole.HOST);
197199
// TODO: Redis에서 제거하도록 변경
198-
room.decrementParticipant();
200+
// room.decrementParticipant(); // Redis로 이관 - DB 업데이트 제거
199201

200202
log.info("새 방장 지정 - RoomId: {}, NewHostId: {}",
201203
room.getId(), newHost.getUser().getId());
@@ -339,9 +341,81 @@ public void kickMember(Long roomId, Long targetUserId, Long requesterId) {
339341

340342
Room room = roomRepository.findById(roomId)
341343
.orElseThrow(() -> new CustomException(ErrorCode.ROOM_NOT_FOUND));
342-
room.decrementParticipant();
344+
// room.decrementParticipant(); // Redis로 이관 - DB 업데이트 제거
343345

344346
log.info("멤버 추방 완료 - RoomId: {}, TargetUserId: {}, RequesterId: {}",
345347
roomId, targetUserId, requesterId);
346348
}
349+
350+
// ==================== DTO 생성 헬퍼 메서드 ====================
351+
352+
/**
353+
* RoomResponse 생성 (Redis에서 실시간 참가자 수 조회)
354+
*/
355+
public com.back.domain.studyroom.dto.RoomResponse toRoomResponse(Room room) {
356+
long onlineCount = sessionManager.getRoomOnlineUserCount(room.getId());
357+
return com.back.domain.studyroom.dto.RoomResponse.from(room, onlineCount);
358+
}
359+
360+
/**
361+
* RoomResponse 리스트 생성 (일괄 조회로 N+1 방지)
362+
*/
363+
public java.util.List<com.back.domain.studyroom.dto.RoomResponse> toRoomResponseList(java.util.List<Room> rooms) {
364+
java.util.List<Long> roomIds = rooms.stream()
365+
.map(Room::getId)
366+
.collect(java.util.stream.Collectors.toList());
367+
368+
java.util.Map<Long, Long> participantCounts = sessionManager.getBulkRoomOnlineUserCounts(roomIds);
369+
370+
return rooms.stream()
371+
.map(room -> com.back.domain.studyroom.dto.RoomResponse.from(
372+
room,
373+
participantCounts.getOrDefault(room.getId(), 0L)
374+
))
375+
.collect(java.util.stream.Collectors.toList());
376+
}
377+
378+
/**
379+
* RoomDetailResponse 생성 (Redis에서 실시간 참가자 수 조회)
380+
*/
381+
public com.back.domain.studyroom.dto.RoomDetailResponse toRoomDetailResponse(
382+
Room room,
383+
java.util.List<com.back.domain.studyroom.entity.RoomMember> members) {
384+
long onlineCount = sessionManager.getRoomOnlineUserCount(room.getId());
385+
386+
java.util.List<com.back.domain.studyroom.dto.RoomMemberResponse> memberResponses = members.stream()
387+
.map(com.back.domain.studyroom.dto.RoomMemberResponse::from)
388+
.collect(java.util.stream.Collectors.toList());
389+
390+
return com.back.domain.studyroom.dto.RoomDetailResponse.of(room, onlineCount, memberResponses);
391+
}
392+
393+
/**
394+
* MyRoomResponse 생성 (Redis에서 실시간 참가자 수 조회)
395+
*/
396+
public com.back.domain.studyroom.dto.MyRoomResponse toMyRoomResponse(Room room, RoomRole myRole) {
397+
long onlineCount = sessionManager.getRoomOnlineUserCount(room.getId());
398+
return com.back.domain.studyroom.dto.MyRoomResponse.of(room, onlineCount, myRole);
399+
}
400+
401+
/**
402+
* MyRoomResponse 리스트 생성 (일괄 조회로 N+1 방지)
403+
*/
404+
public java.util.List<com.back.domain.studyroom.dto.MyRoomResponse> toMyRoomResponseList(
405+
java.util.List<Room> rooms,
406+
Long userId) {
407+
java.util.List<Long> roomIds = rooms.stream()
408+
.map(Room::getId)
409+
.collect(java.util.stream.Collectors.toList());
410+
411+
java.util.Map<Long, Long> participantCounts = sessionManager.getBulkRoomOnlineUserCounts(roomIds);
412+
413+
return rooms.stream()
414+
.map(room -> {
415+
RoomRole role = getUserRoomRole(room.getId(), userId);
416+
long count = participantCounts.getOrDefault(room.getId(), 0L);
417+
return com.back.domain.studyroom.dto.MyRoomResponse.of(room, count, role);
418+
})
419+
.collect(java.util.stream.Collectors.toList());
420+
}
347421
}

src/main/java/com/back/global/websocket/service/WebSocketSessionManager.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,13 @@ public Long getUserCurrentRoomId(Long userId) {
8484
public boolean isUserInRoom(Long userId, Long roomId) {
8585
return roomParticipantService.isUserInRoom(userId, roomId);
8686
}
87+
88+
// 여러 방의 온라인 사용자 수 일괄 조회 (N+1 방지)
89+
public java.util.Map<Long, Long> getBulkRoomOnlineUserCounts(java.util.List<Long> roomIds) {
90+
return roomIds.stream()
91+
.collect(java.util.stream.Collectors.toMap(
92+
roomId -> roomId,
93+
this::getRoomOnlineUserCount
94+
));
95+
}
8796
}

src/test/java/com/back/domain/studyroom/controller/RoomControllerTest.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,13 @@ void createRoom() {
105105
anyInt(),
106106
eq(1L)
107107
)).willReturn(testRoom);
108+
109+
RoomResponse roomResponse = RoomResponse.from(testRoom, 1);
110+
given(roomService.toRoomResponse(any(Room.class))).willReturn(roomResponse);
108111

109112
// when
110113
ResponseEntity<RsData<RoomResponse>> response = roomController.createRoom(request);
114+
111115
// then
112116
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
113117
assertThat(response.getBody()).isNotNull();
@@ -123,6 +127,7 @@ void createRoom() {
123127
anyInt(),
124128
eq(1L)
125129
);
130+
verify(roomService, times(1)).toRoomResponse(any(Room.class));
126131
}
127132

128133
@Test
@@ -174,6 +179,9 @@ void getRooms() {
174179
1
175180
);
176181
given(roomService.getJoinableRooms(any())).willReturn(roomPage);
182+
183+
List<RoomResponse> roomResponses = Arrays.asList(RoomResponse.from(testRoom, 1));
184+
given(roomService.toRoomResponseList(anyList())).willReturn(roomResponses);
177185

178186
// when
179187
ResponseEntity<RsData<Map<String, Object>>> response = roomController.getRooms(0, 20);
@@ -185,6 +193,7 @@ void getRooms() {
185193
assertThat(response.getBody().getData().get("rooms")).isNotNull();
186194

187195
verify(roomService, times(1)).getJoinableRooms(any());
196+
verify(roomService, times(1)).toRoomResponseList(anyList());
188197
}
189198

190199
@Test
@@ -195,6 +204,13 @@ void getRoomDetail() {
195204

196205
given(roomService.getRoomDetail(eq(1L), eq(1L))).willReturn(testRoom);
197206
given(roomService.getRoomMembers(eq(1L), eq(1L))).willReturn(Arrays.asList(testMember));
207+
208+
RoomDetailResponse roomDetailResponse = RoomDetailResponse.of(
209+
testRoom,
210+
1,
211+
Arrays.asList(RoomMemberResponse.from(testMember))
212+
);
213+
given(roomService.toRoomDetailResponse(any(Room.class), anyList())).willReturn(roomDetailResponse);
198214

199215
// when
200216
ResponseEntity<RsData<RoomDetailResponse>> response = roomController.getRoomDetail(1L);
@@ -208,6 +224,7 @@ void getRoomDetail() {
208224
verify(currentUser, times(1)).getUserId();
209225
verify(roomService, times(1)).getRoomDetail(eq(1L), eq(1L));
210226
verify(roomService, times(1)).getRoomMembers(eq(1L), eq(1L));
227+
verify(roomService, times(1)).toRoomDetailResponse(any(Room.class), anyList());
211228
}
212229

213230
@Test
@@ -226,7 +243,11 @@ void getMyRooms() {
226243
}
227244

228245
given(roomService.getUserRooms(eq(1L))).willReturn(Arrays.asList(testRoom));
229-
given(roomService.getUserRoomRole(eq(1L), eq(1L))).willReturn(RoomRole.HOST);
246+
247+
List<MyRoomResponse> myRoomResponses = Arrays.asList(
248+
MyRoomResponse.of(testRoom, 1, RoomRole.HOST)
249+
);
250+
given(roomService.toMyRoomResponseList(anyList(), eq(1L))).willReturn(myRoomResponses);
230251

231252
// when
232253
ResponseEntity<RsData<List<MyRoomResponse>>> response = roomController.getMyRooms();
@@ -240,6 +261,7 @@ void getMyRooms() {
240261

241262
verify(currentUser, times(1)).getUserId();
242263
verify(roomService, times(1)).getUserRooms(eq(1L));
264+
verify(roomService, times(1)).toMyRoomResponseList(anyList(), eq(1L));
243265
}
244266

245267
@Test
@@ -328,6 +350,9 @@ void getPopularRooms() {
328350
1
329351
);
330352
given(roomService.getPopularRooms(any())).willReturn(roomPage);
353+
354+
List<RoomResponse> roomResponses = Arrays.asList(RoomResponse.from(testRoom, 1));
355+
given(roomService.toRoomResponseList(anyList())).willReturn(roomResponses);
331356

332357
// when
333358
ResponseEntity<RsData<Map<String, Object>>> response = roomController.getPopularRooms(0, 20);
@@ -339,5 +364,6 @@ void getPopularRooms() {
339364
assertThat(response.getBody().getData().get("rooms")).isNotNull();
340365

341366
verify(roomService, times(1)).getPopularRooms(any());
367+
verify(roomService, times(1)).toRoomResponseList(anyList());
342368
}
343369
}

0 commit comments

Comments
 (0)