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)];
}
}
[ 참고 자료 ]
'항해99 개발 일지 > [Final] 실전 프로젝트' 카테고리의 다른 글
[14] 2주차 기술멘토링 피드백 정리 (0) | 2023.01.18 |
---|---|
[13] 트러블 슈팅 : HTTPS 배포 유의사항 (0) | 2023.01.17 |
[11] Docker (1) (0) | 2023.01.17 |
[10] Spring Security Refresh Token (2) (0) | 2023.01.14 |
[09] http vs https (0) | 2023.01.12 |