프로그래밍/- 남굼성의 Spring 교육

spring 페이징, SQL_CALC_FOUND_ROWS

즐겁게 하하하 2022. 2. 10. 00:20
728x90

 

페이징을 하기 전에 부트스트랩의 pagination 을 들어가서 css 를 적용한다.

https://getbootstrap.kr/docs/5.1/components/pagination/#%ED%81%AC%EA%B8%B0-%EC%A1%B0%EC%A0%88

 

페이지네이션

여러 페이지에 일련의 관련 내용이 있음을 나타내는 페이지네이션을 사용한 문서와 예시입니다.

getbootstrap.kr

 

 

준비가 끝나면 페이징을 구현한다.

아래 사진은 작업한 파일 경로들을 캡쳐해 놓았다.

 

UserDTO

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@EqualsAndHashCode
public class UserDTO {
    private String user_no;
    private String user_id;
    private String user_pw;
    private String user_nm;
    private String user_tel;
    private String user_salt;
    private String user_email;
    private String user_isshow;
    private int fail_count;
    private Date modify_pw;
    private Date req_dt;
    private String command;
}

 

Criteria

package com.house.handler.paging;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.web.util.UriComponentsBuilder;

@Getter
@Setter
@ToString
public class Criteria { // 페이징에 필요한 클래스

    private int pageNum; // 페이지

    private int amount; // 한번에 보여줄 게시물 수

    private String type; // 검색종류

    private String keyword; // 검색어

    public Criteria() { this(1, 10); }

    public Criteria(int pageNum, int amount) {
        this.pageNum = pageNum;
        this.amount = amount;
    }

    public String[] getTypeArr() {
        return type == null ? new String[] {} : type.split("");
    }

    public String getListLink() {
        UriComponentsBuilder builder = UriComponentsBuilder.fromPath("")
                .queryParam("pageNum", this.pageNum)
                .queryParam("amount", this.amount)
                .queryParam("type", this.type)
                .queryParam("keyword", this.keyword);
        return builder.toUriString();

    }
}

 

 

PageMaker

package com.house.handler.paging;

import lombok.Getter;
import lombok.ToString;

@Getter
@ToString
public class PageMaker {

    // 보고있는 페이지에서 시작번호  ( 예) 10개씩이라고하면 1 , 11 , 21 , 31 ..... )
    private int startPage;

    // 보고있는 페이지에서 끝번호 ( 예) 10개씩이라고하면 10, 20, 30 ,40 ,50 .....)
    private int endPage;        // 이번페이지가 있는지 다음페이지가 있는지 확인
    private boolean prev,next;
    private int lastPage;       // 전체 게시글 수
    private int total;          // 요청이 온 페이지의 페이지번호와 몇개씩 보고 싶은지
    private Criteria cri;

    public PageMaker(Criteria cri, int total) {
        this.cri = cri; // 요청 정보
        this.total = total; // 전체 게시글 수
        this.endPage = (int) (Math.ceil(cri.getPageNum() / 10.0))*10;
        this.startPage = this.endPage - 9;
        int realEnd = (int) (Math.ceil((total*1.0)/cri.getAmount()));
        lastPage = realEnd;
        if(realEnd < this.endPage) {
            this.endPage = realEnd;
        }

        this.prev = this.startPage > 1;
        this.next = this.endPage < realEnd;
    }
}

 

Controller

@Controller
public class BasicController extends AdminController{

    @Autowired
    private UserService userService;

    /** 환경설정 - 권한관리 List page 이동 */
    @GetMapping("/basic/auth")
    public ModelAndView userManagementPage(HttpSession session , Criteria cri , HttpServletRequest request) throws Exception{

        //검색 param
        UserDTO userDTO = new UserDTO();
        userDTO.setUser_id(request.getParameter("search_id"));
        userDTO.setUser_nm(request.getParameter("search_nm"));

        //메뉴 및 권한 loading
        String user_id = (String)session.getAttribute("user_id");
        Map<String, List<MenuDTO>> menu = gnbList(user_id);

        //사용자 list loading
        Map<String,Object> map = userService.listUser(cri , userDTO);
        PageMaker pageMaker = new PageMaker(cri,(Integer)map.get("total_count"));

        ModelAndView mv = new ModelAndView();
        mv.addObject("setMenu",menu);
        mv.addObject("totalCount",map.get("total_count"));
        mv.addObject("listUser",map.get("listUser"));
        mv.addObject("pageMaker",pageMaker);
        mv.setViewName("basic/auth");
        return mv;
    }

}

 

 

