개발관련/코드로 배우는 스프링 웹 프로젝트(개정판)

Part3 - MyBatis와 스프링에서 페이징 처리 Chapter13

개념원리 2023. 6. 4. 10:58

Mybatis는 SQL을 그대로 사용할 수 있기 때문에 인라인뷰를 이용하는 SQL을 작성하고, 필요한 파라미터를 지정하는 방식으로 페이징 처리를 하게 됩니다.

여기서 신경써야 하는 점은 페이징 처리를 위해서는 SQL을 실행할 때 몇가지 파라미터가 필요하다는 점 입니다.

 

페이징 처리를 위해 필요한 파라미터

  1. 페이지 번호(PageNum)
  2. 한 페이지당 몇 개의 데이터(amount)를 보여줄 것인지

페이지 번호와 몇개의 데이터가 필요한지를 파라미터로 전달하는 방식도 좋치만 이후 확장성을 생각한다면 데이터를 하나의 객체로 묶어서 전송 하는것이 좋습니다.

 

org.zerock.domain 패키지에 Criteria 이름의 클래스를 작성 합니다.

Criteria는 검색의 기준을 의미 합니다.

package org.zerock.domain;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class Criteria {
	
	private int pageNum;
	private int amount;
	
	
	public Criteria() {
		this(1,10);
	}


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

Criteria 클래스의 용도는 pageNum과 amount 값을 같이 전달하는 용도지만 생성자를 통해 기본 값을 1페이지, 10개로 지정해서 처리 합니다.

Lombok을 이용해서 getter/setter를 생성해줍니다.

 

13.1 MyBatis 처리와 테스트

BoardMapper는 인터페이스와 어노테이션을 이용하기 때문에 페이징 처리와 같이 경우에 따라 SQL 구문 처리가 필요한 상황에서는 복잡하게 작성 됩니다.

(SQL문이 길어지고 복잡해지면 개인적으로 XML로 처리하는 것이 더 알아보기 쉽고 관리하기 편리합니다.)

 

org.zerock.mapper 패키지의 BoardMapper에는 위에서 작성한 Criteria 타입을 파라미터로 사용하는 getListWithPaging() 메서드를 작성합니다.

 

package org.zerock.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Select;
import org.zerock.domain.BoardVO;
import org.zerock.domain.Criteria;

public interface BoardMapper {
	
	//@Select("select * from tbl_board where bno > 0")
	public List<BoardVO> getList();
	
	public List<BoardVO> getListWithPaging(Criteria cri);
	
	public void insert(BoardVO board);
	
	public void insertSelectKey(BoardVO board);
	
	public BoardVO read(Long bno);
	
	public int delete(Long bno);
	
	public int update(BoardVO board);
}

 

기존에 만들어둔 src/main/resources의 BoardMapper.xml에 getListWithPaging에 해당하는 태그를 추가합니다.

	<select id="getListWithPaging" resultType="org.zerock.domain.BoardVO">
	  <![CDATA[
		  select 
		    bno, title, content, writer, regdate, updatedate
		  from 
		      (
			      select /*+INDEX_DESC(tbl_board pk_board) */
			        rownum rn, bno, title, content, writer, regdate, updatedate 
			      from 
			        tbl_board
			      where rownum <= 20
		      )
	      where rn > 10
	  ]]>
	</select>

작성된 BoardMapper.xml에서는 XML의 CDATA 처리가 들어갑니다.

CDATA 섹션은 XML에서 사용할 수 없는 부등호를 사용하기 위함인데, XML을 사용할 경우에는 "< , > " 는 태그로 인식하는데, 이로 인해 생기는 문제를 막기 위함입니다.

(&lt; 난 &gt;와 같은 특수문자를 사용할수도 있긴 합니다.)

 

인라인뷰에서는 BoardVO를 구성하는데 필요한 모든 칼럼과 ROWNUM을 RN이라는 가명을 이용해서 만들어 주고 바깥쪽 SQL에서는 RN 칼럼을 조건으로 처리합니다.

 

13.1.1 페이징 테스트와 수정

MyBatis의 "#{ } " 를 정용하기 전에 XML 설정이 제대로 동작하는지 테스트를 먼저 진행 하는것이 좋습니다.

테스트 환경은 이미 준비 되어 있으므로 간단히 테스트 코드만을 추가할수 있습니다.

src/test/java 내의 BoardMappterTests 클래스에 메서드를 추가합니다.

 

	@Test
	public void testPaging() {
		Criteria cri = new Criteria();
		
		List<BoardVO> list = mapper.getListWithPaging(cri);
		
		list.forEach(board -> log.info(board));
		
	}

Critera 클래스에서 생성된 객체는 pageNum은 1, amount는 10이라는 기본값을 가지므로 별도의 파라미터 없이 생성합니다.

현재는 파라미터의 값이 반영되지 않았으므로 2페이지의 내용이 정상적으로 나오는지 확인 합니다.

SQL에 문제가 없다는 것을 확인했담녀 이제 Criteria 객체 내부의 값을 이용해서 SQL이 동작하도록 수정합니다. 

20과 10이라는 값은 결국 pageNum과 amount를 이용해서 조절되는 값 입니다.

]

