DevKim

[ Webtooniverse ] 웹툰 상세 페이지 개발 - 웹툰 별점 등록하기 본문

Spring Project/Webtooniverse

[ Webtooniverse ] 웹툰 상세 페이지 개발 - 웹툰 별점 등록하기

on_doing 2021. 8. 2. 13:34
728x90

[ 요구 사항 분석 ]

API Method request response
웹툰에 별점주기 클릭 PUT  /api/v1/reviews/star {
"webtoonId": 웹툰 id
"userPointNumber": 4.5
}
{
"reviewId": 리뷰 Id
}

[ 비즈니스 로직 ]

1. 유저가 해당 웹툰에 별점을 준적이 있는지 체크한다.
 - 해당 유저의 FK와 해당 웹툰 FK를 가진 리뷰의 존재 유무를 확인한다.

Webtoon findWebtoon = webtoonRepository.findById(reviewStarDto.getWebtoonId()).orElseThrow(
		() -> new IllegalArgumentException("해당 웹툰이 존재하지 않습니다")
);

Review findReview = reviewRepository.checkUserPointIsExist(findWebtoon, user);

 

2. 존재하지 않는다면 (별점을 누른적이 없다면)
  2-1. review 생성
  2-2. webtoon의 별점 개수 +1
  2-3. webtoon의 평균 별점 변경

if(findReview==null)
{
	Review review = Review.builder()
		.userPointNumber(reviewStarDto.getUserPointNumber())
		.build();

    //총 별점 개수 늘려주기
    findWebtoon.changeToonPointTotalNumber();

    //별점 평균 점수 변경
    findWebtoon.changeToonAvgPoint(reviewStarDto.getUserPointNumber());

    //웹툰,유저 정보 넣기
    review.insertWebToonAndUser(findWebtoon,user);

    reviewRepository.save(review);

}

별점이 처음 등록되는 경우,

총 별점은 ( 이전까지의 전체 평점 점수의 합+ 새로 등록된 별점 ) / 별점 개수 로 구할 수 있다.

/**
     * case : 별점을 처음 다는 유저
     * 평균 별점 점수 계산
     */
    public void changeToonAvgPoint(float userPoint) {
        float totalPoint = this.toonAvgPoint * (this.totalPointCount - 1) + userPoint;
        this.toonAvgPoint= (float) (Math.round(totalPoint/this.totalPointCount*100)/100.0);

    }


3. 이미 존재한다면 (별점을 누른적이 있다면)
  3-1. webtoon의 평균 별점 변경
  3-2. review
의 유저 별점 점수 변경

else
{
    //유저의 변경전 별점 점수
    float originalUserPoint =findReview.getUserPointNumber();

    //웹툰 평균 별점 점수 변경(원래 점수, 변경될 점수)
    findWebtoon.updateToonAvgPoint(originalUserPoint, reviewStarDto.getUserPointNumber());

    //유저의 별점 점수 변경
    findReview.changeUserPoint(reviewStarDto.getUserPointNumber());
}

별점을 수정하려는 유저에 대해서는,

별점의 개수는 변화가 없다.

/**
     * case : 별점 수정하려는 유저
     * - 별점 개수 변화 X
     * - 평균 별점 점수 변경
     */
    public void updateToonAvgPoint(float originalUserPoint,float userPoint)
    {
        float totalPoint = this.toonAvgPoint *(this.totalPointCount) - originalUserPoint +userPoint;
        this.toonAvgPoint =(float) (Math.round(totalPoint/this.totalPointCount*100)/100.0);
    }

[ 테스트 코드 ]

/**
     * 웹툰에 좋아요 누르기 테스트
     */
    @DisplayName("좋아요 처음 누르는 사용자의 경우")
    @Test
    public void clickWebtoonStar1() throws Exception{
        //given
        //임시 유저
        User user = User.builder()
                .userName("홍길동")
                .userEmail("abc@naver.com")
                .userImg(1)
                .userGrade(UserGrade.FIRST)
                .build();

        em.persist(user);
        em.flush();

        //웹툰 생성
        Webtoon w1 = createWebtoon("제목1", "작가1", "내용1",3.5F,25);
        em.persist(w1);
        em.flush();

        //별점 정보
        WebtoonPointRequestDto webtoonPointRequestDto= new WebtoonPointRequestDto(w1.getId(),3.0F);

        //when
        reviewService.clickWebtoonPointNumber(webtoonPointRequestDto,user);

        //then
        assertThat(w1.getToonAvgPoint()).isEqualTo(3.48F);
        assertThat(w1.getTotalPointCount()).isEqualTo(26);

        //when2 - 별점 수정하려는 사용자
        //별점 정보2
        WebtoonPointRequestDto webtoonPointRequestDto2= new WebtoonPointRequestDto(w1.getId(),2.0F);

        reviewService.clickWebtoonPointNumber(webtoonPointRequestDto2,user);

        assertThat(w1.getToonAvgPoint()).isEqualTo(3.44F);
        assertThat(w1.getTotalPointCount()).isEqualTo(26);
        
    }

[ Type issue ] - double/float VS. BigDecimal

테스트 코드의 결과값을 보면, 아래와 같이 정확하게 3.48이 나오지 않는 것을 확인할 수 있다.

그 이유는 내부적으로 수를 저장할 때, double과float는 이진수의 근사치를 저장하기 때문이다.

미세한 숫자의 변동도 허용하지 않는 돈과 소수점을 다룬다면 BigDecimal을 사용해야하지만,

BigDecimal은 비교적 속도가 느리다.

 

- 별점의 소수점 자체가 절대 틀리면 안되고 미세하게 다뤄야하는 것은 아니기에 ..

그냥 float형으로 가져가고 프론트 쪽에서 소수점을 떼고 화면에 보여주는 쪽으로 합의를 봤다.

728x90
Comments