Service

public interface UserService {
 
       Map<String,Object> listUser(Criteria criteria , UserDTO userDTO);
 
}

 

ServiceImpl

@Service("UserService")
public class UserServiceImpl implements UserService{

    @Autowired
    private UserDAO userDAO;  
    
    public Map<String,Object> listUser(Criteria criteria , UserDTO userDTO) { return userDAO.listUser(criteria , userDTO); }    // 사용자 리스트    
}

 

UserDAO

SQL_CALC_FOUND_ROWS , FOUND_ROWS() 를 사용하기 위해서 트랜젝션을 오픈한다.

@Repository
public class UserDAO extends SqlSessionDaoSupport {

    @Autowired
    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        super.setSqlSessionFactory(sqlSessionFactory);
    }

      //사용자 리스트
    public Map<String,Object> listUser(Criteria criteria , UserDTO userDTO){

        int pageNum = criteria.getPageNum();
        int amount = criteria.getAmount();
        if(pageNum < 0) pageNum = 1;
        int startNum = (pageNum-1) * amount;

        SqlSession session = getSqlSessionFactory().openSession();
        Map<String,Object> map2 = new LinkedHashMap<>();
        try{
            HashMap<String,Object> map = new HashMap();
            map.put("startNum",startNum);
            map.put("endNum",amount);
            map.put("userDTO",userDTO);

            List<UserDTO> listUser = session.selectList("listUser" , map);
            int total_count = session.selectOne("queryRowCount");
            map2.put("listUser",listUser);
            map2.put("total_count",total_count);
        }finally {
            session.close();
        }
        return map2;
    }
}

 

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <typeAliases>
        <typeAlias type="com.house.handler.dto.UserDTO" alias="userConfig"  />  
    </typeAliases>
</configuration>

 

 