BoardMapper.xml 을 수정해서 pageNum과 amount를 변경 할 수 있게 수정 합니다.

	<select id="getListWithPaging" resultType="org.zerock.domain.BoardVO">
	  <![CDATA[
		  select 
		    bno, title, content, writer, regdate, updatedate
		  from 
		      (
			      select /*+INDEX_DESC(tbl_board pk_board) */
			        rownum rn, bno, title, content, writer, regdate, updatedate 
			      from 
			        tbl_board
			      where rownum <= #{pageNum} * #{amount}
		      )
	      where rn > (#{pageNum} -1) * #{amount}
	  ]]>
	</select>

SQL의 동작에 문제가 없는지 확인해야 합니다.

이전의 testpaging()을 조금 수정하겠습니다.

BoardMapperTests.java

확인을 위해서 Criteria 객체를 생성할 때 파라미터를 추가해 보거나, setter를 이용해서 내용을 수정 합니다.

 

위의 경우는 한 페이지당 10개씩 출력하는 3페이지에 해당하는 데이터를 구한 것 입니다.

테스트 코드가 동작한 이후에는 SQL Developer에서 실행된 결과와 동일한지 체크하고 페이지 번호를 변경해서 정상적으로 번호가 처리 되는지 확인 합니다.

 

13.2 BoardController와 BoardService 수정

페이징 처리는 브라우저에서 들어오는 정보를 기준으로 동작하기 때문에 BoardController와 BoardService 역시 전달되는 파라미터들을 받는 형태로 수정해야 합니다.

 

13.2.1 BoardService 수정

BoardService는 Criteria를 파라미터로 처리하도록 BoardService 인터페이스와 BoardServiceImpl클래스를 수정합니다.

BoardService.java
BoardServiceImpl.java

원칙적으로는 BoardService 쪽에 대한 수정이 이루어졌으니 이에 대한 테스트를 진행 합니다.

메서드를 수정하면서 이미 테스트 코드 역시 에러가 발생 했으므로 아래와 같이 수정해줍니다.

 

13.2.2 BoardController 수정

기존 BoardContoller의 list()는 아무런 파라미터가 없이 처리되었기 때문에 pageNum과 amount를 처리하기 위해서 아래와 같이 수정 합니다.

	@GetMapping("/list")
	public void list(Criteria cri, Model model) {
		log.info("list"+cri);
		
		model.addAttribute("list",service.getList(cri));
	}

Criteria 클래스를 하나 만들어 두면 위와 같이 편리하게 하나의 타입만으로 파라미터라 리턴 타입을 사용 할 수 있습니다.

BoardController 역시 이전에 테스트를 진행 했으므로 pageNum 과 amount를 파라미터로 테스트 합니다.

	@Test
	public void testListPaging() throws Exception {

		log.info(mockMvc.perform(
				MockMvcRequestBuilders.get("/board/list")
				.param("pageNum", "2")
				.param("amount","50"))
				.andReturn().getModelAndView().getModelMap());
	}