GameController

  • 웹소켓을 사용하기 때문에 @PostMapping 이 아닌 @MessageMapping 을 사용한다.
  • @PathVariable 대신 @DestinationVariable 을 사용한다.
@Slf4j
@RequiredArgsConstructor
@RestController
public class GameController {

    private final GameService gameService;

    // 게임 시작
    @MessageMapping("/game/{gameRoomId}/start")
    public ResponseEntity<?> gameStart(@DestinationVariable Long gameRoomId,
                                       GameDto gameDto) {
        gameService.gameStart(gameRoomId, gameDto);
        return ResponseUtil.response(StatusCode.GAME_START);
    }

 

KeywordRepository

  • SELECT * FROM table ORDER BY RAND(); 는 DB에서 랜덤으로 값을 추출해오는 쿼리문이다. 이 쿼리문을 이용하여 아래와 같이 작성하였다. limit 숫자 를 붙임으로써 숫자만큼의 데이터 혹은 원하는 데이터 만큼의 레코드를 가져올 수 있다.
  • @Query("select * from keyword(테이블 이름) k where k.category(테이블 안의 Colum) = :category order by rand() limit 4(4개 불러오기)")
  • 그리고 findTop4ByCategory 라는 JPA 쿼리를 통해 지정된 카테고리를 갖고있는 키워드가 4개만 조회되도록 했다. 
  • List<Keyword> findTop4ByCategory(@Param("category") String category);
public interface KeywordRepository extends JpaRepository<Keyword, Long> {
    @Query(value = "select * from keyword k where k.category = :category order by rand() limit 4", nativeQuery = true)
    List<Keyword> findTop4ByCategory(@Param("category") String category);

    @Query(value = "select * from keyword k where k.category = :category order by rand() limit 3", nativeQuery = true)
    List<Keyword> findTop3ByCategory(@Param("category") String category);
}

 

GameService ( 게임 시작 API )

1. 수정 전 코드

  • 수정 전 작성한 코드는 키워드 엔티티 안에 카테고리가 있고, 카테고리 엔티티는 따로 없는 상태로 구현한 로직이다.
  • 구현한 로직의 순서는 다음과 같다.
    • 카테고리 엔티티가 없기 때문에 바로 카테고리 조회가 불가능 했다. 그래서 가장 먼저 키워드 하나를 랜덤으로 조회해서 그 해당 키워드 카테고리를 가져온다. 랜덤 조회는 Math.random() 메소드를 이용했다.
    • 그 다음 방금 가져온 카테고리를 가진 모든 키워드들을 List<Keyword>에 담아 주었다.
    • 참여인원에 따라 keywordRepository에서 findTop4ByCategory(category) / findTop3ByCategory(category) 를 이용하여 랜덤으로 4개, 3개의 키워드를 가져온다.
    • 그다음 키워드와 게임 참여 인원을 키:밸류 로 맺어줄 HashMap<> keywordToMember 을 하나 만들어 준다. 
    • 게임참여 인원의 목록이 담긴 List<> memberListNickname 을 만들어 준다.
    • for문을 돌면서 랜덤으로 가져오 키워드를 게임 참여한 멤버에 배당한다.
    • 게임 정보를 담아주는 gameStartSet리포지토리에 반영된 데이터를 저장해 준다.
        // 멤버들에게 뿌려지게 될 키워드 전체 목록 불러오기
        List<Keyword> keywordList1 = keywordRepository.findAll();

        // 랜덤으로 키워드 하나 뽑기
        Keyword keyword1 = keywordList1.get((int) (Math.random() * keywordList1.size()) + 1);

        // 위에서 랜덤으로 뽑은 키워드의 카테고리
        String category = keyword1.getCategory();

        // 같은 카테고리를 가진 키워드 리스트 만들기
        List<Keyword> keywordList;

        if (gameRoomAttendees.size() == 4) {
            // 참여 멤버가 4명 이라면, 랜덤으로 키워드 4장이 담긴 리스트를 만들어 준다.
            keywordList = keywordRepository.findTop4ByCategory(category);
        } else if (gameRoomAttendees.size() == 3) {
            // 참여 멤버가 3명 이라면, 랜덤으로 키워드 3장이 담긴 리스트를 만들어 준다.
            keywordList = keywordRepository.findTop3ByCategory(category);
        } else {
            throw new CustomException(NOT_ENOUGH_MEMBER);
        }

        HashMap<String, String> keywordToMember = new HashMap<>();

        // 웹소켓으로 방에 참가한 인원 리스트 전달을 위한 리스트
        // 닉네임만 필요하기에 닉네임만 담음
        List<String> memberNicknameList = new ArrayList<>();

        for (GameRoomAttendee gameRoomAttendee : gameRoomAttendees) {
            memberNicknameList.add(gameRoomAttendee.getMemberNickname());
        }

        //게임룸 멤버한테 키워드 배당
        for (int i = 0; i < gameRoomAttendees.size(); i++) {
            keywordToMember.put(memberNicknameList.get(i), keywordList.get(i).getWord());
        }

        GameStartSet gameStartSet = GameStartSet.builder()
                .roomId(gameRoomId)
                .category(category)
                .keywordToMember(keywordToMember)
                .round(0)
                .spotNum(0)
                .winner("")
                .build();

        // StartSet 저장
        gameStartSetRepository.save(gameStartSet);

 

2. 수정 후 코드

  • 위에 작성된 코드는 모든 DB를 조회하는 로직이라 좀 더 효율적인 코드를 위해 Category라는 Enum 클래스를 만들어 주었다.
  • 아래는 변경된 서비스 부분이다.
  • 키워드 전체 목록을 가져와서 랜덤으로 하나 뽑아주는 로직을 제거하였다.
  • Enum 클래스 안에 만들어 놓은 .getRandom().name() 메소드를 이용하여 Enum으로 저장되어 있는 카테고리 중 하나를 랜덤으로 가져오게 하였다.

	// 카테고리 랜덤으로 가져오기 (변경된 부분)
        String category = Category.getRandom().name();

        // 같은 카테고리를 가진 키워드 리스트 만들기
        List<Keyword> keywordList;

        if (gameRoomAttendees.size() == 4) {
            // 참여 멤버가 4명 이라면, 랜덤으로 키워드 4장이 담긴 리스트를 만들어 준다.
            keywordList = keywordRepository.findTop4ByCategory(category);
        } else if (gameRoomAttendees.size() == 3) {
            // 참여 멤버가 3명 이라면, 랜덤으로 키워드 3장이 담긴 리스트를 만들어 준다.
            keywordList = keywordRepository.findTop3ByCategory(category);
        } else {
            throw new CustomException(NOT_ENOUGH_MEMBER);
        }

 

Category

  • getRandom() 메소드를 이용해 랜덤으로 값을 가져온다.
@Getter
public enum Category {

    인물, 동물, 음식, 만화, 영화, 악기;

    public static Category getRandom(){
        return values()[(int)(Math.random()* values().length)];
    }
}

 


[ 참고 자료 ]

 

 

+ Recent posts