엄지월드

Spring paging 본문

java/Spring

Spring paging

킨글 2022. 8. 10. 18:03

Paging을 구성하는 데이터 흐름에 대해서 정리를 진행해보려고 한다.

먼저, 미리보는 흐름은 아래와 같다. 

  • list.html ->
  • memberParam.java ->
  • AdminMemberController.java ->
  • MemberService.java ->
  • MemberMapper.xml, PageUtil.java ->
  • list.html

 

그리고 각 파일마다 설명을 진행해보겠다. 

AdminMemberController.java

  • parameter.init() 을 통하여 매번 페이지 정보를 초기화 시켜준다.
  • List<MemberDto> members = memberService.list(parameter);을 통하여 members를 가져온다.
  • totalCount = members.get(0).getTotalCount(); totalCount를 현재 상황에 맞게 갱신해준다.
  • String queryString = parameter.getQueryString();를 통해 URL Parameter에 붙어 있는 Query 조건이 1개인지, 2개인지 확인해서 PageUtil에 전달해준다.
package com.myapp.lms.admin;

import com.myapp.lms.admin.dto.MemberDto;
import com.myapp.lms.admin.model.MemberParam;
import com.myapp.lms.member.entity.Member;
import com.myapp.lms.member.repository.MemberRepository;
import com.myapp.lms.member.service.MemberService;
import com.myapp.lms.util.PageUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.List;

@RequiredArgsConstructor
@Controller
public class AdminMemberController {
    private final MemberService memberService;

    @GetMapping("/admin/member/list.do")
    public String list(Model model, MemberParam parameter){
    	// 먼저 초기화 진행
        parameter.init(); 
		// member list 가져오기 
        List<MemberDto> members = memberService.list(parameter); 

		// totalCount 가져오기 
        long totalCount = 0;
        if(members != null && members.size() > 0){
            totalCount = members.get(0).getTotalCount();
        }
        
        // 페이징 처리 
        String queryString = parameter.getQueryString();		
        PageUtil pageUtil = new PageUtil(
                totalCount,
                parameter.getPageSize(),
                parameter.getPageIndex(),
                queryString
        );
        model.addAttribute("list", members);
        model.addAttribute("totalCount", totalCount);
        model.addAttribute("pager", pageUtil.paper());

        return "admin/member/list";
    }
}

MemberParam.java

  • parameter가 되는 정보들을 모아 놓는 곳. 
  • init()을 통해서 매번 초기화를 진행해준다.
  • getQueryString()을 통해서 URL Parameter에 있는 조건이 1개인지 2개인지 처리하여 String으로 반환해준다.
package com.myapp.lms.admin.model;

import lombok.Data;

@Data
public class MemberParam {
    long pageIndex;
    long pageSize;

    String searchType;
    String searchValue;

    /*
    limit 0, 10 --> pageIndex : 1
    limit 10, 10 --> pageIndex : 2
    limit 20, 30    --> pageIndex : 3
     */
    public long getPageStart(){
        init(); // 초기화
        return (pageIndex - 1) * pageSize;
    }

    public long getPageEnd(){
        init();
        return pageSize;
    }

    public void init(){
        if(pageIndex < 1){
            pageIndex = 1;
        }
        if(pageSize < 10){
            pageSize = 10;
        }
    }

    public String getQueryString() {
        init();
        StringBuilder sb = new StringBuilder();
        if(searchType != null && searchType.length() > 0){
            sb.append(String.format("searchType=%s", searchType));
        }

        if(searchValue != null && searchValue.length() > 0){
            if(sb.length() > 0){ // searchType이 있을 때 &로 묶어줌 
                sb.append("&");
            }
            sb.append(String.format("searchValue=%s", searchValue));
        }
        return sb.toString();
    }
}

MemberServiceImpl.java

  • xml에서 totalCount를 계속해서 구해준다. 
  • xml에서 list를 계속해서 구해준다. 
  • x.setSeq를 통해서 몇번째 Seq인지 구해준다. 
@Override
public List<MemberDto> list(MemberParam parameter) {
    long totalCount = memberMapper.selectListCount(parameter);
    List<MemberDto> list = memberMapper.selectList(parameter);
    if(!CollectionUtils.isEmpty(list)){ // empty가 아니면
        int i = 0;
        for(MemberDto x : list){
            x.setTotalCount(totalCount);
            x.setSeq(totalCount - parameter.getPageStart() - i); // seq 설정
            i++;
        }
    }
    return list;
}

MemberMapper.xml

  • Query들을 모아 놓은 xml이다.
  • <if test="searchType != null and searchValue != null">을 통해서 검색 조건에 맞게 Query를 꾸며준다.
  • 검색 시 totalCount도 사용되기 때문에 selectList 뿐만 아니라 selectListCount에서도 <if test="..."> 부분이 존재한다.
