한 페이지에 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에 조건문을 붙여 게시글을 보이게 해야 한다.
그런데 문제가 하나 더 있다.
SELECT rownum, b.*
FROM boards b
WHERE rownum > 1
ORDER BY id DESC;
에서 WHERE이 먼저 실행되므로 rownum이 SELECT 될 수 없다.
SELECT * FROM ( SELECT rownum no, b.* FROM boards b ORDER BY id DESC ) WHERE no>=1 AND no<=10;
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씩 변하는 변수 쿼리를 만들어야 한다.
<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으로 받았다.
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;
}
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
}
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);
}
우리는 일단 페이징 바가 없기 때문에 주소로 페이지를 이동해야 한다.
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";
}
그런데
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문은 {}를 사용하지 않아도 된다.