1. JSP

<section class="studyCategory">
         <div class="studyCategory__container max-container">
            <div class="studyCategory__left">
               <p>카테고리</p>
               <div class="studyCategory__left__list">
					<a href="studyList.do?cp=1&sc_idx=0" class="cate ${param.sc_idx=='0'?'active':''}">전체</a>
					<a href="studyList.do?cp=1&sc_idx=1" class="cate ${param.sc_idx=='1'?'active':''}">코딩</a>
					<a href="studyList.do?cp=1&sc_idx=2" class="cate ${param.sc_idx=='2'?'active':''}">언어</a>
					<a href="studyList.do?cp=1&sc_idx=3" class="cate ${param.sc_idx=='3'?'active':''}">학업</a>
					<a href="studyList.do?cp=1&sc_idx=4" class="cate ${param.sc_idx=='4'?'active':''}">자격증</a>
					<a href="studyList.do?cp=1&sc_idx=5" class="cate ${param.sc_idx=='5'?'active':''}">취업</a>
               </div>
               <p>총 <span>${studyListCount}</span>개의 스터디</p>
            </div>
         </div>
      </section>
      <section class="studyGrid">
         <c:if test="${!empty requestScope.studyList}">
            <c:forEach var="dto" items="${requestScope.studyList}">
               <article class="studyCard">
                   <div class="studyCard__thumb">
                     <img src="/histudy/study-img/${!empty dto.study_upload_img ? dto.study_upload_img : 'groupStudy.png'}" alt="스터디 이미지">
                   </div>
                   <div class="studyCard__content">
                     <div class="studyCard__tags">
                        <span class="tag tag--language">${dto.sc_name}</span>
                     </div>
                        <h3 class="studyCard__title">${dto.study_title}</h3>
                     <div class="studyCard__rating">
                       <div class="stars">
                         ★★★★☆ <span style="color:black; font-weight:bold">4.9 (24)</span>
                       </div>
                    </div>
                        <ul class="studyCard__meta">
                          <li><img src="/histudy/main-img/user.png">${dto.user_name}</li>
                             <li><img src="/histudy/main-img/personnel.png">${dto.study_current_members }/${dto.study_max_members}명</li>
                          <li><img src="/histudy/main-img/clock.png">마감일 - ${dto.study_end_date.substring(0, 10)}</li>
                          <li><img src="/histudy/main-img/location.png">${empty dto.study_addr?'장소가 지정되지 않았어요':dto.study_addr }</li>
                       </ul>
                   </div>
                </article>
            </c:forEach>
         </c:if>
         <c:if test="${empty requestScope.studyList}">
            <div id="notStudy">
               <h2>개설된 스터디가 없습니다.</h2>
            </div>
         </c:if>
      </section>
      <div class="paging">
         ${pageStr}
      </div>

2. 컨트롤러

   @GetMapping("/studyList.do")
   public ModelAndView studyList(
		   @RequestParam(value="cp", defaultValue="1")int cp,
		   @RequestParam(value="sc_idx", defaultValue="0")Integer sc_idx) {
      
	   // int로 받을 경우에 없다면? 0이 들어옴
	   // Integer로 받는다면 ? 래퍼클래스이기 때문에 null 비교 가능
	   
      int listSize = 9;
      int pageSize = 5;
      int totalCnt = 0;
      String pagename = "studyList.do";
    
      
      int start_num = (cp-1)*listSize+1;
      int end_num = cp*listSize;
      
      Map<String, Integer> map = new HashMap<String, Integer>();
      map.put("start_num", start_num);
      map.put("end_num", end_num);
      if(sc_idx == 0) {
    	  sc_idx = null;
    	  totalCnt = ss.studyTotalCnt(sc_idx);
      }else {
    	  totalCnt = ss.studyTotalCnt(sc_idx);
      }
      map.put("sc_idx", sc_idx);
      
      String pageStr = com.histudy.page.PagingModule.makePage(cp, listSize, pageSize, totalCnt, pagename, sc_idx);

      List<StudyDTO> lists = ss.getStudyList(map);
      
      ModelAndView mav = new ModelAndView();
      mav.addObject("studyList", lists);
      mav.addObject("studyListCount", lists.size());
      mav.addObject("pageStr", pageStr);
      mav.setViewName("study/studyList");
      return mav;
   }

3. studySQL.xml

   <select id="selectStudyList" parameterType="map" resultType="com.histudy.study.model.StudyDTO">
      SELECT * 
            FROM
                (SELECT rownum as rnum, a.*
               FROM 
                 (
                  SELECT study.*, usertb.user_name, study_category.sc_name
                  FROM study JOIN usertb ON study.user_idx=usertb.user_idx JOIN study_category ON study_category.sc_idx = study.sc_idx
                  <if test="sc_idx != null">
                  	WHERE study_category.sc_idx=#{sc_idx} 
                  </if>
                  ORDER BY study_idx desc
                 ) a ) b
      WHERE rnum between #{start_num} and #{end_num}
   </select>
   <select id="studyTotalCnt" parameterType="Integer" resultType="Integer">
      SELECT count(*)
      FROM study
      <if test="sc_idx != null">
      		WHERE sc_idx=#{sc_idx}
      </if>
   </select>

총 데이터 수 구하는 쿼리

<select id="studyTotalCnt" parameterType="Integer" resultType="Integer">
    SELECT count(*)
    FROM study
    <if test="sc_idx != null">
      WHERE sc_idx=#{sc_idx}
    </if>
</select>

개발 의도

처음에는 기본적인 페이징 모듈과 sql 쿼리를 이용해서 구현을 했다. 사용자가 보는 화면에 필요한 요소들은 테이블 JOIN문을 통해 가져왔다.

그 이후 사용자가 카테고리를 클릭 했을 때 해당 카테고리만 조회해야 했다.

JSP에서 사용자가 카테고리를 클릭하면 나는 <a> 태그를 이용해 파라미터로 sc_idx (카테고리 번호)를 넘겨줬다.

이때도 처음에는 sc_idx를 int 타입으로 받았는데 생각을 해보니.. MyBatis 쿼리를 활용 할 수 있으니 null 처리를 할 수 있게 Integer 타입으로 변경 했다.

@RequestParam을 이용해서 sc_idx값을 받는데 만약 값이 안 넘어왔을 때 defaultValue=”0”으로 세팅 해줬다.

만약 사용자가 카테고리를 클릭 했다면 sc_idx는 0이 아닐 것이고, 스터디 리스트 페이지에 처음 접속 했거나 카테고리를 클릭 하지 않았다면 sc_idx는 0이 될 것이다.

이 때 만약 sc_idx가 0이라면 sc_idx 에 null을 대입했다. 이유는..?

우선, 사용자가 카테고리를 선택하면 그거에 맞는 페이징이 되어야 되는데 SQL 쿼리를 두 개 만드는 것 보다 하나의 SQL에서 두 가지의 동작을 할 수 있게 MyBatis 활용을 해야겠다고 생각했다.

즉, sc_idx가 null 이라면 테이블에 있는 총 데이터 수를 가져오게 만들고,

null이 아니라면 WHERE sc_idx = #{sc_idx} 이 조건절을 추가하여 해당 카테고리의 총 데이터 수를 가져오게 만들었다.

이렇게 하면 상황에 맞는 페이징이 정상적으로 이루어진다.