항해99/개발일지

20220312 개발일지

paran21 2022. 3. 14. 00:09

로그인은 없고, 게임할 때만 임의로 방과 유저를 만든 후에 이를 모두 삭제하지만

게임 결과는 별도로 저장해서 보여주기로 했다.

메인페이지에서 게임 순위를 보여주는 부분이 있고, 게임 종료 후에는 해당 팀의 결과 포함 위아래 2개씩 해서 총 5개만 보여주기로 했다.

 

전체 Rank를 보여주는 api는 이미 작성한 상태고, rankList를 가져오고 나면 Dto에 넣는 과정은 비슷하기 때문에 RankService의 같은 로직을 조금만 수정해서 그대로 사용하고 싶었다.

먼저 매개변수가 있고, 없는 차이가 있었는데 이거는 Controller에서 임의값을 넣어주기로 했다.

// 전체 랭킹 조회하기
@GetMapping("/ranks")
public List<RankResponseDto> getRanks() {
    Long roomId = -1L;                      
    return rankService.getRanks(roomId);
}
// 위 아래 같은 getRanks 사용!

// 게임 종료 후 랭킹 5개 조회하기
@GetMapping("/rank/{roomId}")
public List<RankResponseDto> getRanks(@PathVariable Long roomId) {
    return rankService.getRanks(roomId);
}

그리고 roomId를 기준으로 service에서 rankList가 달라진다.

우선 순위를 따로 저장하지 않기 때문에 걸린 시간이 짧은 순으로 정렬한 전체 리스트가 필요하다.

List<Rank> rankList = rankRepository.findAllByOrderByTimeAsc();

roomId가 0보다 크면 5개만 조회하는 케이스이므로 먼저 해당 방을 찾아서 index를 기준으로 -2 ~ +2를 찾아서 rankList로 만들어주었다.

여기서 문제가 1, 2등인 경우나 꼴찌, 꼴찌-1인 경우에는 조건이 다 달라진다는 점이다.

그래서 백엔드 회의하면서 허수로 각각 2케이스를 만들어서 항상 3~꼴찌-2에 해당하도록 만들어 주었다.

 

그리고 마지막에 dto에 담을 때 해당 값들을 제외하고 담도록 구현하였다.

if (roomId > 0) {

                List<Rank> tempList = new ArrayList();

                int i;
                for (i = 0; i < rankList.size(); i++) {
                    if (rankList.get(i).getRoomId() == roomId) {
                        break;
                    }
                }

                tempList.add(rankList.get(i - 2));
                tempList.add(rankList.get(i - 1));
                tempList.add(rankList.get(i));
                tempList.add(rankList.get(i + 1));
                tempList.add(rankList.get(i + 2));
                rankList = tempList;
            }

            Long check = 1L;
            for (int i=0; i<rankList.size(); i++) {
               
                if (rankList.get(i).getTime().equals("00:00:00")) {
                    check --;
                    continue;
                } else if (rankList.get(i).getTime().equals("99:99:99")) {
                    continue;
                }

                Long rank = i + check;
                String teamName = rankList.get(i).getTeamName();
                String time = rankList.get(i).getTime();
                Integer userNum = rankList.get(i).getUserNum();
                String comment = "";
                Long rankRoomId = rankList.get(i).getRoomId();
                RankResponseDto rankResponseDto = new RankResponseDto(rankRoomId, rank, teamName, time, userNum, comment);

                rankResponseDtoList.add(rankResponseDto);
            }
            return rankResponseDtoList;

그런데 이렇게 구현한 뒤에 프론트에서 rank도 같이 보내줄 수 있는지 요청이 왔다!

어차피 5개를 보여줄 때는 해당 순위를 서버에서 계산해서 보내줘야 하기 때문에 전체 랭크 조회도 통일해서 모두 순위를 넣어주기로 했다.

 

근데 문제가 5개 랭크 보여주기에서 넣어준 임의값은 제외하고 순위를 매겨야 한다는 점이다.

특히 5개를 가져올 때 여기의 임의값이 포함되어 있으면 그 개수에 따라서 순위를 매기는 방식이 달라진다.

 

그래서 dto를 담는 for문 바깥에 check를 1로 만들어주고, 순위에 영향을 미치는 "00:00:00"이 나올 때마다 check--를 해주었다.

그리고 순위는 index인 i에 + check를 해주어서 임의값 포함 개수에 따라 다르게 계산되도록 하였다.

(솔직히 이거 구현하고 좀 뿌듯했다!!!)

 

테스트에서 상황마다 잘 계산되서 들어오는 것을 확인할 수 있었다!!


delete와 disconnect쪽도 프론트와 스프링 모두 수정이 끝나서 모두 연결해 다시 테스트해보았다.

처음에 node에 작성한 쿼리가 제대로 안 들어가서 걱정했는데 알고 보니 칼럼명을 잘못 입력해서 제대로 실행히 안된거였다!

다행히 수정 후에 작동이 잘 되는 것을 확인할 수 있었다.

프론트 & 백 모두 고민이 많았던 부분이라 잘 구현되서 다행이다.


지금 DB쪽에서 mysql를 그대로 쓰는게 맞는지 고민이 있다.

Room과 User, Clue, Quiz는 게임이 종료되면 모두 삭제될 예정이라 DB까지 저장하는게 맞는지, 아니면 인메모리 DB를 쓰는게 맞는지 고민이다.

mysql내에서도 inmemory 엔진이 있는 것 같은데 잘 쓰는 것 같지는 않고, Redis를 많이 사용하는 것 같다,

그런데 Redis는 기본적으로 NoSql인데 mysql과 어떻게 같이 쓰는지 잘 모르겠다...!!

key:value로 저장되는 걸로 알고 있는데 mysql에 연관관계가 포함된 entity를 어떻게 저장하는 건지, Redis를 사용하기 위해서는 DB구조를 다 바꿔야 하는 건지 모르겠다....!!

솔직히 개념이 구체적으로 안잡혀서 그냥 코드에서 문제해결하는게 더 재미있는 것 같다.....

 

mysql과 같이 쓴 case를 찾아서 코드를 좀 살펴보는게 더 나을 것 같다.

다음주에는 중간 발표도 예정되어 있어서 scope 신경쓰면서 검토해봐야 할 것 같다.