TDD / Mybatis - 게시판 paging
paging
- paginInfo 파일 추가
- @param currentPage 현재 페이지
- @param pageLimit 보여지는 paing의 개수
- < 1 2 3 4 5 > : 여기서는 5개
- @param listCount 전체 게시글의 개수
- @param listLimit 한 페이지에 표시될 게시글의 개수
- paging 처리를 위해 전체 게시글 개수부터 가져오기
servlet/JSP 수업 때 사용했던 파일을 그대로 사용했다.
test 코드 작성
- 필터 기능을 통해 조회되는 게시글만 조회
- listCount(전체 게시글의 개수)를 필터가 적용된 수로 가져오기.ㅠㅠ
- getBoardCount() 메서드를 필터링 된 것으로 가져오기.
@Test
public void getBoardCountTest() {
int count = 0;
// 필터 사용
String[] filters = new String[] {"B2", "B3"};
// 필터 넘겨주기
count = service.getBoardCount(filters);
assertThat(count).isGreaterThan(0);
}
service 코드 작성
public int getBoardCount(String[] filters) {
int count = 0;
SqlSession session = getSession();
// Arrays.asList(filters) : List로 넘기기
count = dao.findBoardCount(session, Arrays.asList(filters));
session.close();
return count;
}
dao 코드 작성
// List<String> : 리스트로 넘겨기
public int findBoardCount(SqlSession session, List<String> filters) {
// 총 게시글의 개수를 조회하기 때문에 selectOne() 사용
return session.selectOne("boardMapper.getBoardCountByFilters", filters);
}
service / dao에서 list로 넘겼기 때문에 쿼리문에서도 list로 작성해야한다!
쿼리문 작성
<select id="getBoardCountByFilters" parameterType="map" resultType="_int">
<!-- sql 조각은 모든 컬럼을 조회하기 때문에 사용하지 않고 따로 작성 -->
SELECT COUNT(*)
FROM BOARD
WHERE STATUS = 'Y'
<!-- list로 작성하기. filters라는 이름으로 사용하고 싶을 경우 dao에서 map으로 만들어서 넘기기 -->
<if test="list != null">
AND TYPE IN
<foreach collection="list" item="filter" open="(" separator="," close=")">
#{ filter }
</foreach>
</if>
</select>
매개값 주입 받기
- @MethodSource : 외부/내부에서 반환되는 값을 매개값으로 사용
- 지금 생성한 메서드의 리턴값을 getBoardcountTest()에서 사용할 예정
@MethodeSource에 사용될 메서드 생성 * static 메서드여야 함 * stream을 반환 함
public static Stream<Arguments> filterProvider() {
return Stream.of(
Arguments.arguments((Object) new String[] {"B2", "B3"}),
Arguments.arguments((Object) new String[] {"B1"})
);
}
-
@ParameterizedTest
@MethodSource("filterProvider") // filterProvider() 메서드의 리턴값을 해당 Test에서 사용
@DisplayName("조회되는 게시글 개수 - 필터 기능 포함")
public void getBoardCountTest(String[] filters) {
int count = 0;
// 계속 이런식으로 주석 처리 했다 풀었다 하면서 테스트 진행했었음
// String[] filters = new String[] {"B1"};
// String[] filters = new String[] {"B2", "B3"};
count = service.getBoardCount(filters);
System.out.println(count);
assertThat(count).isPositive().isGreaterThan(0);
}
앞에서는 타입별로(B1, B2, B3) 매개값을 바꿔주면서 테스트를 진행했다.
MethodeSource를 사용하니 그럴 필요 없이 테스트가 가능하게 됐다.
테스트 코드의 매개값을 수정없이 테스트할 수 있게 되어 편한 기능인 거 같다. 하지만 어렵다.^^
paging - test 코드 작성
- findAllTest() 메서드에 추가 작성
- 기존방식 : 쿼리문 작성하여 처리
- 단점 : 검색해하는 조건이 변경될 경우 쿼리문 수정 필요
@ParameterizedTest
@MethodSource("filterProvider")
@DisplayName("게시글 목록 조회 - 필터 기능 포함")
public void findAllTest(String[] filters) {
List<Board> list = null;
PageInfo pageInfo = null; // pageInfo 객체 생성
int listCount = 0;
listCount = service.getBoardCount(filters);
pageInfo = new PageInfo(5, 10, listCount, 10);
// 현재 페이지, paging 개수, 전체 게시글 개수, 한 페이지의 최대 게시글 개수
// service에 요청할 pageInfo 추가
list = service.findAll(filters, pageInfo);
System.out.println(list);
System.out.println(list.size());
assertThat(list).isNotNull();
assertThat(list.size()).isPositive().isEqualTo(expected);
}
paging - service 코드 작성
- findAll() 메서드에 pageInfo 매개값 추가
public List<Board> findAll(String[] filters, PageInfo pageInfo) {
List<Board> list = null;
SqlSession session = getSession();
// dao에도 pageInfo 추가
list = dao.findAll(session, filters, pageInfo);
session.close();
return list;
}
paging - dao 코드 작성
- mybatis에서 제공하는 RowBounds 클래스 사용
- 쿼리문 수정없이 쿼리문 실행 후, 조회가 되면 RowBounds를 갖고 원하는 데이터만 추출
- RowBounds 객체 생성 시 offset / limit 값을 전달하여 paging 구현
- offset = 0, limit = 10으로 세팅 시
- 0개를 건너뛰고 10개를 가져온다.(1번-10번)
- offset = 10, limit = 10으로 세팅 시
- 10개를 건너뛰고 10개를 가져온다.(11번-10번)
- offset = 20, limit = 10으로 세팅 시
- 20개를 건너뛰고 10개를 가져온다.(21번-10번)
- offset = 0, limit = 10으로 세팅 시
- servlet/JSP 방식 : rownum, subQuery를 사용한 쿼리문 작성하여 조회
public List<Board> findAll(SqlSession session, String[] filters, PageInfo pageInfo) {
// map 객체에 담아서 넘기기
Map<String, Object> map = new HashMap<>();
map.put("filters", filters);
// (pageInfo에서 현재 페이지 -1) * (페이지 인포에서 한 페이지에 보여질 최대 게시글 개수)
// 현재 페이지가 1페이지일 경우 offset이 0이어야되기 때문에 -1
// 그리고 10을 곱하면 0
int offset = (pageInfo.getCurrentPage() -1 ) * pageInfo.getListLimit();
int limit = pageInfo.getListLimit();
RowBounds rowBounds = new RowBounds(offset, limit);
return session.selectList("boardMapper.selectBoardListByFilters", map, rowBounds);
}
필터 / 현재 페이지를 받는 메서드 생성
@ParameterizedTest
@MethodSource("listProvider")
@DisplayName("게시글 목록 조회 -필터 기능 포함")
public void findAllTest(String[] filters) {
List<Board> list = null;
PageInfo pageInfo = null;
int listCount = 0;
listCount = service.getBoardCount(filters, int currentPage, int expected);
pageInfo = new PageInfo(currentPage, 10, listCount, 10);
list = service.findAll(filters, pageInfo);
System.out.println(list.size());
System.out.println(list);
assertThat(list).isNotNull();
// expected : listProvider() 메서드에서 3번째 매개값으로 작성한 값
assertThat(list.size()).isPositive().isEqualTo(expected);
}
// 다른 메서드에서 매개값으로 사용할 메서드 생성
public static Stream<Arguments> listProvider() {
return Stream.of(
// {"type"}, 현재 페이지, 게시글 개수
Arguments.arguments((Object) new String[] {"B2", "B3"}, 1, 4), // B2, B3 조회 시 1페이지에 게시글은 4개
Arguments.arguments((Object) new String[] {"B1"}, 1, 10), // B1 조회시 1페이지에는 10개의 게시글
Arguments.arguments((Object) new String[] {"B1"}, 16, 4) // B1 조회 시 16페이지에는 4개의 게시글
);
}