Skip to content

Commit 233cc6d

Browse files
authored
✨ 방 퇴장(삭제) 구현
* ✨ 방 퇴장 구현 * ✨ 유저 정보 가져오기 적용 * ✨ quiz api 적용 * ♻️ LocaldateTime -> Instant, lazy 예외 fix * chore: Java 스타일 수정 * ♻️ 미사용 import 제거 * ♻️ 리뷰 내용 반영 * ♻️ import 추가 * chore: Java 스타일 수정 * ♻️ 변수명 통일 * ♻️ 빌더패턴으로 변경 하면서 누락된 값 추가 --------- Co-authored-by: github-actions <>
1 parent 5501997 commit 233cc6d

File tree

14 files changed

+212
-38
lines changed

14 files changed

+212
-38
lines changed

backend/src/main/java/io/f1/backend/domain/game/api/RoomController.java

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@
1818
import org.springframework.web.bind.annotation.ResponseStatus;
1919
import org.springframework.web.bind.annotation.RestController;
2020

21-
import java.util.HashMap;
22-
import java.util.Map;
23-
2421
@RestController
2522
@RequestMapping("/rooms")
2623
@RequiredArgsConstructor
@@ -31,12 +28,7 @@ public class RoomController {
3128
@PostMapping
3229
@ResponseStatus(HttpStatus.CREATED)
3330
public RoomCreateResponse saveRoom(@RequestBody @Valid RoomCreateRequest request) {
34-
35-
Map<String, Object> loginUser = new HashMap<>();
36-
loginUser.put("id", 1L);
37-
loginUser.put("nickname", "빵야빵야");
38-
39-
return roomService.saveRoom(request, loginUser);
31+
return roomService.saveRoom(request);
4032
}
4133

4234
@PostMapping("/validation")

backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java

Lines changed: 82 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,27 @@
11
package io.f1.backend.domain.game.app;
22

3-
import static io.f1.backend.domain.game.mapper.RoomMapper.*;
4-
3+
import static io.f1.backend.domain.game.mapper.RoomMapper.ofPlayerEvent;
4+
import static io.f1.backend.domain.game.mapper.RoomMapper.toGameSetting;
5+
import static io.f1.backend.domain.game.mapper.RoomMapper.toGameSettingResponse;
6+
import static io.f1.backend.domain.game.mapper.RoomMapper.toPlayerListResponse;
7+
import static io.f1.backend.domain.game.mapper.RoomMapper.toRoomResponse;
8+
import static io.f1.backend.domain.game.mapper.RoomMapper.toRoomSetting;
9+
import static io.f1.backend.domain.game.mapper.RoomMapper.toRoomSettingResponse;
10+
import static io.f1.backend.global.util.SecurityUtils.getCurrentUserId;
11+
import static io.f1.backend.global.util.SecurityUtils.getCurrentUserNickname;
12+
13+
import io.f1.backend.domain.game.dto.RoomEventType;
14+
import io.f1.backend.domain.game.dto.RoomExitData;
515
import io.f1.backend.domain.game.dto.RoomInitialData;
616
import io.f1.backend.domain.game.dto.request.RoomCreateRequest;
717
import io.f1.backend.domain.game.dto.request.RoomValidationRequest;
818
import io.f1.backend.domain.game.dto.response.GameSettingResponse;
919
import io.f1.backend.domain.game.dto.response.PlayerListResponse;
10-
import io.f1.backend.domain.game.dto.response.QuizResponse;
1120
import io.f1.backend.domain.game.dto.response.RoomCreateResponse;
1221
import io.f1.backend.domain.game.dto.response.RoomListResponse;
1322
import io.f1.backend.domain.game.dto.response.RoomResponse;
1423
import io.f1.backend.domain.game.dto.response.RoomSettingResponse;
24+
import io.f1.backend.domain.game.dto.response.SystemNoticeResponse;
1525
import io.f1.backend.domain.game.event.RoomCreatedEvent;
1626
import io.f1.backend.domain.game.model.GameSetting;
1727
import io.f1.backend.domain.game.model.Player;
@@ -29,6 +39,7 @@
2939

3040
import java.util.List;
3141
import java.util.Map;
42+
import java.util.Optional;
3243
import java.util.concurrent.atomic.AtomicLong;
3344

3445
@Service
@@ -40,12 +51,15 @@ public class RoomService {
4051
private final AtomicLong roomIdGenerator = new AtomicLong(0);
4152
private final ApplicationEventPublisher eventPublisher;
4253

43-
public RoomCreateResponse saveRoom(RoomCreateRequest request, Map<String, Object> loginUser) {
54+
public RoomCreateResponse saveRoom(RoomCreateRequest request) {
55+
56+
Long quizMinId = quizService.getQuizMinId();
57+
Quiz quiz = quizService.getQuizById(quizMinId);
58+
59+
GameSetting gameSetting = toGameSetting(quiz);
60+
61+
Player host = createPlayer();
4462

45-
// todo 제일 작은 index quizId 가져와서 gameSetting(round 설정)
46-
GameSetting gameSetting = new GameSetting(1L, 10, 60);
47-
// todo security에서 가져오는걸로 변경
48-
Player host = new Player((Long) loginUser.get("id"), loginUser.get("nickname").toString());
4963
RoomSetting roomSetting = toRoomSetting(request);
5064

5165
Long newId = roomIdGenerator.incrementAndGet();
@@ -54,9 +68,6 @@ public RoomCreateResponse saveRoom(RoomCreateRequest request, Map<String, Object
5468

5569
roomRepository.saveRoom(room);
5670

57-
Long quizId = room.getGameSetting().getQuizId();
58-
Quiz quiz = quizService.getQuizById(quizId);
59-
6071
eventPublisher.publishEvent(new RoomCreatedEvent(room, quiz));
6172

6273
return new RoomCreateResponse(newId);
@@ -67,7 +78,7 @@ public void validateRoom(RoomValidationRequest request) {
6778
Room room =
6879
roomRepository
6980
.findRoom(request.roomId())
70-
.orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다."));
81+
.orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다.-1"));
7182

7283
if (room.getState().equals(RoomState.PLAYING)) {
7384
throw new IllegalArgumentException("403 게임이 진행중입니다.");
@@ -92,26 +103,69 @@ public RoomInitialData enterRoom(Long roomId, String sessionId) {
92103
.findRoom(roomId)
93104
.orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다."));
94105

95-
// todo security
96-
Player player = new Player(1L, "빵야빵야");
106+
Player player = createPlayer();
97107

98108
Map<String, Player> playerSessionMap = room.getPlayerSessionMap();
99109

100110
playerSessionMap.put(sessionId, player);
101111

102-
String destination = "/sub/room/" + roomId;
103-
104112
RoomSettingResponse roomSettingResponse = toRoomSettingResponse(room);
105-
// todo quiz 생성 api 완성 후 수정
106-
QuizResponse quiz =
107-
new QuizResponse(room.getGameSetting().getQuizId(), "title", "설명", "url", 10);
113+
114+
Long quizId = room.getGameSetting().getQuizId();
115+
Quiz quiz = quizService.getQuizById(quizId);
116+
108117
GameSettingResponse gameSettingResponse =
109118
toGameSettingResponse(room.getGameSetting(), quiz);
110119

111120
PlayerListResponse playerListResponse = toPlayerListResponse(room);
112121

122+
SystemNoticeResponse systemNoticeResponse = ofPlayerEvent(player, RoomEventType.ENTER);
123+
113124
return new RoomInitialData(
114-
destination, roomSettingResponse, gameSettingResponse, playerListResponse);
125+
getDestination(roomId),
126+
roomSettingResponse,
127+
gameSettingResponse,
128+
playerListResponse,
129+
systemNoticeResponse);
130+
}
131+
132+
public RoomExitData exitRoom(Long roomId, String sessionId) {
133+
Room room =
134+
roomRepository
135+
.findRoom(roomId)
136+
.orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다."));
137+
138+
Map<String, Player> playerSessionMap = room.getPlayerSessionMap();
139+
140+
String destination = getDestination(roomId);
141+
142+
if (playerSessionMap.size() == 1 && playerSessionMap.get(sessionId) != null) {
143+
roomRepository.removeRoom(roomId);
144+
return RoomExitData.builder().destination(destination).removedRoom(true).build();
145+
}
146+
147+
Player removedPlayer = playerSessionMap.remove(sessionId);
148+
if (removedPlayer == null) {
149+
throw new IllegalArgumentException("퇴장 처리 불가 - 404 해당 세션 플레이어는 존재하지않습니다.");
150+
}
151+
152+
if (room.getHost().getId().equals(removedPlayer.getId())) {
153+
Optional<String> nextHostSessionId = playerSessionMap.keySet().stream().findFirst();
154+
Player nextHost =
155+
playerSessionMap.get(
156+
nextHostSessionId.orElseThrow(
157+
() ->
158+
new IllegalArgumentException(
159+
"방장 교체 불가 - 404 해당 세션 플레이어는 존재하지않습니다.")));
160+
room.updateHost(nextHost);
161+
}
162+
163+
SystemNoticeResponse systemNoticeResponse =
164+
ofPlayerEvent(removedPlayer, RoomEventType.EXIT);
165+
166+
PlayerListResponse playerListResponse = toPlayerListResponse(room);
167+
168+
return new RoomExitData(destination, playerListResponse, systemNoticeResponse, false);
115169
}
116170

117171
public RoomListResponse getAllRooms() {
@@ -128,4 +182,12 @@ public RoomListResponse getAllRooms() {
128182
.toList();
129183
return new RoomListResponse(roomResponses);
130184
}
185+
186+
private static String getDestination(Long roomId) {
187+
return "/sub/room/" + roomId;
188+
}
189+
190+
private static Player createPlayer() {
191+
return new Player(getCurrentUserId(), getCurrentUserNickname());
192+
}
131193
}

backend/src/main/java/io/f1/backend/domain/game/dto/MessageType.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ public enum MessageType {
44
ROOM_SETTING,
55
GAME_SETTING,
66
PLAYER_LIST,
7+
SYSTEM_NOTICE,
78
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package io.f1.backend.domain.game.dto;
2+
3+
public enum RoomEventType {
4+
ENTER,
5+
EXIT,
6+
START,
7+
END,
8+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package io.f1.backend.domain.game.dto;
2+
3+
import io.f1.backend.domain.game.dto.response.PlayerListResponse;
4+
import io.f1.backend.domain.game.dto.response.SystemNoticeResponse;
5+
6+
import lombok.Builder;
7+
import lombok.Getter;
8+
9+
@Getter
10+
public class RoomExitData {
11+
12+
private final String destination;
13+
private final PlayerListResponse playerListResponses;
14+
private final SystemNoticeResponse systemNoticeResponse;
15+
private final boolean removedRoom;
16+
17+
@Builder
18+
public RoomExitData(
19+
String destination,
20+
PlayerListResponse playerListResponses,
21+
SystemNoticeResponse systemNoticeResponse,
22+
boolean removedRoom) {
23+
this.destination = destination;
24+
this.playerListResponses = playerListResponses;
25+
this.systemNoticeResponse = systemNoticeResponse;
26+
this.removedRoom = removedRoom;
27+
}
28+
}

backend/src/main/java/io/f1/backend/domain/game/dto/RoomInitialData.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
import io.f1.backend.domain.game.dto.response.GameSettingResponse;
44
import io.f1.backend.domain.game.dto.response.PlayerListResponse;
55
import io.f1.backend.domain.game.dto.response.RoomSettingResponse;
6+
import io.f1.backend.domain.game.dto.response.SystemNoticeResponse;
67

78
public record RoomInitialData(
89
String destination,
910
RoomSettingResponse roomSettingResponse,
1011
GameSettingResponse gameSettingResponse,
11-
PlayerListResponse playerListResponse) {}
12+
PlayerListResponse playerListResponse,
13+
SystemNoticeResponse systemNoticeResponse) {}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package io.f1.backend.domain.game.dto.response;
2+
3+
import java.time.Instant;
4+
5+
public record SystemNoticeResponse(String noticeMessage, Instant timestamp) {}

backend/src/main/java/io/f1/backend/domain/game/mapper/RoomMapper.java

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,46 @@
11
package io.f1.backend.domain.game.mapper;
22

3+
import io.f1.backend.domain.game.dto.RoomEventType;
34
import io.f1.backend.domain.game.dto.request.RoomCreateRequest;
45
import io.f1.backend.domain.game.dto.response.GameSettingResponse;
56
import io.f1.backend.domain.game.dto.response.PlayerListResponse;
67
import io.f1.backend.domain.game.dto.response.PlayerResponse;
78
import io.f1.backend.domain.game.dto.response.QuizResponse;
89
import io.f1.backend.domain.game.dto.response.RoomResponse;
910
import io.f1.backend.domain.game.dto.response.RoomSettingResponse;
11+
import io.f1.backend.domain.game.dto.response.SystemNoticeResponse;
1012
import io.f1.backend.domain.game.model.GameSetting;
13+
import io.f1.backend.domain.game.model.Player;
1114
import io.f1.backend.domain.game.model.Room;
1215
import io.f1.backend.domain.game.model.RoomSetting;
1316
import io.f1.backend.domain.quiz.entity.Quiz;
1417

18+
import java.time.Instant;
1519
import java.util.List;
1620

1721
public class RoomMapper {
1822

23+
private static final int DEFAULT_TIME_LIMIT = 60;
24+
1925
public static RoomSetting toRoomSetting(RoomCreateRequest request) {
2026
return new RoomSetting(
2127
request.roomName(), request.maxUserCount(), request.locked(), request.password());
2228
}
2329

30+
public static GameSetting toGameSetting(Quiz quiz) {
31+
return new GameSetting(quiz.getId(), quiz.getQuestions().size(), DEFAULT_TIME_LIMIT);
32+
}
33+
2434
public static RoomSettingResponse toRoomSettingResponse(Room room) {
2535
return new RoomSettingResponse(
2636
room.getRoomSetting().roomName(),
2737
room.getRoomSetting().maxUserCount(),
2838
room.getPlayerSessionMap().size());
2939
}
3040

31-
public static GameSettingResponse toGameSettingResponse(
32-
GameSetting gameSetting, QuizResponse quiz) {
33-
return new GameSettingResponse(gameSetting.getRound(), gameSetting.getTimeLimit(), quiz);
41+
public static GameSettingResponse toGameSettingResponse(GameSetting gameSetting, Quiz quiz) {
42+
return new GameSettingResponse(
43+
gameSetting.getRound(), gameSetting.getTimeLimit(), toQuizResponse(quiz));
3444
}
3545

3646
public static PlayerListResponse toPlayerListResponse(Room room) {
@@ -56,4 +66,23 @@ public static RoomResponse toRoomResponse(Room room, Quiz quiz) {
5666
quiz.getQuestions().size(),
5767
quiz.getThumbnailUrl());
5868
}
69+
70+
public static QuizResponse toQuizResponse(Quiz quiz) {
71+
return new QuizResponse(
72+
quiz.getId(),
73+
quiz.getTitle(),
74+
quiz.getDescription(),
75+
quiz.getThumbnailUrl(),
76+
quiz.getQuestions().size());
77+
}
78+
79+
public static SystemNoticeResponse ofPlayerEvent(Player player, RoomEventType roomEventType) {
80+
String message = "";
81+
if (roomEventType == RoomEventType.ENTER) {
82+
message = " 님이 입장하셨습니다";
83+
} else if (roomEventType == RoomEventType.EXIT) {
84+
message = " 님이 퇴장하셨습니다";
85+
}
86+
return new SystemNoticeResponse(player.getNickname() + message, Instant.now());
87+
}
5988
}

backend/src/main/java/io/f1/backend/domain/game/model/Room.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,8 @@ public Room(Long id, RoomSetting roomSetting, GameSetting gameSetting, Player ho
3535
this.gameSetting = gameSetting;
3636
this.host = host;
3737
}
38+
39+
public void updateHost(Player nextHost) {
40+
this.host = nextHost;
41+
}
3842
}

backend/src/main/java/io/f1/backend/domain/game/store/RoomRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,6 @@ public interface RoomRepository {
1111
Optional<Room> findRoom(Long roomId);
1212

1313
List<Room> findAll();
14+
15+
void removeRoom(Long roomId);
1416
}

0 commit comments

Comments
 (0)