From a1d6dc63d0644dbf16da0d3e6d4371fb5c3b6949 Mon Sep 17 00:00:00 2001 From: silver-eunjoo Date: Wed, 16 Jul 2025 09:18:56 +0900 Subject: [PATCH 01/12] =?UTF-8?q?:sparkles:=20feat=20:=20=EC=A0=95?= =?UTF-8?q?=EB=8B=B5=EC=97=86=EC=9D=B4=20=EB=AC=B8=EC=A0=9C=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/domain/game/app/RoomService.java | 30 +++++++++++++++++++ .../game/dto/request/GameStartRequest.java | 3 ++ .../game/dto/response/GameStartResponse.java | 6 ++++ .../io/f1/backend/domain/game/model/Room.java | 4 +++ .../game/websocket/GameSocketController.java | 18 +++++++++++ .../backend/domain/quiz/app/QuizService.java | 16 ++++++++++ .../domain/quiz/dto/GameQuestionResponse.java | 3 ++ .../domain/quiz/mapper/QuizMapper.java | 15 ++++++++++ 8 files changed, 95 insertions(+) create mode 100644 backend/src/main/java/io/f1/backend/domain/game/dto/request/GameStartRequest.java create mode 100644 backend/src/main/java/io/f1/backend/domain/game/dto/response/GameStartResponse.java create mode 100644 backend/src/main/java/io/f1/backend/domain/quiz/dto/GameQuestionResponse.java diff --git a/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java b/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java index 723c8355..a7618a4c 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java +++ b/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java @@ -41,6 +41,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.atomic.AtomicLong; +import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor @@ -190,4 +191,33 @@ private static String getDestination(Long roomId) { private static Player createPlayer() { return new Player(getCurrentUserId(), getCurrentUserNickname()); } + + @Transactional(readOnly = true) + public Integer checkGameSetting(Long roomId, Long quizId) { + Room room = + roomRepository + .findRoom(roomId) + .orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다.")); + + GameSetting gameSetting = room.getGameSetting(); + + Long roomQuizId = gameSetting.getQuizId(); + + // TODO : 에러 코드 추가하기 + if(!roomQuizId.equals(quizId)) { + throw new IllegalArgumentException("게임 설정이 다릅니다. (게임을 시작할 수 없습니다.)"); + } + + return gameSetting.getRound(); + } + + @Transactional + public void gameStart(Long roomId) { + Room room = + roomRepository + .findRoom(roomId) + .orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다.")); + + room.gameStart(); + } } diff --git a/backend/src/main/java/io/f1/backend/domain/game/dto/request/GameStartRequest.java b/backend/src/main/java/io/f1/backend/domain/game/dto/request/GameStartRequest.java new file mode 100644 index 00000000..d4c30931 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/game/dto/request/GameStartRequest.java @@ -0,0 +1,3 @@ +package io.f1.backend.domain.game.dto.request; + +public record GameStartRequest(Long quizId) { } diff --git a/backend/src/main/java/io/f1/backend/domain/game/dto/response/GameStartResponse.java b/backend/src/main/java/io/f1/backend/domain/game/dto/response/GameStartResponse.java new file mode 100644 index 00000000..a8c2bc16 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/game/dto/response/GameStartResponse.java @@ -0,0 +1,6 @@ +package io.f1.backend.domain.game.dto.response; + +import io.f1.backend.domain.quiz.dto.GameQuestionResponse; +import java.util.List; + +public record GameStartResponse(List questions) { } diff --git a/backend/src/main/java/io/f1/backend/domain/game/model/Room.java b/backend/src/main/java/io/f1/backend/domain/game/model/Room.java index 00b7e71b..c448452d 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/model/Room.java +++ b/backend/src/main/java/io/f1/backend/domain/game/model/Room.java @@ -39,4 +39,8 @@ public Room(Long id, RoomSetting roomSetting, GameSetting gameSetting, Player ho public void updateHost(Player nextHost) { this.host = nextHost; } + + public void gameStart() { + this.state = RoomState.PLAYING; + } } diff --git a/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java b/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java index 9bf2f17f..489e829d 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java +++ b/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java @@ -5,6 +5,9 @@ import io.f1.backend.domain.game.dto.RoomExitData; import io.f1.backend.domain.game.dto.RoomInitialData; +import io.f1.backend.domain.game.dto.request.GameStartRequest; +import io.f1.backend.domain.game.dto.response.GameStartResponse; +import io.f1.backend.domain.quiz.app.QuizService; import lombok.RequiredArgsConstructor; import org.springframework.messaging.Message; @@ -19,6 +22,7 @@ public class GameSocketController { private final MessageSender messageSender; private final RoomService roomService; + private final QuizService quizService; @MessageMapping("/room/enter/{roomId}") public void roomEnter(@DestinationVariable Long roomId, Message message) { @@ -55,6 +59,20 @@ public void exitRoom(@DestinationVariable Long roomId, Message message) { } } + @MessageMapping("/room/start/{roomId}") + public void gameStart(@DestinationVariable Long roomId, Message message) { + + Long quizId = message.getPayload().quizId(); + + Integer round = roomService.checkGameSetting(roomId, quizId); + + // TODO : 라운드 수만큼 랜덤하게 문제 주기..! + GameStartResponse questions = quizService.getQuestionsWithoutAnswer(quizId, round); + + roomService.gameStart(roomId); + + } + private static String getSessionId(Message message) { StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message); return accessor.getSessionId(); diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java index 37c0585b..120e968f 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java @@ -4,9 +4,11 @@ import static java.nio.file.Files.deleteIfExists; +import io.f1.backend.domain.game.dto.response.GameStartResponse; import io.f1.backend.domain.question.app.QuestionService; import io.f1.backend.domain.question.dto.QuestionRequest; import io.f1.backend.domain.quiz.dao.QuizRepository; +import io.f1.backend.domain.quiz.dto.GameQuestionResponse; import io.f1.backend.domain.quiz.dto.QuizCreateRequest; import io.f1.backend.domain.quiz.dto.QuizCreateResponse; import io.f1.backend.domain.quiz.dto.QuizListPageResponse; @@ -205,6 +207,7 @@ public Long getQuizMinId() { return quizRepository.getQuizMinId(); } + @Transactional(readOnly = true) public QuizQuestionListResponse getQuizWithQuestions(Long quizId) { Quiz quiz = quizRepository @@ -213,4 +216,17 @@ public QuizQuestionListResponse getQuizWithQuestions(Long quizId) { return quizToQuizQuestionListResponse(quiz); } + + @Transactional(readOnly = true) + public GameStartResponse getQuestionsWithoutAnswer(Long quizId, Integer round) { + Quiz quiz = + quizRepository + .findById(quizId) + .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); + + + + return toGameStartResponse(quiz); + } + } diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/dto/GameQuestionResponse.java b/backend/src/main/java/io/f1/backend/domain/quiz/dto/GameQuestionResponse.java new file mode 100644 index 00000000..1c63e9c7 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/quiz/dto/GameQuestionResponse.java @@ -0,0 +1,3 @@ +package io.f1.backend.domain.quiz.dto; + +public record GameQuestionResponse(Long id, String question) { } diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java b/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java index b515f679..71614f76 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java @@ -1,7 +1,9 @@ package io.f1.backend.domain.quiz.mapper; +import io.f1.backend.domain.game.dto.response.GameStartResponse; import io.f1.backend.domain.question.dto.QuestionResponse; import io.f1.backend.domain.question.entity.Question; +import io.f1.backend.domain.quiz.dto.GameQuestionResponse; import io.f1.backend.domain.quiz.dto.QuizCreateRequest; import io.f1.backend.domain.quiz.dto.QuizCreateResponse; import io.f1.backend.domain.quiz.dto.QuizListPageResponse; @@ -83,4 +85,17 @@ public static QuizQuestionListResponse quizToQuizQuestionListResponse(Quiz quiz) quiz.getQuestions().size(), questionsToQuestionResponses(quiz.getQuestions())); } + + public static List toGameQuestionResponseList(List questions) { + return questions.stream() + .map(QuizMapper::toGameQuestionResponse).toList(); + } + + public static GameQuestionResponse toGameQuestionResponse(Question question) { + return new GameQuestionResponse(question.getId(), question.getTextQuestion().getContent()); + } + + public static GameStartResponse toGameStartResponse(Quiz quiz) { + return new GameStartResponse(toGameQuestionResponseList(quiz.getQuestions())); + } } From 4885ae91a879bd7cb8cbf488629ec70ed72c462d Mon Sep 17 00:00:00 2001 From: silver-eunjoo Date: Wed, 16 Jul 2025 10:49:21 +0900 Subject: [PATCH 02/12] =?UTF-8?q?:sparkles:=20feat=20:=20=EB=B0=A9=20?= =?UTF-8?q?=EA=B2=8C=EC=9E=84=20=EC=8B=9C=EC=9E=91=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/domain/game/app/RoomService.java | 43 ++++++++++++++----- .../domain/game/dto/GameStartData.java | 7 +++ .../backend/domain/game/dto/MessageType.java | 1 + .../io/f1/backend/domain/game/model/Room.java | 4 +- .../game/websocket/GameSocketController.java | 8 ++-- .../backend/domain/quiz/app/QuizService.java | 12 +++--- .../domain/quiz/dao/QuizRepository.java | 5 +++ .../domain/quiz/mapper/QuizMapper.java | 4 +- .../backend/global/config/SecurityConfig.java | 2 +- 9 files changed, 59 insertions(+), 27 deletions(-) create mode 100644 backend/src/main/java/io/f1/backend/domain/game/dto/GameStartData.java diff --git a/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java b/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java index a7618a4c..00f7c0af 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java +++ b/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java @@ -10,12 +10,14 @@ import static io.f1.backend.global.util.SecurityUtils.getCurrentUserId; import static io.f1.backend.global.util.SecurityUtils.getCurrentUserNickname; +import io.f1.backend.domain.game.dto.GameStartData; import io.f1.backend.domain.game.dto.RoomEventType; import io.f1.backend.domain.game.dto.RoomExitData; import io.f1.backend.domain.game.dto.RoomInitialData; import io.f1.backend.domain.game.dto.request.RoomCreateRequest; import io.f1.backend.domain.game.dto.request.RoomValidationRequest; import io.f1.backend.domain.game.dto.response.GameSettingResponse; +import io.f1.backend.domain.game.dto.response.GameStartResponse; import io.f1.backend.domain.game.dto.response.PlayerListResponse; import io.f1.backend.domain.game.dto.response.RoomCreateResponse; import io.f1.backend.domain.game.dto.response.RoomListResponse; @@ -192,32 +194,51 @@ private static Player createPlayer() { return new Player(getCurrentUserId(), getCurrentUserNickname()); } - @Transactional(readOnly = true) - public Integer checkGameSetting(Long roomId, Long quizId) { - Room room = - roomRepository - .findRoom(roomId) - .orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다.")); + private Integer checkGameSetting(Room room, Long quizId) { GameSetting gameSetting = room.getGameSetting(); Long roomQuizId = gameSetting.getQuizId(); - // TODO : 에러 코드 추가하기 if(!roomQuizId.equals(quizId)) { - throw new IllegalArgumentException("게임 설정이 다릅니다. (게임을 시작할 수 없습니다.)"); + throw new IllegalArgumentException("E409002 : 게임 설정이 다릅니다. (게임을 시작할 수 없습니다.)"); } return gameSetting.getRound(); } - @Transactional - public void gameStart(Long roomId) { + public GameStartData gameStart(Long roomId, Long quizId) { + Room room = roomRepository .findRoom(roomId) .orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다.")); - room.gameStart(); + if(!validateReadyStatus(room)){ + throw new IllegalArgumentException("E403004 : 레디 상태가 아닙니다."); + } + + // 방의 gameSetting에 설정된 퀴즈랑 요청 퀴즈랑 같은지 체크 후 GameSetting에서 라운드 가져오기 + Integer round = checkGameSetting(room, quizId); + + // 라운드 수만큼 랜덤 Question 추출 + GameStartResponse questions = quizService.getRandomQuestionsWithoutAnswer(quizId, round); + + // 방 정보 게임 중으로 변경 + room.updateRoomState(RoomState.PLAYING); + + return new GameStartData(getDestination(roomId), questions); + } + + private boolean validateReadyStatus(Room room) { + + Map playerSessionMap = room.getPlayerSessionMap(); + + for(Player player : playerSessionMap.values()) { + if(!player.isReady()) { + return false; + } + } + return true; } } diff --git a/backend/src/main/java/io/f1/backend/domain/game/dto/GameStartData.java b/backend/src/main/java/io/f1/backend/domain/game/dto/GameStartData.java new file mode 100644 index 00000000..a170e158 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/game/dto/GameStartData.java @@ -0,0 +1,7 @@ +package io.f1.backend.domain.game.dto; + +import io.f1.backend.domain.game.dto.response.GameStartResponse; + +public record GameStartData(String destination, GameStartResponse gameStartResponse) { + +} diff --git a/backend/src/main/java/io/f1/backend/domain/game/dto/MessageType.java b/backend/src/main/java/io/f1/backend/domain/game/dto/MessageType.java index f6d40420..22dfdee2 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/dto/MessageType.java +++ b/backend/src/main/java/io/f1/backend/domain/game/dto/MessageType.java @@ -5,4 +5,5 @@ public enum MessageType { GAME_SETTING, PLAYER_LIST, SYSTEM_NOTICE, + GAME_START, } diff --git a/backend/src/main/java/io/f1/backend/domain/game/model/Room.java b/backend/src/main/java/io/f1/backend/domain/game/model/Room.java index c448452d..9ded0555 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/model/Room.java +++ b/backend/src/main/java/io/f1/backend/domain/game/model/Room.java @@ -40,7 +40,7 @@ public void updateHost(Player nextHost) { this.host = nextHost; } - public void gameStart() { - this.state = RoomState.PLAYING; + public void updateRoomState(RoomState newState) { + this.state = newState; } } diff --git a/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java b/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java index 489e829d..3f159522 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java +++ b/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java @@ -1,6 +1,7 @@ package io.f1.backend.domain.game.websocket; import io.f1.backend.domain.game.app.RoomService; +import io.f1.backend.domain.game.dto.GameStartData; import io.f1.backend.domain.game.dto.MessageType; import io.f1.backend.domain.game.dto.RoomExitData; import io.f1.backend.domain.game.dto.RoomInitialData; @@ -64,12 +65,11 @@ public void gameStart(@DestinationVariable Long roomId, Message new NoSuchElementException("존재하지 않는 퀴즈입니다.")); + List randomQuestions = quizRepository.findRandQuestionsByQuizId(quizId, round); - - return toGameStartResponse(quiz); + return toGameStartResponse(randomQuestions); } } diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java b/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java index d5021088..da4c3495 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java @@ -1,7 +1,9 @@ package io.f1.backend.domain.quiz.dao; +import io.f1.backend.domain.question.entity.Question; import io.f1.backend.domain.quiz.entity.Quiz; +import java.util.List; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; @@ -15,4 +17,7 @@ public interface QuizRepository extends JpaRepository { @Query("SELECT MIN(q.id) FROM Quiz q") Long getQuizMinId(); + + @Query(value="SELECT * FROM question WHERE quiz_id = :quizId ORDER BY RAND() LIMIT :round", nativeQuery = true) + List findRandQuestionsByQuizId(Long quizId, Integer round); } diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java b/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java index 71614f76..6485e571 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java @@ -95,7 +95,7 @@ public static GameQuestionResponse toGameQuestionResponse(Question question) { return new GameQuestionResponse(question.getId(), question.getTextQuestion().getContent()); } - public static GameStartResponse toGameStartResponse(Quiz quiz) { - return new GameStartResponse(toGameQuestionResponseList(quiz.getQuestions())); + public static GameStartResponse toGameStartResponse(List questions) { + return new GameStartResponse(toGameQuestionResponseList(questions)); } } diff --git a/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java b/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java index ebcfc42e..544817cb 100644 --- a/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java +++ b/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java @@ -38,7 +38,7 @@ public SecurityFilterChain userFilterChain(HttpSecurity http) throws Exception { "/oauth2/**", "/signup", "/css/**", - "/js/**") + "/js/**","/**") .permitAll() .requestMatchers("/ws/**") .authenticated() From 3f4d0ca8eb214827a4ff3c70d24886ab6691bbbd Mon Sep 17 00:00:00 2001 From: github-actions <> Date: Wed, 16 Jul 2025 01:49:34 +0000 Subject: [PATCH 03/12] =?UTF-8?q?chore:=20Java=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../f1/backend/domain/game/app/RoomService.java | 15 +++++++-------- .../f1/backend/domain/game/dto/GameStartData.java | 4 +--- .../domain/game/dto/request/GameStartRequest.java | 2 +- .../game/dto/response/GameStartResponse.java | 3 ++- .../game/websocket/GameSocketController.java | 4 +--- .../f1/backend/domain/quiz/app/QuizService.java | 4 ++-- .../backend/domain/quiz/dao/QuizRepository.java | 7 +++++-- .../domain/quiz/dto/GameQuestionResponse.java | 2 +- .../f1/backend/domain/quiz/mapper/QuizMapper.java | 3 +-- .../f1/backend/global/config/SecurityConfig.java | 3 ++- 10 files changed, 23 insertions(+), 24 deletions(-) diff --git a/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java b/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java index 00f7c0af..d9451623 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java +++ b/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java @@ -43,7 +43,6 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.atomic.AtomicLong; -import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor @@ -200,7 +199,7 @@ private Integer checkGameSetting(Room room, Long quizId) { Long roomQuizId = gameSetting.getQuizId(); - if(!roomQuizId.equals(quizId)) { + if (!roomQuizId.equals(quizId)) { throw new IllegalArgumentException("E409002 : 게임 설정이 다릅니다. (게임을 시작할 수 없습니다.)"); } @@ -210,11 +209,11 @@ private Integer checkGameSetting(Room room, Long quizId) { public GameStartData gameStart(Long roomId, Long quizId) { Room room = - roomRepository - .findRoom(roomId) - .orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다.")); + roomRepository + .findRoom(roomId) + .orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다.")); - if(!validateReadyStatus(room)){ + if (!validateReadyStatus(room)) { throw new IllegalArgumentException("E403004 : 레디 상태가 아닙니다."); } @@ -234,8 +233,8 @@ private boolean validateReadyStatus(Room room) { Map playerSessionMap = room.getPlayerSessionMap(); - for(Player player : playerSessionMap.values()) { - if(!player.isReady()) { + for (Player player : playerSessionMap.values()) { + if (!player.isReady()) { return false; } } diff --git a/backend/src/main/java/io/f1/backend/domain/game/dto/GameStartData.java b/backend/src/main/java/io/f1/backend/domain/game/dto/GameStartData.java index a170e158..c68d056e 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/dto/GameStartData.java +++ b/backend/src/main/java/io/f1/backend/domain/game/dto/GameStartData.java @@ -2,6 +2,4 @@ import io.f1.backend.domain.game.dto.response.GameStartResponse; -public record GameStartData(String destination, GameStartResponse gameStartResponse) { - -} +public record GameStartData(String destination, GameStartResponse gameStartResponse) {} diff --git a/backend/src/main/java/io/f1/backend/domain/game/dto/request/GameStartRequest.java b/backend/src/main/java/io/f1/backend/domain/game/dto/request/GameStartRequest.java index d4c30931..61f792ea 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/dto/request/GameStartRequest.java +++ b/backend/src/main/java/io/f1/backend/domain/game/dto/request/GameStartRequest.java @@ -1,3 +1,3 @@ package io.f1.backend.domain.game.dto.request; -public record GameStartRequest(Long quizId) { } +public record GameStartRequest(Long quizId) {} diff --git a/backend/src/main/java/io/f1/backend/domain/game/dto/response/GameStartResponse.java b/backend/src/main/java/io/f1/backend/domain/game/dto/response/GameStartResponse.java index a8c2bc16..9545a8ff 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/dto/response/GameStartResponse.java +++ b/backend/src/main/java/io/f1/backend/domain/game/dto/response/GameStartResponse.java @@ -1,6 +1,7 @@ package io.f1.backend.domain.game.dto.response; import io.f1.backend.domain.quiz.dto.GameQuestionResponse; + import java.util.List; -public record GameStartResponse(List questions) { } +public record GameStartResponse(List questions) {} diff --git a/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java b/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java index 3f159522..8aa4594a 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java +++ b/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java @@ -5,10 +5,9 @@ import io.f1.backend.domain.game.dto.MessageType; import io.f1.backend.domain.game.dto.RoomExitData; import io.f1.backend.domain.game.dto.RoomInitialData; - import io.f1.backend.domain.game.dto.request.GameStartRequest; -import io.f1.backend.domain.game.dto.response.GameStartResponse; import io.f1.backend.domain.quiz.app.QuizService; + import lombok.RequiredArgsConstructor; import org.springframework.messaging.Message; @@ -70,7 +69,6 @@ public void gameStart(@DestinationVariable Long roomId, Message message) { diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java index ca3cc358..1f7ca671 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java @@ -219,12 +219,12 @@ public QuizQuestionListResponse getQuizWithQuestions(Long quizId) { @Transactional(readOnly = true) public GameStartResponse getRandomQuestionsWithoutAnswer(Long quizId, Integer round) { - quizRepository.findById(quizId) + quizRepository + .findById(quizId) .orElseThrow(() -> new NoSuchElementException("존재하지 않는 퀴즈입니다.")); List randomQuestions = quizRepository.findRandQuestionsByQuizId(quizId, round); return toGameStartResponse(randomQuestions); } - } diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java b/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java index da4c3495..bf754db7 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java @@ -3,12 +3,13 @@ import io.f1.backend.domain.question.entity.Question; import io.f1.backend.domain.quiz.entity.Quiz; -import java.util.List; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import java.util.List; + public interface QuizRepository extends JpaRepository { Page findQuizzesByTitleContaining(String title, Pageable pageable); @@ -18,6 +19,8 @@ public interface QuizRepository extends JpaRepository { @Query("SELECT MIN(q.id) FROM Quiz q") Long getQuizMinId(); - @Query(value="SELECT * FROM question WHERE quiz_id = :quizId ORDER BY RAND() LIMIT :round", nativeQuery = true) + @Query( + value = "SELECT * FROM question WHERE quiz_id = :quizId ORDER BY RAND() LIMIT :round", + nativeQuery = true) List findRandQuestionsByQuizId(Long quizId, Integer round); } diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/dto/GameQuestionResponse.java b/backend/src/main/java/io/f1/backend/domain/quiz/dto/GameQuestionResponse.java index 1c63e9c7..a47b93d9 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/dto/GameQuestionResponse.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/dto/GameQuestionResponse.java @@ -1,3 +1,3 @@ package io.f1.backend.domain.quiz.dto; -public record GameQuestionResponse(Long id, String question) { } +public record GameQuestionResponse(Long id, String question) {} diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java b/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java index 6485e571..0c0c0513 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/mapper/QuizMapper.java @@ -87,8 +87,7 @@ public static QuizQuestionListResponse quizToQuizQuestionListResponse(Quiz quiz) } public static List toGameQuestionResponseList(List questions) { - return questions.stream() - .map(QuizMapper::toGameQuestionResponse).toList(); + return questions.stream().map(QuizMapper::toGameQuestionResponse).toList(); } public static GameQuestionResponse toGameQuestionResponse(Question question) { diff --git a/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java b/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java index 544817cb..4db3bd5c 100644 --- a/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java +++ b/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java @@ -38,7 +38,8 @@ public SecurityFilterChain userFilterChain(HttpSecurity http) throws Exception { "/oauth2/**", "/signup", "/css/**", - "/js/**","/**") + "/js/**", + "/**") .permitAll() .requestMatchers("/ws/**") .authenticated() From e625940f6ebdcdf226051fd12b82c36b16d6d487 Mon Sep 17 00:00:00 2001 From: silver-eunjoo Date: Wed, 16 Jul 2025 11:01:09 +0900 Subject: [PATCH 04/12] =?UTF-8?q?:wrench:=20chore=20:=20=EC=8B=9C=ED=81=90?= =?UTF-8?q?=EB=A6=AC=ED=8B=B0=20=ED=95=84=ED=84=B0=20=EC=9E=84=EC=8B=9C=20?= =?UTF-8?q?=ED=97=88=EC=9A=A9=20=ED=95=B4=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/io/f1/backend/global/config/SecurityConfig.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java b/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java index 4db3bd5c..ebcfc42e 100644 --- a/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java +++ b/backend/src/main/java/io/f1/backend/global/config/SecurityConfig.java @@ -38,8 +38,7 @@ public SecurityFilterChain userFilterChain(HttpSecurity http) throws Exception { "/oauth2/**", "/signup", "/css/**", - "/js/**", - "/**") + "/js/**") .permitAll() .requestMatchers("/ws/**") .authenticated() From b84628e2d90e38bb5a2506c399b6f38ff44aab4d Mon Sep 17 00:00:00 2001 From: silver-eunjoo Date: Wed, 16 Jul 2025 12:09:32 +0900 Subject: [PATCH 05/12] =?UTF-8?q?:recycle:=20refactor=20:=20GameService=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/domain/game/app/GameService.java | 74 +++++++++++++++++++ .../backend/domain/game/app/RoomService.java | 47 ------------ .../game/websocket/GameSocketController.java | 5 +- 3 files changed, 77 insertions(+), 49 deletions(-) create mode 100644 backend/src/main/java/io/f1/backend/domain/game/app/GameService.java diff --git a/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java b/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java new file mode 100644 index 00000000..9da89d76 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java @@ -0,0 +1,74 @@ +package io.f1.backend.domain.game.app; + +import io.f1.backend.domain.game.dto.GameStartData; +import io.f1.backend.domain.game.dto.response.GameStartResponse; +import io.f1.backend.domain.game.model.GameSetting; +import io.f1.backend.domain.game.model.Player; +import io.f1.backend.domain.game.model.Room; +import io.f1.backend.domain.game.model.RoomState; +import io.f1.backend.domain.game.store.RoomRepository; +import io.f1.backend.domain.quiz.app.QuizService; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class GameService { + + private final QuizService quizService; + private final RoomRepository roomRepository; + + private Integer checkGameSetting(Room room, Long quizId) { + + GameSetting gameSetting = room.getGameSetting(); + + Long roomQuizId = gameSetting.getQuizId(); + + if (!roomQuizId.equals(quizId)) { + throw new IllegalArgumentException("E409002 : 게임 설정이 다릅니다. (게임을 시작할 수 없습니다.)"); + } + + return gameSetting.getRound(); + } + + public GameStartData gameStart(Long roomId, Long quizId) { + + Room room = + roomRepository + .findRoom(roomId) + .orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다.")); + + if (!validateReadyStatus(room)) { + throw new IllegalArgumentException("E403004 : 레디 상태가 아닙니다."); + } + + // 방의 gameSetting에 설정된 퀴즈랑 요청 퀴즈랑 같은지 체크 후 GameSetting에서 라운드 가져오기 + Integer round = checkGameSetting(room, quizId); + + // 라운드 수만큼 랜덤 Question 추출 + GameStartResponse questions = quizService.getRandomQuestionsWithoutAnswer(quizId, round); + + // 방 정보 게임 중으로 변경 + room.updateRoomState(RoomState.PLAYING); + + return new GameStartData(getDestination(roomId), questions); + } + + private boolean validateReadyStatus(Room room) { + + Map playerSessionMap = room.getPlayerSessionMap(); + + for (Player player : playerSessionMap.values()) { + if (!player.isReady()) { + return false; + } + } + return true; + } + + private static String getDestination(Long roomId) { + return "/sub/room/" + roomId; + } + +} diff --git a/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java b/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java index d9451623..4d504d27 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java +++ b/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java @@ -193,51 +193,4 @@ private static Player createPlayer() { return new Player(getCurrentUserId(), getCurrentUserNickname()); } - private Integer checkGameSetting(Room room, Long quizId) { - - GameSetting gameSetting = room.getGameSetting(); - - Long roomQuizId = gameSetting.getQuizId(); - - if (!roomQuizId.equals(quizId)) { - throw new IllegalArgumentException("E409002 : 게임 설정이 다릅니다. (게임을 시작할 수 없습니다.)"); - } - - return gameSetting.getRound(); - } - - public GameStartData gameStart(Long roomId, Long quizId) { - - Room room = - roomRepository - .findRoom(roomId) - .orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다.")); - - if (!validateReadyStatus(room)) { - throw new IllegalArgumentException("E403004 : 레디 상태가 아닙니다."); - } - - // 방의 gameSetting에 설정된 퀴즈랑 요청 퀴즈랑 같은지 체크 후 GameSetting에서 라운드 가져오기 - Integer round = checkGameSetting(room, quizId); - - // 라운드 수만큼 랜덤 Question 추출 - GameStartResponse questions = quizService.getRandomQuestionsWithoutAnswer(quizId, round); - - // 방 정보 게임 중으로 변경 - room.updateRoomState(RoomState.PLAYING); - - return new GameStartData(getDestination(roomId), questions); - } - - private boolean validateReadyStatus(Room room) { - - Map playerSessionMap = room.getPlayerSessionMap(); - - for (Player player : playerSessionMap.values()) { - if (!player.isReady()) { - return false; - } - } - return true; - } } diff --git a/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java b/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java index 8aa4594a..46a952cb 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java +++ b/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java @@ -1,5 +1,6 @@ package io.f1.backend.domain.game.websocket; +import io.f1.backend.domain.game.app.GameService; import io.f1.backend.domain.game.app.RoomService; import io.f1.backend.domain.game.dto.GameStartData; import io.f1.backend.domain.game.dto.MessageType; @@ -22,7 +23,7 @@ public class GameSocketController { private final MessageSender messageSender; private final RoomService roomService; - private final QuizService quizService; + private final GameService gameService; @MessageMapping("/room/enter/{roomId}") public void roomEnter(@DestinationVariable Long roomId, Message message) { @@ -64,7 +65,7 @@ public void gameStart(@DestinationVariable Long roomId, Message Date: Wed, 16 Jul 2025 03:09:47 +0000 Subject: [PATCH 06/12] =?UTF-8?q?chore:=20Java=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/f1/backend/domain/game/app/GameService.java | 12 +++++++----- .../io/f1/backend/domain/game/app/RoomService.java | 3 --- .../domain/game/websocket/GameSocketController.java | 1 - 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java b/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java index 9da89d76..51b5cd66 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java +++ b/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java @@ -8,10 +8,13 @@ import io.f1.backend.domain.game.model.RoomState; import io.f1.backend.domain.game.store.RoomRepository; import io.f1.backend.domain.quiz.app.QuizService; -import java.util.Map; + import lombok.RequiredArgsConstructor; + import org.springframework.stereotype.Service; +import java.util.Map; + @Service @RequiredArgsConstructor public class GameService { @@ -35,9 +38,9 @@ private Integer checkGameSetting(Room room, Long quizId) { public GameStartData gameStart(Long roomId, Long quizId) { Room room = - roomRepository - .findRoom(roomId) - .orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다.")); + roomRepository + .findRoom(roomId) + .orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다.")); if (!validateReadyStatus(room)) { throw new IllegalArgumentException("E403004 : 레디 상태가 아닙니다."); @@ -70,5 +73,4 @@ private boolean validateReadyStatus(Room room) { private static String getDestination(Long roomId) { return "/sub/room/" + roomId; } - } diff --git a/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java b/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java index 4d504d27..723c8355 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java +++ b/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java @@ -10,14 +10,12 @@ import static io.f1.backend.global.util.SecurityUtils.getCurrentUserId; import static io.f1.backend.global.util.SecurityUtils.getCurrentUserNickname; -import io.f1.backend.domain.game.dto.GameStartData; import io.f1.backend.domain.game.dto.RoomEventType; import io.f1.backend.domain.game.dto.RoomExitData; import io.f1.backend.domain.game.dto.RoomInitialData; import io.f1.backend.domain.game.dto.request.RoomCreateRequest; import io.f1.backend.domain.game.dto.request.RoomValidationRequest; import io.f1.backend.domain.game.dto.response.GameSettingResponse; -import io.f1.backend.domain.game.dto.response.GameStartResponse; import io.f1.backend.domain.game.dto.response.PlayerListResponse; import io.f1.backend.domain.game.dto.response.RoomCreateResponse; import io.f1.backend.domain.game.dto.response.RoomListResponse; @@ -192,5 +190,4 @@ private static String getDestination(Long roomId) { private static Player createPlayer() { return new Player(getCurrentUserId(), getCurrentUserNickname()); } - } diff --git a/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java b/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java index 46a952cb..8acae13b 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java +++ b/backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java @@ -7,7 +7,6 @@ import io.f1.backend.domain.game.dto.RoomExitData; import io.f1.backend.domain.game.dto.RoomInitialData; import io.f1.backend.domain.game.dto.request.GameStartRequest; -import io.f1.backend.domain.quiz.app.QuizService; import lombok.RequiredArgsConstructor; From 7fac78ac47c159966e09edbe051f7709337b192e Mon Sep 17 00:00:00 2001 From: silver-eunjoo Date: Wed, 16 Jul 2025 12:14:06 +0900 Subject: [PATCH 07/12] =?UTF-8?q?:wrench:=20chore=20:=20merge=20=EC=9E=98?= =?UTF-8?q?=EB=AA=BB=20=ED=95=9C=20=EA=B1=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/main/java/io/f1/backend/domain/game/model/Room.java | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/main/java/io/f1/backend/domain/game/model/Room.java b/backend/src/main/java/io/f1/backend/domain/game/model/Room.java index f45cb02b..8877ab83 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/model/Room.java +++ b/backend/src/main/java/io/f1/backend/domain/game/model/Room.java @@ -49,6 +49,7 @@ public void updateHost(Player nextHost) { public void updateRoomState(RoomState newState) { this.state = newState; + } public void removeUserId(Long id) { this.userIdSessionMap.remove(id); From b975a3c332b4d866051cd518724972a3c30a0a5d Mon Sep 17 00:00:00 2001 From: github-actions <> Date: Wed, 16 Jul 2025 03:14:18 +0000 Subject: [PATCH 08/12] =?UTF-8?q?chore:=20Java=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/main/java/io/f1/backend/domain/game/model/Room.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/src/main/java/io/f1/backend/domain/game/model/Room.java b/backend/src/main/java/io/f1/backend/domain/game/model/Room.java index 8877ab83..d42abc8d 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/model/Room.java +++ b/backend/src/main/java/io/f1/backend/domain/game/model/Room.java @@ -46,7 +46,6 @@ public void updateHost(Player nextHost) { this.host = nextHost; } - public void updateRoomState(RoomState newState) { this.state = newState; } @@ -57,6 +56,5 @@ public void removeUserId(Long id) { public void removeSessionId(String sessionId) { this.playerSessionMap.remove(sessionId); - } } From 0c3ff2bb962f2407ccde1c063dd25cbcabb7be19 Mon Sep 17 00:00:00 2001 From: silver-eunjoo Date: Wed, 16 Jul 2025 12:40:00 +0900 Subject: [PATCH 09/12] =?UTF-8?q?:sparkles:=20=EA=B2=8C=EC=9E=84=20?= =?UTF-8?q?=EC=8B=9C=EC=9E=91=20=EC=83=81=ED=83=9C=20SSE=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=ED=8D=BC=EB=B8=94=EB=A6=AC?= =?UTF-8?q?=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/domain/game/app/GameService.java | 39 ++++++++++++------- .../backend/domain/game/app/RoomService.java | 6 +-- .../backend/domain/quiz/app/QuizService.java | 5 +-- .../domain/quiz/dao/QuizRepository.java | 5 +++ 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java b/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java index 51b5cd66..bd2cc587 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java +++ b/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java @@ -2,6 +2,7 @@ import io.f1.backend.domain.game.dto.GameStartData; import io.f1.backend.domain.game.dto.response.GameStartResponse; +import io.f1.backend.domain.game.event.RoomUpdatedEvent; import io.f1.backend.domain.game.model.GameSetting; import io.f1.backend.domain.game.model.Player; import io.f1.backend.domain.game.model.Room; @@ -9,8 +10,10 @@ import io.f1.backend.domain.game.store.RoomRepository; import io.f1.backend.domain.quiz.app.QuizService; +import io.f1.backend.domain.quiz.entity.Quiz; import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import java.util.Map; @@ -21,26 +24,15 @@ public class GameService { private final QuizService quizService; private final RoomRepository roomRepository; + private final ApplicationEventPublisher eventPublisher; - private Integer checkGameSetting(Room room, Long quizId) { - - GameSetting gameSetting = room.getGameSetting(); - - Long roomQuizId = gameSetting.getQuizId(); - - if (!roomQuizId.equals(quizId)) { - throw new IllegalArgumentException("E409002 : 게임 설정이 다릅니다. (게임을 시작할 수 없습니다.)"); - } - - return gameSetting.getRound(); - } public GameStartData gameStart(Long roomId, Long quizId) { Room room = - roomRepository - .findRoom(roomId) - .orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다.")); + roomRepository + .findRoom(roomId) + .orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다.")); if (!validateReadyStatus(room)) { throw new IllegalArgumentException("E403004 : 레디 상태가 아닙니다."); @@ -49,15 +41,32 @@ public GameStartData gameStart(Long roomId, Long quizId) { // 방의 gameSetting에 설정된 퀴즈랑 요청 퀴즈랑 같은지 체크 후 GameSetting에서 라운드 가져오기 Integer round = checkGameSetting(room, quizId); + Quiz quiz = quizService.getQuizWithQuestionsById(quizId); + // 라운드 수만큼 랜덤 Question 추출 GameStartResponse questions = quizService.getRandomQuestionsWithoutAnswer(quizId, round); // 방 정보 게임 중으로 변경 room.updateRoomState(RoomState.PLAYING); + eventPublisher.publishEvent(new RoomUpdatedEvent(room, quiz)); + return new GameStartData(getDestination(roomId), questions); } + private Integer checkGameSetting(Room room, Long quizId) { + + GameSetting gameSetting = room.getGameSetting(); + + Long roomQuizId = gameSetting.getQuizId(); + + if (!roomQuizId.equals(quizId)) { + throw new IllegalArgumentException("E409002 : 게임 설정이 다릅니다. (게임을 시작할 수 없습니다.)"); + } + + return gameSetting.getRound(); + } + private boolean validateReadyStatus(Room room) { Map playerSessionMap = room.getPlayerSessionMap(); diff --git a/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java b/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java index 27c1522c..dd31a875 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java +++ b/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java @@ -60,7 +60,7 @@ public class RoomService { public RoomCreateResponse saveRoom(RoomCreateRequest request) { Long quizMinId = quizService.getQuizMinId(); - Quiz quiz = quizService.getQuizById(quizMinId); + Quiz quiz = quizService.getQuizWithQuestionsById(quizMinId); GameSetting gameSetting = toGameSetting(quiz); @@ -132,7 +132,7 @@ public RoomInitialData initializeRoomSocket(Long roomId, String sessionId) { RoomSettingResponse roomSettingResponse = toRoomSettingResponse(room); Long quizId = room.getGameSetting().getQuizId(); - Quiz quiz = quizService.getQuizById(quizId); + Quiz quiz = quizService.getQuizWithQuestionsById(quizId); GameSettingResponse gameSettingResponse = toGameSettingResponse(room.getGameSetting(), quiz); @@ -189,7 +189,7 @@ public RoomListResponse getAllRooms() { .map( room -> { Long quizId = room.getGameSetting().getQuizId(); - Quiz quiz = quizService.getQuizById(quizId); + Quiz quiz = quizService.getQuizWithQuestionsById(quizId); return toRoomResponse(room, quiz); }) diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java index d7e562ac..ce705fb6 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/app/QuizService.java @@ -216,12 +216,11 @@ public QuizListPageResponse getQuizzes(String title, String creator, Pageable pa } @Transactional(readOnly = true) - public Quiz getQuizById(Long quizId) { + public Quiz getQuizWithQuestionsById(Long quizId) { Quiz quiz = quizRepository - .findById(quizId) + .findQuizWithQuestionsById(quizId) .orElseThrow(() -> new RuntimeException("E404002: 존재하지 않는 퀴즈입니다.")); - quiz.getQuestions().size(); return quiz; } diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java b/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java index bf754db7..2097dec0 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java @@ -3,12 +3,14 @@ import io.f1.backend.domain.question.entity.Question; import io.f1.backend.domain.quiz.entity.Quiz; +import java.util.Optional; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import java.util.List; +import org.springframework.data.repository.query.Param; public interface QuizRepository extends JpaRepository { @@ -16,6 +18,9 @@ public interface QuizRepository extends JpaRepository { Page findQuizzesByCreator_NicknameContaining(String creator, Pageable pageable); + @Query("SELECT q FROM Quiz q LEFT JOIN FETCH q.questions WHERE q.id = :quizId") + Optional findQuizWithQuestionsById(Long quizId); + @Query("SELECT MIN(q.id) FROM Quiz q") Long getQuizMinId(); From e63e36c0717ad1f241c8da74006895289e68a251 Mon Sep 17 00:00:00 2001 From: github-actions <> Date: Wed, 16 Jul 2025 03:40:24 +0000 Subject: [PATCH 10/12] =?UTF-8?q?chore:=20Java=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/f1/backend/domain/game/app/GameService.java | 9 ++++----- .../io/f1/backend/domain/quiz/dao/QuizRepository.java | 3 +-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java b/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java index bd2cc587..491a24ed 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java +++ b/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java @@ -9,8 +9,8 @@ import io.f1.backend.domain.game.model.RoomState; import io.f1.backend.domain.game.store.RoomRepository; import io.f1.backend.domain.quiz.app.QuizService; - import io.f1.backend.domain.quiz.entity.Quiz; + import lombok.RequiredArgsConstructor; import org.springframework.context.ApplicationEventPublisher; @@ -26,13 +26,12 @@ public class GameService { private final RoomRepository roomRepository; private final ApplicationEventPublisher eventPublisher; - public GameStartData gameStart(Long roomId, Long quizId) { Room room = - roomRepository - .findRoom(roomId) - .orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다.")); + roomRepository + .findRoom(roomId) + .orElseThrow(() -> new IllegalArgumentException("404 존재하지 않는 방입니다.")); if (!validateReadyStatus(room)) { throw new IllegalArgumentException("E403004 : 레디 상태가 아닙니다."); diff --git a/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java b/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java index 2097dec0..b2d1728d 100644 --- a/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java +++ b/backend/src/main/java/io/f1/backend/domain/quiz/dao/QuizRepository.java @@ -3,14 +3,13 @@ import io.f1.backend.domain.question.entity.Question; import io.f1.backend.domain.quiz.entity.Quiz; -import java.util.Optional; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import java.util.List; -import org.springframework.data.repository.query.Param; +import java.util.Optional; public interface QuizRepository extends JpaRepository { From e54b9a63310f59813080b98ff8cf5cf95728a68a Mon Sep 17 00:00:00 2001 From: silver-eunjoo Date: Wed, 16 Jul 2025 14:27:29 +0900 Subject: [PATCH 11/12] =?UTF-8?q?:recycle:=20refactor=20:=20PR=20=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EB=B0=98=EC=98=81(stream().allMatch,=20gameSetting?= =?UTF-8?q?=20=EB=82=B4=EB=B6=80=20=EB=A9=94=EC=84=9C=EB=93=9C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/f1/backend/domain/game/app/GameService.java | 12 +++--------- .../io/f1/backend/domain/game/model/GameSetting.java | 7 +++++++ .../java/io/f1/backend/domain/game/model/Room.java | 1 + 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java b/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java index 491a24ed..a384a219 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java +++ b/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java @@ -57,9 +57,7 @@ private Integer checkGameSetting(Room room, Long quizId) { GameSetting gameSetting = room.getGameSetting(); - Long roomQuizId = gameSetting.getQuizId(); - - if (!roomQuizId.equals(quizId)) { + if (!gameSetting.checkQuizId(quizId)) { throw new IllegalArgumentException("E409002 : 게임 설정이 다릅니다. (게임을 시작할 수 없습니다.)"); } @@ -70,12 +68,8 @@ private boolean validateReadyStatus(Room room) { Map playerSessionMap = room.getPlayerSessionMap(); - for (Player player : playerSessionMap.values()) { - if (!player.isReady()) { - return false; - } - } - return true; + return playerSessionMap.values().stream().allMatch(Player::isReady); + } private static String getDestination(Long roomId) { diff --git a/backend/src/main/java/io/f1/backend/domain/game/model/GameSetting.java b/backend/src/main/java/io/f1/backend/domain/game/model/GameSetting.java index 7643d861..70cd8c25 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/model/GameSetting.java +++ b/backend/src/main/java/io/f1/backend/domain/game/model/GameSetting.java @@ -10,4 +10,11 @@ public class GameSetting { private Long quizId; private Integer round; // 게임 변경 시 해당 게임의 총 문제 수로 설정 private int timeLimit = 60; + + public boolean checkQuizId(Long quizId) { + if(this.quizId != null && this.quizId.equals(quizId)) { + return false; + } + return true; + } } diff --git a/backend/src/main/java/io/f1/backend/domain/game/model/Room.java b/backend/src/main/java/io/f1/backend/domain/game/model/Room.java index d42abc8d..e71a4f0d 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/model/Room.java +++ b/backend/src/main/java/io/f1/backend/domain/game/model/Room.java @@ -57,4 +57,5 @@ public void removeUserId(Long id) { public void removeSessionId(String sessionId) { this.playerSessionMap.remove(sessionId); } + } From 55d53eca1123aa59d9249b492511b288def7569b Mon Sep 17 00:00:00 2001 From: github-actions <> Date: Wed, 16 Jul 2025 05:27:51 +0000 Subject: [PATCH 12/12] =?UTF-8?q?chore:=20Java=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/io/f1/backend/domain/game/app/GameService.java | 1 - .../main/java/io/f1/backend/domain/game/model/GameSetting.java | 2 +- backend/src/main/java/io/f1/backend/domain/game/model/Room.java | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java b/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java index a384a219..12cbd7ed 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java +++ b/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java @@ -69,7 +69,6 @@ private boolean validateReadyStatus(Room room) { Map playerSessionMap = room.getPlayerSessionMap(); return playerSessionMap.values().stream().allMatch(Player::isReady); - } private static String getDestination(Long roomId) { diff --git a/backend/src/main/java/io/f1/backend/domain/game/model/GameSetting.java b/backend/src/main/java/io/f1/backend/domain/game/model/GameSetting.java index 70cd8c25..7634d114 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/model/GameSetting.java +++ b/backend/src/main/java/io/f1/backend/domain/game/model/GameSetting.java @@ -12,7 +12,7 @@ public class GameSetting { private int timeLimit = 60; public boolean checkQuizId(Long quizId) { - if(this.quizId != null && this.quizId.equals(quizId)) { + if (this.quizId != null && this.quizId.equals(quizId)) { return false; } return true; diff --git a/backend/src/main/java/io/f1/backend/domain/game/model/Room.java b/backend/src/main/java/io/f1/backend/domain/game/model/Room.java index e71a4f0d..d42abc8d 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/model/Room.java +++ b/backend/src/main/java/io/f1/backend/domain/game/model/Room.java @@ -57,5 +57,4 @@ public void removeUserId(Long id) { public void removeSessionId(String sessionId) { this.playerSessionMap.remove(sessionId); } - }