Skip to content

Commit 8cb4561

Browse files
committed
refactor, feat
: 조회 분할
1 parent 98c9e4c commit 8cb4561

File tree

6 files changed

+493
-1
lines changed

6 files changed

+493
-1
lines changed

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

Lines changed: 180 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,140 @@ public ResponseEntity<RsData<Void>> leaveRoom(
126126
.body(RsData.success("방 퇴장 완료", null));
127127
}
128128

129-
@GetMapping
129+
@GetMapping("/all")
130+
@Operation(
131+
summary = "모든 방 목록 조회",
132+
description = "공개 방과 비공개 방 전체를 조회합니다. 비공개 방은 제목과 방장 정보가 마스킹됩니다. 열린 방(WAITING, ACTIVE)이 우선 표시되고, 닫힌 방(PAUSED, TERMINATED)은 뒤로 밀립니다."
133+
)
134+
@ApiResponses({
135+
@ApiResponse(responseCode = "200", description = "조회 성공"),
136+
@ApiResponse(responseCode = "401", description = "인증 실패")
137+
})
138+
public ResponseEntity<RsData<Map<String, Object>>> getAllRooms(
139+
@Parameter(description = "페이지 번호 (0부터 시작)") @RequestParam(defaultValue = "0") int page,
140+
@Parameter(description = "페이지 크기") @RequestParam(defaultValue = "20") int size) {
141+
142+
Pageable pageable = PageRequest.of(page, size);
143+
Page<Room> rooms = roomService.getAllRooms(pageable);
144+
145+
// 비공개 방 마스킹 포함한 변환
146+
List<RoomResponse> roomList = roomService.toRoomResponseListWithMasking(rooms.getContent());
147+
148+
Map<String, Object> response = new HashMap<>();
149+
response.put("rooms", roomList);
150+
response.put("page", rooms.getNumber());
151+
response.put("size", rooms.getSize());
152+
response.put("totalElements", rooms.getTotalElements());
153+
response.put("totalPages", rooms.getTotalPages());
154+
response.put("hasNext", rooms.hasNext());
155+
156+
return ResponseEntity
157+
.status(HttpStatus.OK)
158+
.body(RsData.success("모든 방 목록 조회 완료", response));
159+
}
160+
161+
@GetMapping("/public")
130162
@Operation(
131163
summary = "공개 방 목록 조회",
164+
description = "공개 방 전체를 조회합니다. includeInactive=true로 설정하면 닫힌 방도 포함됩니다 (기본값: true). 열린 방이 우선 표시됩니다."
165+
)
166+
@ApiResponses({
167+
@ApiResponse(responseCode = "200", description = "조회 성공"),
168+
@ApiResponse(responseCode = "401", description = "인증 실패")
169+
})
170+
public ResponseEntity<RsData<Map<String, Object>>> getPublicRooms(
171+
@Parameter(description = "페이지 번호 (0부터 시작)") @RequestParam(defaultValue = "0") int page,
172+
@Parameter(description = "페이지 크기") @RequestParam(defaultValue = "20") int size,
173+
@Parameter(description = "닫힌 방 포함 여부") @RequestParam(defaultValue = "true") boolean includeInactive) {
174+
175+
Pageable pageable = PageRequest.of(page, size);
176+
Page<Room> rooms = roomService.getPublicRooms(includeInactive, pageable);
177+
178+
List<RoomResponse> roomList = roomService.toRoomResponseList(rooms.getContent());
179+
180+
Map<String, Object> response = new HashMap<>();
181+
response.put("rooms", roomList);
182+
response.put("page", rooms.getNumber());
183+
response.put("size", rooms.getSize());
184+
response.put("totalElements", rooms.getTotalElements());
185+
response.put("totalPages", rooms.getTotalPages());
186+
response.put("hasNext", rooms.hasNext());
187+
188+
return ResponseEntity
189+
.status(HttpStatus.OK)
190+
.body(RsData.success("공개 방 목록 조회 완료", response));
191+
}
192+
193+
@GetMapping("/private")
194+
@Operation(
195+
summary = "내 비공개 방 목록 조회",
196+
description = "내가 멤버로 등록된 비공개 방을 조회합니다. includeInactive=true로 설정하면 닫힌 방도 포함됩니다 (기본값: true). 열린 방이 우선 표시됩니다."
197+
)
198+
@ApiResponses({
199+
@ApiResponse(responseCode = "200", description = "조회 성공"),
200+
@ApiResponse(responseCode = "401", description = "인증 실패")
201+
})
202+
public ResponseEntity<RsData<Map<String, Object>>> getMyPrivateRooms(
203+
@Parameter(description = "페이지 번호 (0부터 시작)") @RequestParam(defaultValue = "0") int page,
204+
@Parameter(description = "페이지 크기") @RequestParam(defaultValue = "20") int size,
205+
@Parameter(description = "닫힌 방 포함 여부") @RequestParam(defaultValue = "true") boolean includeInactive) {
206+
207+
Long currentUserId = currentUser.getUserId();
208+
209+
Pageable pageable = PageRequest.of(page, size);
210+
Page<Room> rooms = roomService.getMyPrivateRooms(currentUserId, includeInactive, pageable);
211+
212+
List<RoomResponse> roomList = roomService.toRoomResponseList(rooms.getContent());
213+
214+
Map<String, Object> response = new HashMap<>();
215+
response.put("rooms", roomList);
216+
response.put("page", rooms.getNumber());
217+
response.put("size", rooms.getSize());
218+
response.put("totalElements", rooms.getTotalElements());
219+
response.put("totalPages", rooms.getTotalPages());
220+
response.put("hasNext", rooms.hasNext());
221+
222+
return ResponseEntity
223+
.status(HttpStatus.OK)
224+
.body(RsData.success("내 비공개 방 목록 조회 완료", response));
225+
}
226+
227+
@GetMapping("/my/hosting")
228+
@Operation(
229+
summary = "내가 호스트인 방 목록 조회",
230+
description = "내가 방장으로 있는 방을 조회합니다. 열린 방이 우선 표시되고, 닫힌 방은 뒤로 밀립니다."
231+
)
232+
@ApiResponses({
233+
@ApiResponse(responseCode = "200", description = "조회 성공"),
234+
@ApiResponse(responseCode = "401", description = "인증 실패")
235+
})
236+
public ResponseEntity<RsData<Map<String, Object>>> getMyHostingRooms(
237+
@Parameter(description = "페이지 번호 (0부터 시작)") @RequestParam(defaultValue = "0") int page,
238+
@Parameter(description = "페이지 크기") @RequestParam(defaultValue = "20") int size) {
239+
240+
Long currentUserId = currentUser.getUserId();
241+
242+
Pageable pageable = PageRequest.of(page, size);
243+
Page<Room> rooms = roomService.getMyHostingRooms(currentUserId, pageable);
244+
245+
List<RoomResponse> roomList = roomService.toRoomResponseList(rooms.getContent());
246+
247+
Map<String, Object> response = new HashMap<>();
248+
response.put("rooms", roomList);
249+
response.put("page", rooms.getNumber());
250+
response.put("size", rooms.getSize());
251+
response.put("totalElements", rooms.getTotalElements());
252+
response.put("totalPages", rooms.getTotalPages());
253+
response.put("hasNext", rooms.hasNext());
254+
255+
return ResponseEntity
256+
.status(HttpStatus.OK)
257+
.body(RsData.success("내가 호스트인 방 목록 조회 완료", response));
258+
}
259+
260+
@GetMapping
261+
@Operation(
262+
summary = "입장 가능한 공개 방 목록 조회 (기존)",
132263
description = "입장 가능한 공개 스터디 룸 목록을 페이징하여 조회합니다. 최신 생성 순으로 정렬됩니다."
133264
)
134265
@ApiResponses({
@@ -262,6 +393,54 @@ public ResponseEntity<RsData<Void>> deleteRoom(
262393
.body(RsData.success("방 종료 완료", null));
263394
}
264395

396+
@PutMapping("/{roomId}/pause")
397+
@Operation(
398+
summary = "방 일시정지",
399+
description = "방을 일시정지 상태로 변경합니다. 일시정지된 방은 입장할 수 없으며, 방 목록에서 뒤로 밀립니다. 방장만 실행 가능합니다."
400+
)
401+
@ApiResponses({
402+
@ApiResponse(responseCode = "200", description = "일시정지 성공"),
403+
@ApiResponse(responseCode = "400", description = "이미 종료되었거나 일시정지 불가능한 상태"),
404+
@ApiResponse(responseCode = "403", description = "방장 권한 없음"),
405+
@ApiResponse(responseCode = "404", description = "존재하지 않는 방"),
406+
@ApiResponse(responseCode = "401", description = "인증 실패")
407+
})
408+
public ResponseEntity<RsData<Void>> pauseRoom(
409+
@Parameter(description = "방 ID", required = true) @PathVariable Long roomId) {
410+
411+
Long currentUserId = currentUser.getUserId();
412+
413+
roomService.pauseRoom(roomId, currentUserId);
414+
415+
return ResponseEntity
416+
.status(HttpStatus.OK)
417+
.body(RsData.success("방 일시정지 완료", null));
418+
}
419+
420+
@PutMapping("/{roomId}/activate")
421+
@Operation(
422+
summary = "방 활성화/재개",
423+
description = "일시정지된 방을 다시 활성화합니다. 활성화된 방은 다시 입장 가능하며, 방 목록 앞쪽에 표시됩니다. 방장만 실행 가능합니다."
424+
)
425+
@ApiResponses({
426+
@ApiResponse(responseCode = "200", description = "활성화 성공"),
427+
@ApiResponse(responseCode = "400", description = "이미 종료되었거나 활성화 불가능한 상태"),
428+
@ApiResponse(responseCode = "403", description = "방장 권한 없음"),
429+
@ApiResponse(responseCode = "404", description = "존재하지 않는 방"),
430+
@ApiResponse(responseCode = "401", description = "인증 실패")
431+
})
432+
public ResponseEntity<RsData<Void>> activateRoom(
433+
@Parameter(description = "방 ID", required = true) @PathVariable Long roomId) {
434+
435+
Long currentUserId = currentUser.getUserId();
436+
437+
roomService.activateRoom(roomId, currentUserId);
438+
439+
return ResponseEntity
440+
.status(HttpStatus.OK)
441+
.body(RsData.success("방 활성화 완료", null));
442+
}
443+
265444
@GetMapping("/{roomId}/members")
266445
@Operation(
267446
summary = "방 멤버 목록 조회",

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public class MyRoomResponse {
1414
private Long roomId;
1515
private String title;
1616
private String description;
17+
private Boolean isPrivate; // 비공개 방 여부 (UI에서 🔒 아이콘 표시용)
1718
private int currentParticipants;
1819
private int maxParticipants;
1920
private RoomStatus status;
@@ -25,6 +26,7 @@ public static MyRoomResponse of(Room room, long currentParticipants, RoomRole my
2526
.roomId(room.getId())
2627
.title(room.getTitle())
2728
.description(room.getDescription() != null ? room.getDescription() : "")
29+
.isPrivate(room.isPrivate()) // 비공개 방 여부
2830
.currentParticipants((int) currentParticipants) // Redis에서 조회한 실시간 값
2931
.maxParticipants(room.getMaxParticipants())
3032
.status(room.getStatus())

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public class RoomResponse {
1313
private Long roomId;
1414
private String title;
1515
private String description;
16+
private Boolean isPrivate; // 비공개 방 여부 (UI에서 🔒 아이콘 표시용)
1617
private int currentParticipants;
1718
private int maxParticipants;
1819
private RoomStatus status;
@@ -29,6 +30,7 @@ public static RoomResponse from(Room room, long currentParticipants) {
2930
.roomId(room.getId())
3031
.title(room.getTitle())
3132
.description(room.getDescription() != null ? room.getDescription() : "")
33+
.isPrivate(room.isPrivate()) // 비공개 방 여부
3234
.currentParticipants((int) currentParticipants) // Redis에서 조회한 실시간 값
3335
.maxParticipants(room.getMaxParticipants())
3436
.status(room.getStatus())
@@ -39,4 +41,25 @@ public static RoomResponse from(Room room, long currentParticipants) {
3941
.allowScreenShare(room.isAllowScreenShare())
4042
.build();
4143
}
44+
45+
/**
46+
* 비공개 방 정보 마스킹 버전 (전체 목록에서 볼 때 사용)
47+
* "모든 방" 조회 시 사용 - 비공개 방의 민감한 정보를 숨김
48+
*/
49+
public static RoomResponse fromMasked(Room room) {
50+
return RoomResponse.builder()
51+
.roomId(room.getId())
52+
.title("🔒 비공개 방") // 제목 마스킹
53+
.description("비공개 방입니다") // 설명 마스킹
54+
.isPrivate(true)
55+
.currentParticipants(0) // 참가자 수 숨김
56+
.maxParticipants(0) // 정원 숨김
57+
.status(room.getStatus())
58+
.createdBy("익명") // 방장 정보 숨김
59+
.createdAt(room.getCreatedAt())
60+
.allowCamera(false) // RTC 정보 숨김
61+
.allowAudio(false)
62+
.allowScreenShare(false)
63+
.build();
64+
}
4265
}

src/main/java/com/back/domain/studyroom/repository/RoomRepositoryCustom.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,41 @@ public interface RoomRepositoryCustom {
4747
* 비관적 락으로 방 조회 (동시성 제어용)
4848
*/
4949
Optional<Room> findByIdWithLock(Long roomId);
50+
51+
/**
52+
* 모든 방 조회 (공개 + 비공개 전체)
53+
* 정렬: 열린 방(WAITING, ACTIVE) 우선 → 최신순
54+
* 비공개 방은 정보 마스킹하여 반환
55+
* @param pageable 페이징 정보
56+
* @return 페이징된 방 목록
57+
*/
58+
Page<Room> findAllRooms(Pageable pageable);
59+
60+
/**
61+
* 공개 방 전체 조회
62+
* 정렬: 열린 방 우선 → 최신순
63+
* @param includeInactive 닫힌 방(PAUSED, TERMINATED) 포함 여부
64+
* @param pageable 페이징 정보
65+
* @return 페이징된 공개 방 목록
66+
*/
67+
Page<Room> findPublicRoomsWithStatus(boolean includeInactive, Pageable pageable);
68+
69+
/**
70+
* 내가 멤버인 비공개 방 조회
71+
* 정렬: 열린 방 우선 → 최신순
72+
* @param userId 사용자 ID
73+
* @param includeInactive 닫힌 방 포함 여부
74+
* @param pageable 페이징 정보
75+
* @return 페이징된 비공개 방 목록
76+
*/
77+
Page<Room> findMyPrivateRooms(Long userId, boolean includeInactive, Pageable pageable);
78+
79+
/**
80+
* 내가 호스트(방장)인 방 조회
81+
* 정렬: 열린 방 우선 → 최신순
82+
* @param userId 사용자 ID
83+
* @param pageable 페이징 정보
84+
* @return 페이징된 방 목록
85+
*/
86+
Page<Room> findRoomsByHostId(Long userId, Pageable pageable);
5087
}

0 commit comments

Comments
 (0)