user-mapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="userConfig">

    <select id="queryRowCount" resultType="int" >
        SELECT FOUND_ROWS() AS total_cnt
    </select>


    <select id="listUser" parameterType="hashmap" resultType="userConfig">
        select
            SQL_CALC_FOUND_ROWS
            *
        from
        (
            select
                @rownum:=@rownum+1 as num
                 , mc.*
            from user mc
               ,(SELECT @rownum:=0) r
            where  <![CDATA[ mc.user_no > 0 ]]>

            <if test="userDTO.user_id != null" >
                and mc.user_id LIKE CONCAT('%', #{userDTO.user_id}, '%')
            </if>
            <if test="userDTO.user_nm != null" >
                and mc.user_nm LIKE CONCAT('%', #{userDTO.user_nm}, '%')
            </if>

            order by mc.user_no desc
        )ee
        order by num desc
        LIMIT  #{startNum} , #{endNum}
    </select>

</mapper>

 

 

jsp

<form name="requestForm" id="requestForm" method="post">
    <input type="hidden" name="checkList" id="checkList" value="">
    <div class="row justify-content-between col-xl-12 col-md-12 col-sm-12 mb-2">
        <div class="px-3">
            <span id="searchDetailLabel" data-toggle="dropdown" class="btn btn-sm btn-outline-primary dropdown-toggle"><i class="fas fa-search"></i></span>
            <div class="dropdown-menu px-2 container-fluid" aria-labelledby="searchDetailLabel" style="width:50%">
                <div class="form-row mb-2 ml-2">
                    <div class="col-sm-12">
                        <div class="input-group input-group-lg pt-1">
                            <div class="input-group-prepend"><span class="input-group-text">이&nbsp;&nbsp;&nbsp;름</span></div>
                            <input type="text" name="search_nm" id="search_nm" value="" class="form-control" aria-label="이름" aria-describedby="이름">
                        </div>
                        <div class="input-group input-group-lg pt-1">
                            <div class="input-group-prepend"><span class="input-group-text">아이디</span></div>
                            <input type="text" name="search_id" id="search_id" value="" class="form-control" aria-label="아이디" aria-describedby="아이디">
                        </div>
                    </div>
                </div>
                <a type="button" class="btn btn-sm btn-outline-primary btn-block active" onclick="searchDetail();" aria-label="검색"> 검색 </a>
            </div>
        </div>
        <button type="button" class="btn btn-sm btn-outline-danger" onclick="btnDeleteCheckBox()">선택한 사용자 탈퇴</button>
    </div>
    <table class="table table-sm  table-bordered table-hover" id="employeeTable">
        <colgroup>
            <col width="5%">
            <col width="15%">
            <col width="20%">
            <col width="20%">
            <col width="20%">
            <col width="20%">
        </colgroup>
        <thead class="thead-light">
        <tr>
            <th scope="col" class="text-center">
                <input type="checkbox" id="allCheck" name="allCheck" />
            </th>
            <th scope="col" class="text-center">이름 (ID)</th>
            <th scope="col" class="text-center">이메일</th>
            <th scope="col" class="text-center">연락처</th>
            <th scope="col" class="text-center">암호 변경일</th>
            <th scope="col" class="text-center">권한설정</th>
        </tr>
        </thead>
        <tbody>
        <c:if test="${totalCount gt 0 }">
            <c:forEach items="${listUser}" var="user" >
                <tr class="text-align bg-white" style="cursor:pointer">
                    <td class="text-center">
                        <input type="checkbox" id="chk_it_no" name="chk_it_no" value="${user.getUser_no()}" />
                    </td>
                    <td class="rowTr">
                        ${user.getUser_nm()}
                        <span style="color: cadetblue"> ( ${user.getUser_id()} ) </span>
                    </td>
                    <td class="rowTr">
                        ${user.getUser_email()}
                    </td>
                    <td class="rowTr">
                        ${user.getUser_tel()}
                    </td>
                    <td class="rowTr">

                        <fmt:formatDate value='${user.getModify_pw()}' pattern='yyyy-MM-dd' var="modiDate"/>
                        <fmt:parseDate value="${modiDate}" var="modiDate2" pattern="yyyy-MM-dd"/>
                        <fmt:parseNumber value="${modiDate2.time / (1000*60*60*24)}" integerOnly="true" var="modiDate3"/>

                        <jsp:useBean id="today" class="java.util.Date" />
                        <fmt:formatDate value='${today}' pattern='yyyy-MM-dd' var="nowDate"/>
                        <fmt:parseDate value="${nowDate}" var="nowDate2" pattern="yyyy-MM-dd"/>
                        <fmt:parseNumber value="${nowDate2.time / (1000*60*60*24)}" integerOnly="true" var="nowDate3"/>
                        <c:set var="check_pw" value="${nowDate3 - modiDate3}" />

                        ${modiDate}
                        <c:if test="${check_pw gt 30}" >
                            <span class="ml-3" style="font-family: 'AmeriGarmnd BT';color:brown"><b>30일 초과</b></span>
                        </c:if>
                    </td>
                    <td class="">
                        <button type="button" class="btn btn-sm btn-outline-info btnGrant">권한설정</button>
                        <button type="button" class="btn btn-sm btn-outline-danger btnPwClear">접속 실패 ${user.getFail_count()} 회</button>
                    </td>
                </tr>
            </c:forEach>
        </c:if>
        <c:if test="${totalCount eq 0 }">
            <tr class="center">
                <td scope='row' colspan='10'>검색 결과가 없습니다.</td>
            </tr>
        </c:if>
        </tbody>
    </table>
    
    // 페이징 ==========================================
    <ul class="pagination">
        <c:if test="${pageMaker.prev }">
            <li class="page-item"><a class="page-link" href="<c:url value="/basic/auth?pageNum=1"/>">맨앞</a></li>
        </c:if>
        <c:if test="${pageMaker.prev }">
            <li class="page-item">
                <a class="page-link" href="<c:url value="/basic/auth?pageNum=${pageMaker.cri.pageNum-1}"/>">이전</a>
            </li>
        </c:if>
        <c:forEach var="num" begin="${pageMaker.startPage }" end="${pageMaker.endPage }">
            <li class="page-item ${pageMaker.cri.pageNum == num? "active":"" }">
                <a class="page-link" href=" <c:url value="/basic/auth?pageNum=${num}"/>">${num}</a>
            </li>
        </c:forEach>
        <c:if test="${pageMaker.next }">
            <li class="page-item"><a class="page-link" href="<c:url value="/basic/auth?pageNum=${pageMaker.cri.pageNum+1}"/>">다음</a></li>
        </c:if>
        <c:if test="${pageMaker.next }">
            <li class="page-item"><a class="page-link" href="<c:url value="/basic/auth?pageNum=${pageMaker.lastPage}"/>">맨끝</a></li>
        </c:if>
    </ul>
</form>
728x90