티스토리 뷰

spring에서 사용할 수 있는 paging 방식은 여러개가 있다. JPA를 사용한다면 Pageable를 사용하여 간단하게 paging을 할 수도 있지만 JPA는 필자는 많이 사용하고 있지 않고 대부분이 MyBatis를 사용하므로 그에 맞는 Paging 방식인 PageHelpler를 사용하는 방식에 대해 소개를 하도록 하겠다. PageHelpler는 중국인이 개발했는지 소스를 보면 중국말로 주석이 작성되어 있다. 이것빼고는 다 괜찮은것 같다. 


설정 및 구조

샘플은 springboot 2.1.1.RELEASE, java 1.8, h2database 기반으로 작성되었다. 

 

구조

pagehelper

PageHelper 샘플을 구현한 프로젝트젝의 구조이다. 일반적인 springboot + maven 프로젝트의 모습이다. 

 

pom.xml (dependency add)

<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>mybatis-spring-boot-starter</artifactId>
	<version>2.1.4</version>
</dependency>
<dependency>
	<groupId>com.github.pagehelper</groupId>
	<artifactId>pagehelper-spring-boot-starter</artifactId>
	<version>1.3.0</version>
</dependency>

<dependency>
	<groupId>com.h2database</groupId>
	<artifactId>h2</artifactId>
	<scope>runtime</scope>
</dependency>

일단 PageHelper를 사용하기 위해 dependency를 추가해주자. pagehelper-spring-boot-starter라는 녀석이 paging의 핵심이다. 그 외에 mybatis-spring-boot-starter와 DB는 h2database를 추가해주었다. 

 

data.sql (h2)

INSERT INTO `SAMPLE_EMPLOYEE` (`USER_ID`, `USER_NAME`, `USER_GENDER`, `DEPARTMENT_CODE`) VALUES
	(1, 'Kim', 'm', 'hr'),
	(2, 'Janny', 'f', 'dev'),
	(3, 'Billie Eilish', 'f', 'dev'),
	(4, 'Taylor Swift', 'm', 'sales'),
	(5, 'Jack', 'm', 'sales'),
	(6, 'Ken', 'm', 'dev'),
	(7, 'Jefrry', 'm', 'dev'),
	(8, 'Candle', 'm', 'dev'),
	(9, 'Bear', 'm', 'hr'),
	(10, 'Tom', 'm', 'dev'),
    
    .... more

h2database에는 대략 이런 모습의 데이터를 넣어두었다. 30개 조금 넘는 데이터를 넣어두었다. paging을 하기 위한 샘플데이터라고 보면 된다.

 

application.yml

pagehelper:
  helper-dialect: h2 
  auto-dialect: true
  page-size-zero: false
  reasonable: true
  offset-as-page-num: false
  row-bounds-with-count: false
  auto-runtime-dialect: false
  close-conn: true
  default-count: true

spring:
  datasource:
    hikari:
      driver-class-name: org.h2.Driver
      jdbc-url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
      username: sa
      password:
    initialization-mode: always
    schema: classpath:h2/schema.sql 
    data: classpath:h2/data.sql
  h2:
    console:
      enabled: true
      path: /h2-console

application.yml에서는 pagehelper에 대한 옵션을 설정할 수 있다. 옵션에 대한 값은 다음과 같다. 

property desc
pagehelper.helper-dialect DB 종류 선택 (설정 안하면 자동감지) 
oracle, mysql, mariadb, sqlite, hsqldb, postgresql, db2, sqlserver, informix, h2, sqlserver2012, derby 중 택1
pagehelper.auto-dialect DB 자동 설정 (default : false)
pagehelper.page-size-zero pageSize=0 으로 실행 (default : false)
pagehelper.reasonable true 일시 0 <= pageNum <= pages 로 실행 (default : false)
pagehelper.offset-as-page-num RowBound를 사용할 때 offset param을 pageNum으로 사용 (default : false)
pagehelper.row-bounds-with-count RowBound를 사용할 때 Count Query 수행 (default : false)
pagehelper.auto-runtime-dialect Runtime에 DB 자동 설정. auto-dialect 보다 우선 (default : false)
pagehelper.close-conn DB Connection을 닫을 지 여부 (default : true)
pagehelper.support-methods-arguments mapper 방식 사용시 true 설정 (default : false)
pagehelper.dialect Custom Dialect를 만들때 사용. Dialect를 implements 해서 만들어야 함. 
기본값은 com.github.pagehelper.PageHelper

