개주 훈련일지/🏋️ 전집중 호흡 훈련

별점 리뷰 기능 구현하기 (플러그인 활용)

lshfood2 2025. 11. 29. 23:21

오늘은 JSP와 jQuery로

별점 리뷰 기능을 구현해 보았다.

 

클릭 가능한 별점(Star Rating) UI를 만들고,

리뷰 작성 시 별점과 내용이 함께 저장되며,

리스트에서 다시 별점이 표시되도록 설계했다.


1. 전체 기능 개요

구현한 기능은 다음과 같다.

  • 클릭하면 별이 채워지는 별점 UI
  • 별점을 선택하지 않으면 기본값 5점 자동 입력
  • 리뷰 작성 폼과 연결되어 star_point 값이 서버로 전달
  • DB에서 가져온 리뷰 리스트에 별점 이미지로 출력
  • 리뷰 수정 시 리뷰 내용만 변경 (별점 변경 불가)

2. 별점 UI HTML 구조

별점은 span.star 다섯 개로 이루어진다.

<div class="star_rating">
    <span class="star"></span>
    <span class="star"></span>
    <span class="star"></span>
    <span class="star"></span>
    <span class="star"></span>
</div>

리뷰 작성 시 별점을 선택하면

JS가 숨겨진 <input type="hidden">을

자동 생성해 서버로 점수를 넘길 예정이다.


3. jQuery로 별 선택 구현

별을 클릭하면 해당 별+이전 별까지

모두 .on 클래스를 적용해

채워진 이미지로 바꾼다.

 

단 별점을 선택하지 않을 경우

기본값으로 5점이 되도록 설정하였다.

(maxStars=5)

 

또한 별은 icon일 뿐 실제 값이 아니므로,

별에 값을 대입할 수 있는 input type=hidden을

별 클릭 시 생성해 주고, score 값을 대입시킨다.

 

이러한 과정을 통해 별점을 DB에 넘길 수 있게 된다.

// ★ 페이지가 로드되면 실행
$(function() {
    const maxStars = 5;  // 최대로 표시할 별 개수
    // ⭐ 초기 세팅: 별점 전체 비우기
    $('.star_rating .star').removeClass('on');
    // ⭐ 기본값을 5점으로 설정 (모든 별 활성화)
    $('.star_rating .star:lt(' + maxStars + ')').addClass('on');
    
    // ⭐ 별 클릭 이벤트
    $('.star_rating > .star').click(function() {
        const index = $(this).index(); 
        // 클릭한 요소의 0~4 인덱스

        const score = index + 1;  
        // 별점은 1~5이므로 +1

        // 1) 모든 별 비활성화
        $(this).parent().children('span').removeClass('on');

        // 2) 클릭한 별 + 이전 모든 별 채우기
        $(this).addClass('on').prevAll('span').addClass('on');

        // ⭐ hidden input 생성 또는 업데이트
        // 별점을 서버에 전달하려면 form 안에 input이 반드시 있어야 함.
        // <input type="hidden" id="star_point"> 이걸 매번 새로 만들 필요 없이
        // 1번만 만들고 .val()로 값만 바꿔도 됨.
        //id가 star_point인 요소가 존재하는지 체크
        if ($('#star_point').length === 0) {

	// 없으면 히든 인풋 추가
            // attr()는 해당 태그에 여러 속성을 객체 형태로 넣을 수 있는 메서드
            // type, id, name, value 값을 한 번에 추가 가능
            $('<input>').attr({
                type: 'hidden',
                id: 'star_point',
                name: 'star_point',
                value: score   // 선택한 별점
            }).appendTo('#reviewForm');

        } else {
            $('#star_point').val(score); // 이미 있으면 값만 변경
        }
    });

    // 폼 제출 시 별점을 선택하지 않았을 경우 기본값 5점 부여
    $('#reviewForm').submit(function() {
        if ($('#star_point').length === 0) {
            $('<input>').attr({
                type: 'hidden',
                id: 'star_point',
                name: 'star_point',
                value: maxStars
            }).appendTo('#reviewForm');
        }
    });
});

4. 리뷰 작성 폼

리뷰 작성 시 form타입 안에 있는 히든타입과

JS에 있는 히든타입(별점)이 함께 넘어간다.

 

즉 bid, writer, content, star_point

4가지 컬럼이 서버로 전달된다.

<!-- ⭐ 리뷰 작성 폼 -->
<c:if test="${not empty userInfo}">
<form id="reviewForm" action="reply.do" method="POST">
    <input type="hidden" name="bid" value="${board.bid}">
    <input type="hidden" name="writer" value="${userInfo}">

    <!-- ⭐ 별점 선택 UI -->
    <div class="star_rating">
        <span class="star"></span>
        <span class="star"></span>
        <span class="star"></span>
        <span class="star"></span>
        <span class="star"></span>
    </div>

    <textarea class="star_box" name="content" placeholder="별점을 선택하지 않으면 5점으로 자동 등록됩니다."></textarea>
    <input type="submit" class="replywrite_btn" value="리뷰 등록">
</form>
</c:if>

<c:if test="${empty userInfo}">
    <input type="text" value="리뷰를 작성하려면 로그인이 필요합니다." disabled size="35">
</c:if>

5. CSS로 별 이미지 스타일 지정

