221207 TIL 어떤 게시판에 게시글이 가장 많을까?

오늘은 최상위 게시판(EPL, LaLiga, SerieA, Bundesliga) 4개 중 어떤 게시판의 비중이 가장 큰지 알기 위해 4대 리그 게시판별 게시글을 종합하는 작업을 했다. 예를 들어 EPL 게시판을 부모로 갖고 있는 하위 게시판에 있는 게시글을 모두 종합하는 작업이다.
그런데 리그 게시판이 하위 게시판들의의 게시글을 갖고 있지 않아 findAll 같이 간단하게 구할 수 있는 문제가 아니였기 때문에 어떻게 모든 게시판의 게시글을 찾을지 고민을 했다.
우선 게시판의 구조가 총 3 depth(리그 게시판 -> 팀 게시판 -> 선수 게시판)로 구성된 게시판이기 때문에 리그 게시판을 부모로 갖고 있는 모든 팀 게시판을 리스트로 담아 팀 게시판 하나하나당 게시글의 개수를 더한 다음 또 팀 게시판 하나하나당 선수 게시판을 모두 찾아 선수 게시판 하나당 존재하는 게시글의 수를 더해야 하는 약간 귀찮은 작업을 해줘야 했다.

 

첫 번째로 리그 게시판에 존재하는 게시글의 개수를 구하기 위해 findAllByBoardId를 이용해 모든 게시글을 리스트에 담아 해당 리스트의 사이즈를 게시글의 총개수로 판단했다.

List<Post> eplBoardPosts =  postRepository.findAllByBoardId(boardId);

 

두 번째는 팀 게시판의 게시글 개수를 구해야 하는데 그러기 위해서는 팀 게시판을 구해야 했다. 
팀 게시판은 상위 게시판 즉 리그 게시판의 아이디로 찾아 리스트에 담아 리스트에 담긴 팀 게시판 하나하나당 게시글의 개수를 구했다.
팀 게시판부터는 게시판이 삭제가 되지 않은 게시판의 게시글의 개수만 구해야 했기 때문에 filter를 이용해 삭제가 되지 않은 상태의 게시판의 게시글의 개수만 카운트하도록 했다.
근데 지금 글을 쓰면서 생각해보니까 게시판이 삭제된 상태라면 해당 게시판 안에는 게시글이 존재하지 않기 때문에 굳이 해주지 않아도 됐을 것 같은데 그래도 확실히 filter로 걸러주면 좋으니까..

 

코드는 아래와 같다.

List<Board> teamBoards = boardRepository.findAllByParentId(boardId);

teamBoardPostsNumber.addAndGet(teamBoards.stream()
    .filter(eplTeamBoard -> !eplTeamBoard.isDeleted())
    .collect(Collectors.toList())
    .stream()
    .mapToInt(eplTeamBoard -> postRepository.findAllByBoardId(eplTeamBoard.id())
        .size()).sum());

근데 여기서 처음 보는 AtomicInteger라는 처음보는 클래스가 등장하는데 기존에는 그냥 게시글의 개수를 int형으로 선언해서 카운트해주고 있었는데 stream을 두 번 이상 쓰면서부터 intelliJ가 int형을 AtomicInteger 클래스로 바꾸라고 신호를 줬었다.

 

우선 AtomicInteger는 원자성을 보장하는 Integer를 의미한다고 한다. 원자성은 모두 실행되던지 모두 실행되지 않도록 하던지를 보장하는 특성이다.

내가 원자성을 이해할 때 한 번에 와닿던 예시는 은행 송금 예시이다. 예를 들어 A가 B에게 1000원을 송금해서 A의 계좌에서 1000원이 빠져나갔는데 송금 도중 문제가 생겨 B는 1000원을 받지 못하는 상황이 발상하면 안 되기 때문에 거래가 실패하면 A에게 1000원이 다시 입금이 되어 원상태로 돌아가야 한다. 즉 둘 중 하나의 거래만 이루어지면 안 된다.

아무튼 AtomicInteger는 원자성을 보장하는 Integer 클래스인데 IntelliJ가 AtomicInteger클래스로 변경하라고 하는 이유가 람다식을 쓰는 코드에서 동시성 문제가 발생한 건지 다른 문제 때문인 건지 아직 정확히 잘 모르겠다.

 

아무튼 지금까지 팀 게시판의 게시글의 개수까지 구했고 선수 게시판의 개시 글의 개수를 구해야 했는데 위 코드와 별 다를 게 없지만 forEach를 두 번 써야 하는 문제가 있었다.
왜냐 현재 팀 게시판도 리스트로 갖고 있고 팀 게시판 하나당 선수 게시판도 여러 개일 수 도 있으니 리스트 형태라서 forEach문을 이중으로 돌려야 했다. 

문제의 코드는 아래와 같다.

teamBoards.forEach(teamBoard -> {
    boardRepository.findAllByParentId(teamBoard.id())
        .stream()
        .filter(playerBoard -> !playerBoard.isDeleted())
        .forEach(playerBoard -> {
            playerBoardPostsNumber.addAndGet(postRepository.findAllByBoardId(playerBoard.id()).size());
        });
});

 

해당 작업을 리그 게시판이 4개가 존재했기 때문에 메서드로 추출해 4번을 반복해서 게시판의 게시글 개수를 구하는 아주 괴팍한 코드가 탄생했지만 현재로써는 최선이였다는...

이제 이 데이터를 이용하여 한눈에 보기 좋게 chart 라이브러리를 활용해서 게시판의 비중을 어드민 대시보드 페이지에 나타내 보자!