내일배움캠프 프로젝트

BuySell - 별점기능 구현

공부처음하는사람 2024. 3. 13. 20:12

내가 처음에 생각했던 별점기능은 진짜 별거없이 금방 끝낼것 같았는데

검색해보니 좀 복잡해보인다.

깊게 생각 안해서 일어난 일인듯...

내가 생각했던 방식은

  1. float으로 게시물에 대한(정확히 말하자면 판매자의 별점) 별점 등록하기 (애초에 이거부터가 글렀음)
  2. 값을 평균내서 판매자 별점에 반영하기

이거 였는데 지금 생각해보면 되겠나 싶다.

front에서 생각해보면 평점을 등록할 때 별 몇개를 준다거나 그런식으로 점수를 부여할텐데

단순히 소수점 한자리까지만 표현하자는 생각으로 float을 사용하게 됨

  1. 별점은 1에서 5까지 소수점이 없는 정수로 선택
  2. 그 값을 평균낼땐 float 형태가 되어야함
  3. member와 별점을 어떻게 연관지을지 생각도 해야하고..
@Schema(description = "리뷰를 작성할 때 입력한 정보를 전달하는 객체")
data class CreateReviewRequest(
    @field:Size(min = 1, max = 300, message = "내용은 1자 이상 300자 이하로 작성해주세요.")
    @field:NotBlank(message = "내용을 입력해주세요.")
    val content: String,

    @field:Min(value = 1, message = "별점은 1에서 5까지만 입력할 수 있습니다.")
    @field:Max(value = 5, message = "message = 별점은 1에서 5까지만 입력할 수 있습니다.")
    val rating: Int,
    val sellerRating: Int = rating
)

 

일단 @field를 사용해 별점에 대한 범위를 정했다.

평균을 내는 방법은 SQL함수 AVG를 사용해 리뷰가 업데이트 될 때마다 평균값을 업데이트 하는 방식으로 작성했다.

 

    @Query ("SELECT AVG(r.rating) FROM Review r WHERE r.member.id = :memberId")
    fun getAverageRatingByMember(memberId: Int): Double

 

 

이제 그 이후에 가장 중요한 문제인 서비스쪽인데..

    override fun createReview(
        postId: Int,
        request: CreateReviewRequest,
        principal: UserPrincipal
    ): MessageResponse {
        val post = postRepository.findByIdOrNull(postId)
            ?: throw ModelNotFoundException("Post", postId)
        val member = memberRepository.findByIdOrNull(principal.id)
            ?: throw ModelNotFoundException("Member", principal.id)

        val seller = post.member

        if (!post.isSoldOut) {
            throw IllegalStateException("판매되지 않은 물품에 리뷰를 작성할 수 없습니다.")
        }
        // order.memberId == review.memberId 일 경우에 작성가능한 메서드 추가

        post.myPostCheckPermission(principal)

        val sellerReview = Review.makeEntity(
            request = request.copy(sellerRating = request.rating),
            post = post,
            member = seller
        )
        reviewRepository.save(sellerReview)

        val averageRating = reviewRepository.getAverageRatingByMember(seller.id!!)
        seller.sellerRating = averageRating
        memberRepository.save(seller)

        return MessageResponse("리뷰가 작성되었습니다.")
    }

 

 

팩터링은 나중에 하고, 평균값을 조회할 수 있게 구현 먼저 해보려고 코드를 작성했는데.....

 

    이 코드에서 발생하는 문제, 아직 더 추가해야하는 문제

 

    - 일단 평점은 정상적으로 계산되어 업데이트 된다.... 다만

 

    1. review에 memberId가 seller의 id로 생성이 되어 userprincipal에 의해 리뷰 작성자가 수정 및 삭제를 할 수 없게된다.

    2. 한 판매글에 리뷰를 중복으로 작성할 수 없게 예외처리 추가해야한다.

    3. order.memberId와 review.memberId가 같아야 작성할 수 있다.

 

    리뷰가 seller id 작성되지 않고, 평점도 정상적으로 계산되게 방법이 없을까......