별점과 관련된 디자인 영역

즉 CSS 부분은 플러그인을 사용했다.

 

이미 완성되어 올라온 별점 플러그인 중

CSS만 가져와 사용했으며, 내 코드에 맞게

매핑되는 부분의 클래스 네임만 통일하였다.

 

1. star_rating
: 별점을 묶는 최상위 컨테이너

2. star_rating .star

: 기본 상태로 비활성화된 별 아이콘

3. star_rating .star.on

: 클릭을 통해 활성화된 별 아이콘

4. star_box

: 리뷰 텍스트가 입력되는 텍스트 박스

5. replywrite_btn
: 리뷰 등록하기 버튼

6. star_icon
: 사용자 닉네임 옆에 표기될 별점 데이터

 

/* ⭐ 별점 컨테이너 */
.star_rating {
  width: 100%;
  box-sizing: border-box;
  display: inline-flex;
  float: left;
  flex-direction: row;
  justify-content: flex-start;
}

/* ⭐ 기본 비활성 별 (빈 별 이미지) */
.star_rating .star {
  width: 25px;
  height: 25px;
  margin-right: 10px;
  display: inline-block;
  background: url('../images/star_empty.png') no-repeat;
  background-size: 100%;
  box-sizing: border-box;
}

/* ⭐ 클릭 시 활성화된 별 (채워진 이미지) */
.star_rating .star.on {
  background: url('../images/star_fill.png') no-repeat;
  background-size: 100%;
}

/* ⭐ 리뷰 내용 입력 박스 */
.star_box {
  width: 400px;
  box-sizing: border-box;
  display: inline-block;
  margin: 15px 0;
  background: #F3F4F8;
  border: 0;
  border-radius: 10px;
  height: 100px;
  resize: none;
  padding: 15px;
  font-size: 13px;
  font-family: sans-serif;
}

/* ⭐ 리뷰 등록 버튼 */
.replywrite_btn {
  display: block;
  width: 400px;
  font-weight: bold;
  border: 0;
  border-radius: 10px;
  max-height: 50px;
  padding: 15px 0;
  font-size: 1.1em;
  text-align: center;
  background: bisque;
}

/* ⭐ 리뷰 목록에서 별 아이콘 출력용 */
.star_icon {
  width: 18px;
  height: 18px;
  vertical-align: middle;
}

6. 저장된 리뷰 별점 출력하기 (JSTL)

DB에서 조회한 ReplyDTO의

starPoint 값을 기반으로 별아이콘을 출력한다.

 

별점 3점이면 ★ ★ ★ ☆ ☆

이런 식으로 표시하기 위해
JSTL 반복문을 아래처럼 2개 사용한다:

 

▼ 채워진 별(점수만큼)

<!-- 채워진 별 표시 -->
<c:forEach var="i" begin="1" end="${data.starPoint}">
    <!-- data.starPoint만큼 반복하면서 별을 채움 -->
    <!-- 예: 별점이 3점이면 i=1,2,3 반복 → ★★★ -->
    <img src="images/star_fill.png" class="star_icon">
    <!-- 채워진 별 이미지를 표시, class=star_icon으로 CSS 스타일 적용 -->
</c:forEach>

 

▼ 빈 별(5 - 점수만큼)

<!-- 빈 별 표시 -->
<c:forEach var="i" begin="1" end="${5 - data.starPoint}">
    <!-- 전체 별 5개 중에서 남은 별만큼 반복 -->
    <!-- 예: 별점 3점이면 5-3=2 → 2개의 빈 별 표시 → ☆☆ -->
    <img src="images/star_empty.png" class="star_icon">
    <!-- 빈 별 이미지를 표시, 채워진 별과 동일하게 CSS 적용 -->
</c:forEach>

이렇게 하면 별점 개수만큼

자동으로 UI가 구성된다.


7. 리뷰 수정 기능

수정 시에는 별점 변경이 불가능하도록

텍스트 내용만 input으로 변환한다.

// 리뷰 수정 - 별점은 바꿀 수 없고 텍스트만 수정
function edit(rid,bid){
    let elem = document.getElementById('reply_'+rid);
    let apple = elem.innerText;
    apple = apple.replace(" 댓글변경 댓글삭제","");

    // 수정 폼 HTML을 문자열로 구성
    let txt = '<form action="updateReply.do" method="POST">';
    txt += '<input type="hidden" name="bid" value="'+bid+'">';
    txt += '<input type="hidden" name="rid" value="'+rid+'">';
    txt += '<input type="text" name="content" required value="'+apple+'">';
    txt += '<input type="submit" value="댓글변경">';
    txt += '</form>';

    elem.innerHTML = txt;
}

8. 전체 흐름 요약

1. 사용자가 별 클릭 → hidden input에 점수 저장
2. 폼 제출 시 star_point 값 전달
3. ReplyAction에서 DTO로 데이터 저장
4. ReplyDAO → DB insert(replyDTO)
5. 다시 boardPage.do 이동
6. JSP에서 별점 숫자만큼 채워진 별 반복 출력

위와 같이 V에서 별점 기능이 구현되면

UI 변화뿐만 아니라 실제 유저의 입력값을

서버로 전달하게 되고 서버는 이를 저장한 후

다시 V에게 전달하여 변화된 데이터를 보여준다.