SpringBoot/Error

페이징 기능이슈

NellKiM 2025. 1. 7. 12:17

쿼리 수정전

<!--페이징을 위한 카운트 쿼리 수정전-->
    
    <select id="selectTotalProductCount" parameterType="map" resultType="int">
    SELECT COUNT(*) 
    FROM PRODUCT P
    LEFT JOIN
    CATEGORY C ON P.category_seq = C.category_seq
    WHERE 1=1
        <!-- 카테고리 필터 -->
        <if test="category_seq != 0">
            AND P.category_seq = #{category_seq}
        </if>
        
        <!-- 검색어 필터 -->
        <if test="query != null and query != ''">
    AND    (P.product_serial ILIKE '%' || #{query} || '%')
        OR (P.product_name ILIKE '%' || #{query} || '%')
        OR (P.product_brand ILIKE '%' || #{query} || '%')
        OR (P.product_height ILIKE '%' || #{query} || '%')
        OR (P.product_weight ILIKE '%' || #{query} || '%')
        OR (P.product_wh ILIKE '%' || #{query} || '%')
        OR (P.product_color ILIKE '%' || #{query} || '%')
        OR (P.product_features ILIKE '%' || #{query} || '%')
        OR (C.category_name ILIKE '%' || #{query} || '%')
        </if>
        
        <!-- 브랜드 필터 -->
        <if test="product_brand != null and product_brand != ''">
            AND P.product_brand = #{product_brand}
        </if>
        
        <!-- 가격대 필터 -->
        <if test="priceRange != null and priceRange != ''">
            AND (
                #{priceRange} LIKE '%below10k%' AND P.product_pay &lt; 10000
                OR #{priceRange} LIKE '%10kTo20k%' AND P.product_pay BETWEEN 10001 AND 20000
                OR #{priceRange} LIKE '%20kTo30k%' AND P.product_pay BETWEEN 20001 AND 30000
                OR #{priceRange} LIKE '%30kTo40k%' AND P.product_pay BETWEEN 30001 AND 40000
                OR #{priceRange} LIKE '%40kTo50k%' AND P.product_pay BETWEEN 40001 AND 50000
                OR #{priceRange} LIKE '%50kTo70k%' AND P.product_pay BETWEEN 50001 AND 70000
                OR #{priceRange} LIKE '%80kTo100k%' AND P.product_pay BETWEEN 80001 AND 100000
                OR #{priceRange} LIKE '%above100k%' AND P.product_pay > 100000
            )
        </if>
</select>

쿼리 수정후

 


<if test="query != null and query != ''">
    AND   (  (P.product_serial ILIKE '%' || #{query} || '%')
        OR (P.product_name ILIKE '%' || #{query} || '%')
        OR (P.product_brand ILIKE '%' || #{query} || '%')
        OR (P.product_height ILIKE '%' || #{query} || '%')
        OR (P.product_weight ILIKE '%' || #{query} || '%')
        OR (P.product_wh ILIKE '%' || #{query} || '%')
        OR (P.product_color ILIKE '%' || #{query} || '%')
        OR (P.product_features ILIKE '%' || #{query} || '%')
        OR (C.category_name ILIKE '%' || #{query} || '%')
)
</if>

    <!-- 가격대 필터 -->
    <if test="priceRange != null">
        AND (
            #{priceRange} LIKE '%below10k%' AND P.product_pay &lt; 10000
            OR #{priceRange} LIKE '%10kTo20k%' AND P.product_pay BETWEEN 10001 AND 20000
            OR #{priceRange} LIKE '%20kTo30k%' AND P.product_pay BETWEEN 20001 AND 30000
            OR #{priceRange} LIKE '%30kTo40k%' AND P.product_pay BETWEEN 30001 AND 40000
            OR #{priceRange} LIKE '%40kTo50k%' AND P.product_pay BETWEEN 40001 AND 50000
            OR #{priceRange} LIKE '%50kTo70k%' AND P.product_pay BETWEEN 50001 AND 70000
            OR #{priceRange} LIKE '%80kTo100k%' AND P.product_pay BETWEEN 80001 AND 100000
            OR #{priceRange} LIKE '%above100k%' AND P.product_pay > 100000
        )
    </if>
   
    <select id="selectTotalProductCount" parameterType="map" resultType="int">
 SELECT COUNT(*) 
    FROM PRODUCT P
    LEFT JOIN
    CATEGORY C ON P.category_seq = C.category_seq
    WHERE 1=1
        <!-- 카테고리 필터 -->
        <if test="category_seq != 0 and category_seq != null">
            AND P.category_seq = #{category_seq}
        </if>
        
        <!-- 검색어 필터 -->
        <if test="query != null and query != ''">
    AND  (  (P.product_serial ILIKE '%' || #{query} || '%')
        OR (P.product_name ILIKE '%' || #{query} || '%')
        OR (P.product_brand ILIKE '%' || #{query} || '%')
        OR (P.product_height ILIKE '%' || #{query} || '%')
        OR (P.product_weight ILIKE '%' || #{query} || '%')
        OR (P.product_wh ILIKE '%' || #{query} || '%')
        OR (P.product_color ILIKE '%' || #{query} || '%')
        OR (P.product_features ILIKE '%' || #{query} || '%')
        OR (C.category_name ILIKE '%' || #{query} || '%')
        )</if>
        
        <!-- 브랜드 필터 -->
        <if test="product_brand != null and product_brand != ''">
            AND P.product_brand = #{product_brand}
        </if>
        
       <!-- 가격대 필터 -->
    <if test="priceRange != null">
        AND (
            #{priceRange} LIKE '%below10k%' AND P.product_pay &lt; 10000
            OR #{priceRange} LIKE '%10kTo20k%' AND P.product_pay BETWEEN 10001 AND 20000
            OR #{priceRange} LIKE '%20kTo30k%' AND P.product_pay BETWEEN 20001 AND 30000
            OR #{priceRange} LIKE '%30kTo40k%' AND P.product_pay BETWEEN 30001 AND 40000
            OR #{priceRange} LIKE '%40kTo50k%' AND P.product_pay BETWEEN 40001 AND 50000
            OR #{priceRange} LIKE '%50kTo70k%' AND P.product_pay BETWEEN 50001 AND 70000
            OR #{priceRange} LIKE '%80kTo100k%' AND P.product_pay BETWEEN 80001 AND 100000
            OR #{priceRange} LIKE '%above100k%' AND P.product_pay > 100000
        )
    </if>
</select>
</mapper>

 

최초 기능 설계시 

검색기능과 필터/정렬 기능을 각각 분리하여 SQL 문을설계 진행 -> 기능을 구현후 테스트 진행시 결과조건은 동일하고 

category_seq 와 query(검색어) 유무에 따른 결과 분리 

 

 

  • currentPage:
    • 설명: param.page가 비어 있으면(예: 첫 진입 시), 기본값으로 1을 설정합니다.
    • 결과: 현재 페이지 번호.
      <c:set var="currentPage" value="${empty param.page ? 1 : param.page}" />
       
  • totalPages:
    • 설명: 전체 페이지 수를 totalPages 변수에 저장합니다. 서버에서 전달된 값을 사용.
       
      <c:set var="totalPages" value="${totalPages}" />

이전 버튼

<li class="page-item ${currentPage == 1 ? 'disabled' : ''}">
    <a class="page-link mx-1" href="javascript:void(0);" aria-label="Previous" data-page="${currentPage > 1 ? currentPage - 1 : 1}">
        <i class="feather-icon icon-chevron-left"></i>
    </a>
</li>
 
  • 클래스 계산:
    • currentPage == 1이면 "disabled" 클래스를 추가해 비활성화.
  • 데이터 속성 계산:
    • data-page: currentPage가 1보다 크면 currentPage - 1(이전 페이지)을 설정.
      그렇지 않으면 1을 유지.

페이지 번호 계산

<c:forEach var="i" begin="${currentPage - 2 > 1 ? currentPage - 2 : 1}" end="${currentPage + 2 < totalPages ? currentPage + 2 : totalPages}">
    <li class="page-item ${currentPage == i ? 'active' : ''}">
        <a class="page-link mx-1" href="javascript:void(0);" data-page="${i}">${i}</a>
    </li>
</c:forEach>
  • begin 시작 값:
    • 설명: 현재 페이지에서 왼쪽으로 최대 2개 표시.
      • 만약 (currentPage - 2)가 1보다 작으면 1로 시작.
        ${currentPage - 2 > 1 ? currentPage - 2 : 1}
  • end 종료 값:
    • 설명: 현재 페이지에서 오른쪽으로 최대 2개 표시.
      • 만약 (currentPage + 2)가 totalPages보다 크면 마지막 페이지(totalPages)를 표시
${currentPage + 2 < totalPages ? currentPage + 2 : totalPages}

 

  • 활성화 클래스:
    • 현재 페이지(currentPage)와 반복 변수(i)가 같으면 active 클래스를 추가해 시각적으로 강조
class="${currentPage == i ? 'active' : ''}"

 '...' 표시

<li class="page-item ${currentPage + 2 < totalPages ? '' : 'd-none'}">
    <a class="page-link mx-1" href="#">...</a>
</li>
 
  • currentPage + 2 < totalPages이면 ... 표시.
    (즉, 현재 페이지 기준으로 오른쪽 2칸 이후에 더 많은 페이지가 있을 때만 표시.)

마지막 페이지 버튼

<li class="page-item ${currentPage == totalPages ? 'disabled' : ''}">
    <a class="page-link mx-1" href="javascript:void(0);" aria-label="Next" data-page="${currentPage < totalPages ? currentPage + 1 : totalPages}">
        <i class="feather-icon icon-chevron-right"></i>
    </a>
</li>

 

  • 클래스 계산:
    • currentPage == totalPages이면 "disabled" 클래스를 추가해 비활성화.
  • 데이터 속성 계산:
    • data-page: currentPage가 totalPages보다 작으면 currentPage + 1(다음 페이지)을 설정.
      그렇지 않으면 마지막 페이지(totalPages)를 유지.