<?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="com.myapp.lms.admin.mapper.MemberMapper">
    <select id="selectListCount"
            parameterType="com.myapp.lms.admin.model.MemberParam"
            resultType="long">
        select count(*)
        from member
        where 1 = 1
            <if test="searchType != null and searchValue != null">
                <choose>
                    <when test="searchType == 'userId'">
                        and user_Id like concat('%', #{searchValue}, '%')
                    </when>
                    <when test="searchType == 'userName'">
                        and user_Name like concat('%', #{searchValue}, '%')
                    </when>
                    <when test="searchType == 'phone'">
                        and phone like concat('%', #{searchValue}, '%')
                    </when>
                    <otherwise>
                        and
                        (
                        user_Id like concat('%', #{searchValue}, '%')
                        or
                        user_Name like concat('%', #{searchValue}, '%')
                        or
                        phone like concat('%', #{searchValue}, '%')
                        )
                    </otherwise>
                </choose>
            </if>
    </select>

    <select id="selectList"
            parameterType="com.myapp.lms.admin.model.MemberParam"
            resultType="com.myapp.lms.admin.dto.MemberDto">
        select *
        from member
        where 1 = 1
            <if test="searchType != null and searchValue != null">
                <choose>
                    <when test="searchType == 'userId'">
                        and user_Id like concat('%', #{searchValue}, '%')
                    </when>
                    <when test="searchType == 'userName'">
                        and user_Name like concat('%', #{searchValue}, '%')
                    </when>
                    <when test="searchType == 'phone'">
                        and phone like concat('%', #{searchValue}, '%')
                    </when>
                    <otherwise>
                        and
                        (
                            user_Id like concat('%', #{searchValue}, '%')
                            or
                            user_Name like concat('%', #{searchValue}, '%')
                            or
                            phone like concat('%', #{searchValue}, '%')
                        )
                    </otherwise>
                </choose>
            </if>

        limit #{pageStart}, #{pageEnd}
    </select>

</mapper>

PageUtil.java

  • Paging을 구성하는 값들이 존재하는 곳.
  • Paper()를 통해서 실제 페이지에서 표시해줄 값들을 그려준다. 
package com.myapp.lms.util;


public class PageUtil {
    // 전체 개수
    private long totalCount;
    // 한 페이지에 나오는 개수
    private long pageSize = 10;
   // 페이지블럭 개수
    private long pageBlockSize = 10;
    // 현재 페이지 번호
    private long pageIndex;
    // 전체페이지 블럭 개수
    private long totalBlockCount;
    // 시작페이지
    private long startPage;
    // 종료 페이지
    private long endPage;
    // 페이지 이동 시 전달되는 파라미터(쿼리xmfld)
    private String queryString;

    public PageUtil(long totalCount, long pageSize, long pageIndex, String queryString){
        this.totalCount = totalCount;
        this.pageSize = pageSize;
        this.pageIndex = pageIndex;
        this.queryString = queryString;
    }
    public PageUtil(long totalCount, long pageIndex, String queryString, long pageSize, long pageBlockSize){
        this.totalCount = totalCount;
        this.pageIndex = pageIndex;
        this.queryString = queryString;
        this.pageSize = pageSize;
        this.pageBlockSize = pageBlockSize;
    }
    public String paper(){
        init();
        StringBuilder sb = new StringBuilder();
        long previousPageIndex = startPage > 1 ? startPage - 1 : 1;

        long nextPageIndex = endPage < totalBlockCount ? endPage + 1 : totalBlockCount;

        String addQueryString = "";
        if(queryString != null && queryString.length() > 0){
            addQueryString = "&" + queryString;
        }
        sb.append(String.format("<a href='?pageIndex=%d%s'>&lt;&lt;</a>", 1, addQueryString));
        sb.append(System.lineSeparator());

        for(long i = startPage; i<=endPage; i++){
            if(i == pageIndex)
                sb.append(String.format("<a class='on' href='?pageIndex=%d%s'>%d</a>", i, addQueryString, i));
            else
                sb.append(String.format("<a href='?pageIndex=%d%s'>%d</a>", i, addQueryString, i));
            sb.append(System.lineSeparator());
        }

        sb.append(String.format("<a href='?pageIndex=%d%s'>&gt;</a>", nextPageIndex, addQueryString));
        sb.append(System.lineSeparator());
        sb.append(String.format("<a href='?pageIndex=%d%s'>&gt;&gt;</a>", totalBlockCount, addQueryString));
        sb.append(System.lineSeparator());

        return sb.toString();
    }

    private void init(){
        if(pageIndex < 1){
            pageIndex = 1;
        }
        if(pageSize < 1){
            pageSize = 1;
        }
        totalBlockCount = totalCount / pageSize + (totalCount % pageSize > 0 ? 1 : 0);
        startPage = ((pageIndex - 1) / pageBlockSize) * pageBlockSize + 1;
        endPage = startPage + pageBlockSize - 1;
        
        if(endPage > totalBlockCount){
            endPage = totalBlockCount;
        }
    }
}
Comments