참고 : https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/en/HowToUse.md#3-pagehelper-parameters

 

이렇게 해서 기본적인 설정은 다 끝났다. 


사용법

사용법은 일반적인 spring의 web flow에 따라 작성을 하였다.

Entity

@Data
public class EmployeeEntity {
    private String userId;
    private String userName;
    private String userGender;
    private String departmentCode;
}

샘플데이터를 담기 위한 Entity를 작성하였다. 

 

Controller

@RestController
@RequestMapping(value = "/employee")
public class EmployeeController {

    @Autowired
    private EmployeeService employeeService;

    @GetMapping("/pagesample")
    public PageInfo<EmployeeEntity> findPage(HttpServletRequest request) {
        PageHelper.startPage(request);
        return PageInfo.of(employeeService.findAll());
    }
}

일반적인 Spring Controller의 모습과 크게 다르지 않다. 

request에는 pageNum, pageSize가 담겨져 있어야 하며 이것을 기반으로 시작 페이지를 설정한다. 

Controller에서 주의깊게 봐야할 부분은 return type이다. PageInfo 라는 return type을 가지고 있는데 이것은 pagehelper-spring-boot-starter에 있는 클래스이다. PageInfo는 다음과 같은 필드를 가지고 있다. 

PageInfo.java

// 현재 페이지
private int pageNum ;
// 페이지당 수량
private int pageSize ;
// 현재 페이지 수
private int size ;
// 현재 페이지의 첫 번째 요소가 데이터베이스에 있는 줄 번호
private long startRow ;
// 현재 페이지의 마지막 요소가 데이터베이스에 있는 줄 번호
private long endRow ;
// 전체 페이지 수
private int pages ;
// 이전 페이지
private int prePage ;
// 다음 페이지
private int nextPage ;
// 첫 페이지인지 여부
private boolean isFirstPage = false ;
// 마지막 페이지인지 여부
private boolean isLastPage = false ;
// 이전 페이지가 있는지 여부
private boolean hasPreviousPage = false ;
// 다음 페이지가 있는지 여부
private boolean hasNextPage = false ;
// 내비게이션 페이지 번호
private int navigatePages ;
// 모든 내비게이션 페이지 번호
private int [ ] navigatepageNums ;
// 내비게이션 바의 첫 페이지
private int navigateFirstPage ;
// 내비게이션 바의 마지막 페이지
private int navigateLastPage ;

PageInfo는 이런 paging과 관련된 정보와 paging 처리가 된 데이터 list를 return 해준다. 

 

Service

@Service
public class EmployeeService {

    @Autowired
    private EmployeeMapper userMapper;

    public List<EmployeeEntity> findAll() {
        return userMapper.findAll();
    }
}

Service는 변경할 부분이 없다. Mapper 방식을 사용하기로 했으므로 Mapper를 주입받고 호출해준다. 

 

Mapper

public interface EmployeeMapper {
	
    @Select("SELECT * FROM SAMPLE_EMPLOYEE")
    @Results({
            @Result(property = "userId",  column = "user_id"),
            @Result(property = "userName", column = "user_name"),
            @Result(property = "userGender", column = "user_gender"),
            @Result(property = "departmentCode", column = "department_code")
    })
    List<EmployeeEntity> findAll();
}

Mapper에서 쿼리를 호출하고 결과값을 담는다. 마찬가지로 paging을 한다고 변경되어야 하는 부분은 없다

 

Controller 말고는 paging을 한다고 해서 변경이 이루어져야 할 부분은 없다! 이 점이 정말 좋은것 같다. 

코드 작성은 모두 끝났다. 


테스트 및 결과 확인

화면까지 만들 필요는 없을것 같아서 테스트는 그냥 작성한 url을 호출해보고 결과를 보는 방식으로 진행을 했다. 

pagehelper test

pageNum과 pageSize를 parameter로 전달해주고 이 값을 바꿔가면서 테스트를 해본다. 내가 주는 pageNum에 따라서 그리고 pageSize에 따라서 원하는 값이 정상적으로 출력되는것을 확인할 수 있다. 그 외의 paging data를 가지고 화면을 구성하여 paging의 구현을 마무리하면 된다. 

 

끝!

댓글
최근에 올라온 글
최근에 달린 댓글
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31