Blog 게시판 만들기 (6) - 페이징 (1) : 쿼리스트림으로 페이지 이동하기

bethe·2022년 9월 10일
0

Springboot

목록 보기
37/46
post-custom-banner

페이징 이론

📝 rownum으로 찾는 페이지

한 페이지에 10개의 게시글을 보이게 하려고 한다.
그런데

select * from boards where id>=1 and id<11;
select * from boards where id>=11 and id<21;
select * from boards where id>=21 and id<31;

처럼 id로 페이지를 찾으려고 하면, id는 시퀀스로 만들어졌기에 차후 삭제되거나 수정되어 원하는 목록의 수만큼 게시글을 보여주지 못하는 문제가 생긴다.

👉 따라서 rownum으로 숫자를 붙여 정렬하고 rownum에 조건문을 붙여 게시글을 보이게 해야 한다.


📝 rownum에 WHERE절이 안 걸려!

그런데 문제가 하나 더 있다.

SELECT rownum, b.*
FROM boards b
WHERE rownum > 1
ORDER BY id DESC;

에서 WHERE이 먼저 실행되므로 rownum이 SELECT 될 수 없다.

🔓 inline view 사용

SELECT * FROM
(
SELECT rownum no, b.*
FROM boards b
ORDER BY id DESC
)
WHERE no>=1 AND no<=10;


오라클 페이징 함수 (OFFSET, Oracle 12부터 가능)

SELECT *
FROM boards
ORDER BY id DESC
OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY;

SELECT *
FROM boards
ORDER BY id DESC
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;

SELECT *
FROM boards
ORDER BY id DESC
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;

페이지마다 10건씩 보기 위해서는 OFFSET 뒤의 값이 10씩 변하는 변수 쿼리를 만들어야 한다.



💻 페이징 코드

1. Mapper

	<select id="findAll" resultType="site.metacoding.red.domain.boards.mapper.MainView">
		SELECT b.id, b.title, u.username
		FROM boards b
		INNER JOIN users u
		ON b.usersId = u.id
		ORDER BY b.id DESC
		OFFSET #{startNum} ROWS FETCH NEXT 10 ROWS ONLY;
	</select>

파라매터 이름을 startNum으로 받았다.


2. MainView

1) MainView에 페이징 변수 설정

package site.metacoding.red.domain.boards.mapper;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class MainView {
	private Integer id;
	private String title;
	private String username;
	private Integer StartNum;
}

Integer StartNum으로 파라매터를 받아도 좋지만, 차후 페이징 바를 만들기 위해서는 여러 변수가 필요해 PagingView라는 오브젝트로 받기로 한다.

package site.metacoding.red.domain.boards.mapper;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class MainView {
	private Integer id;
	private String title;
	private String username;
	private PagingView paging;
}

2) PagingView 생성

package site.metacoding.red.domain.boards.mapper;

public class PagingView {
	private Integer startNum; // startNum이 0이면
	private Integer totalCount; // 는 23
	private Integer totalPage; // 3
	private Integer currentPage; // 0으로 시작해도 되고, 1으로 시작해도 됨 (0으로 설정함)
	private boolean isLast; // 현재 0페이지이면 false = 마지막 페이지이면 true
	private boolean ifFirst; // 현재 0페이지이면 true
}

3. DAO

DAO또한 findAll이 startNum을 받으므로 파라매터 수정.

package site.metacoding.red.domain.boards;

import java.util.List;

import site.metacoding.red.domain.boards.mapper.MainView;

public interface BoardsDao {
	public void insert(Boards boards);
	public Boards findById(Integer id);
	public List<MainView> findAll(Integer startNum);
	public void update(Boards boards);
	public void delete(Integer id);
}

4. Controller

우리는 일단 페이징 바가 없기 때문에 주소로 페이지를 이동해야 한다.

  • 📌 주소에 적을 값은 PK가 아니면 쿼리스트링으로 받는다. 페이지는 id(PK)가 아니므로 쿼리스트링으로 받는다.

1) Page 받기

Page를 받을 때 클라이언트는 페이지가 0, 10, 20씩 증가할 것을 예상해 startNum값을 넣어주진 않는다. 따라서 몇 page인지 받아 우리가 satrtNum을 계산해줘야 한다.

	@GetMapping({"/","/boards"})
	public String getBoardList(Model model, Integer page) { // 0->0, 1->10, 2->20 연산하여 startNum을 만들어줘야 함
		Integer startNum = page * 10;
		List<MainView> boardsList = boardsDao.findAll(startNum);
		model.addAttribute("boardsList", boardsList);
		return "boards/main";
	}

2) 쿼리스트림이 없거나 Page 키값이 없을 때 초기값 설정하기

그런데
http://localhost:8000/
http://localhost:8000/?page=
처럼 쿼리스트림이 없거나 Page 키값이 없을 때에도 게시판 글은 맨 첫 페이지를 보여주어야 한다. 즉, 이러한 경우 초깃값을 0으로 설정해줘야 한다.

🌿→🌳 null or ""(공백?)
주의해야 할 점 : 쿼리스트림이 없거나 키값이 없을 때 null이 나오는지 ""(공백)인지 확인해봐야 한다.
코드가 완성되지 않아서 return은 제대로 되지 않겠지만 System.out.println("page : "+page);으로 null이 나오는지 ""이 나오는지 확인해봐야 한다.
⇒ 결과 : null이 나옴

	@GetMapping({"/","/boards"})
	public String getBoardList(Model model, Integer page) { // 0->0, 1->10, 2->20 연산하여 startNum을 만들어줘야 함
		if(page==null) page = 0; //if문에서 한줄은 {}안써도 됨
		Integer startNum = page * 10;
		List<MainView> boardsList = boardsDao.findAll(startNum);
		model.addAttribute("boardsList", boardsList);
		return "boards/main";
	}
  • if(page==null) page = 0; : 한줄인 if문은 {}를 사용하지 않아도 된다.
profile
코딩을 배우고 기록합니다. 읽는 사람이 이해하기 쉽게 쓰려고 합니다.
post-custom-banner

0개의 댓글