Step1 : https://datobi.tistory.com/28?category=948178
Step2 : https://datobi.tistory.com/29?category=948178
Step3에서는 DB를 연결 했다. 코드가 많이 바뀌진 않았다.
수정한 코드는 db/index.js와 view/index.ejs, routes/index.js 이다
그리고 DB 데이터 몇가지를 추가하였다. DB는 postgre를 사용하였다.
더보기를 누르면 해당 데이터를 추가 할 수 있다.
CREATE TABLE "student" (
"idx" INTEGER NOT NULL,
"name" VARCHAR NOT NULL,
"age" INTEGER NOT NULL,
"grade" CHAR(1) NOT NULL,
"address" VARCHAR NOT NULL,
PRIMARY KEY ("idx")
);
INSERT INTO "student" VALUES (1, '김똘똘', 10, 'B', '서울시');
INSERT INTO "student" VALUES (2, '이장님', 9, 'A', '서울시');
INSERT INTO "student" VALUES (3, '홍길동', 11, 'C', '강릉시');
INSERT INTO "student" VALUES (4, '윤뽀뽀', 10, 'A', '제주시');
INSERT INTO "student" VALUES (5, '박박', 9, 'D', '경기도');
INSERT INTO "student" VALUES (6, '김소희', 8, 'A', '서울시');
INSERT INTO "student" VALUES (7, '지선생', 10, 'A', '경기도');
INSERT INTO "student" VALUES (8, '장기하', 11, 'C', '강릉시');
INSERT INTO "student" VALUES (9, '원빈', 10, 'D', '서울시');
INSERT INTO "student" VALUES (10, '조인성', 10, 'C', '경기도');
INSERT INTO "student" VALUES (11, '산다라박', 11, 'B', '서울시');
INSERT INTO "student" VALUES (12, '김갑생', 9, 'C', '서울시');
INSERT INTO "student" VALUES (13, '김장', 12, 'A', '삼척시');
INSERT INTO "student" VALUES (14, '조여정', 11, 'D', '서울시');
INSERT INTO "student" VALUES (15, '이솜', 10, 'C', '경기도');
INSERT INTO "student" VALUES (16, '김별', 9, 'A', '경기도');
INSERT INTO "student" VALUES (17, '박막례', 10, 'B', '경기도');
INSERT INTO "student" VALUES (18, '조갑생', 11, 'C', '강릉시');
INSERT INTO "student" VALUES (19, '이하루', 10, 'D', '서울시');
INSERT INTO "student" VALUES (20, '김영광', 10, 'C', '경기도');
INSERT INTO "student" VALUES (21, '이택조', 11, 'B', '서울시');
INSERT INTO "student" VALUES (22, '최준', 9, 'C', '서울시');
INSERT INTO "student" VALUES (23, '김해준', 12, 'A', '삼척시');
INSERT INTO "student" VALUES (24, '이은지', 11, 'D', '서울시');
INSERT INTO "student" VALUES (25, '안영미', 10, 'C', '경기도');
INSERT INTO "student" VALUES (26, '김소희', 8, 'A', '서울시');
INSERT INTO "student" VALUES (27, '지선생', 10, 'A', '경기도');
INSERT INTO "student" VALUES (28, '장기하', 11, 'C', '강릉시');
INSERT INTO "student" VALUES (29, '원빈', 10, 'D', '서울시');
INSERT INTO "student" VALUES (30, '조인성', 10, 'C', '경기도');
INSERT INTO "student" VALUES (31, '산다라박', 11, 'B', '서울시');
INSERT INTO "student" VALUES (32, '김갑생', 9, 'C', '서울시');
INSERT INTO "student" VALUES (33, '김장', 12, 'A', '삼척시');
INSERT INTO "student" VALUES (34, '조여정', 11, 'D', '서울시');
INSERT INTO "student" VALUES (35, '이솜', 10, 'C', '경기도');
INSERT INTO "student" VALUES (36, '김별', 9, 'A', '경기도');
INSERT INTO "student" VALUES (37, '박막례', 10, 'B', '경기도');
INSERT INTO "student" VALUES (38, '조갑생', 11, 'C', '강릉시');
INSERT INTO "student" VALUES (39, '이하루', 10, 'D', '서울시');
INSERT INTO "student" VALUES (40, '김영광', 10, 'C', '경기도');
INSERT INTO "student" VALUES (41, '이택조', 11, 'B', '서울시');
INSERT INTO "student" VALUES (42, '최준', 9, 'C', '서울시');
INSERT INTO "student" VALUES (43, '김해준', 12, 'A', '삼척시');
INSERT INTO "student" VALUES (44, '이은지', 11, 'D', '서울시');
INSERT INTO "student" VALUES (45, '안영미', 10, 'C', '경기도');
INSERT INTO "student" VALUES (46, '김소희', 8, 'A', '서울시');
INSERT INTO "student" VALUES (47, '지선생', 10, 'A', '경기도');
INSERT INTO "student" VALUES (48, '장기하', 11, 'C', '강릉시');
INSERT INTO "student" VALUES (49, '원빈', 10, 'D', '서울시');
INSERT INTO "student" VALUES (50, '조인성', 10, 'C', '경기도');
INSERT INTO "student" VALUES (51, '산다라박', 11, 'B', '서울시');
INSERT INTO "student" VALUES (52, '김갑생', 9, 'C', '서울시');
INSERT INTO "student" VALUES (53, '김장', 12, 'A', '삼척시');
INSERT INTO "student" VALUES (54, '조여정', 11, 'D', '서울시');
INSERT INTO "student" VALUES (55, '이솜', 10, 'C', '경기도');
INSERT INTO "student" VALUES (56, '김별', 9, 'A', '경기도');
INSERT INTO "student" VALUES (57, '박막례', 10, 'B', '경기도');
INSERT INTO "student" VALUES (58, '조갑생', 11, 'C', '강릉시');
INSERT INTO "student" VALUES (59, '이하루', 10, 'D', '서울시');
INSERT INTO "student" VALUES (60, '김영광', 10, 'C', '경기도');
INSERT INTO "student" VALUES (61, '이택조', 11, 'B', '서울시');
INSERT INTO "student" VALUES (62, '최준', 9, 'C', '서울시');
INSERT INTO "student" VALUES (63, '김해준', 12, 'A', '삼척시');
INSERT INTO "student" VALUES (64, '이은지', 11, 'D', '서울시');
INSERT INTO "student" VALUES (65, '안영미', 10, 'C', '경기도');
INSERT INTO "student" VALUES (66, '김소희', 8, 'A', '서울시');
INSERT INTO "student" VALUES (67, '지선생', 10, 'A', '경기도');
INSERT INTO "student" VALUES (68, '장기하', 11, 'C', '강릉시');
INSERT INTO "student" VALUES (69, '원빈', 10, 'D', '서울시');
INSERT INTO "student" VALUES (70, '조인성', 10, 'C', '경기도');
INSERT INTO "student" VALUES (71, '산다라박', 11, 'B', '서울시');
INSERT INTO "student" VALUES (72, '김갑생', 9, 'C', '서울시');
INSERT INTO "student" VALUES (73, '김장', 12, 'A', '삼척시');
INSERT INTO "student" VALUES (74, '조여정', 11, 'D', '서울시');
INSERT INTO "student" VALUES (75, '이솜', 10, 'C', '경기도');
INSERT INTO "student" VALUES (76, '김별', 9, 'A', '경기도');
INSERT INTO "student" VALUES (77, '박막례', 10, 'B', '경기도');
INSERT INTO "student" VALUES (78, '조갑생', 11, 'C', '강릉시');
INSERT INTO "student" VALUES (79, '이하루', 10, 'D', '서울시');
INSERT INTO "student" VALUES (80, '김영광', 10, 'C', '경기도');
INSERT INTO "student" VALUES (81, '이택조', 11, 'B', '서울시');
INSERT INTO "student" VALUES (82, '최준', 9, 'C', '서울시');
INSERT INTO "student" VALUES (83, '김해준', 12, 'A', '삼척시');
INSERT INTO "student" VALUES (84, '이은지', 11, 'D', '서울시');
INSERT INTO "student" VALUES (85, '안영미', 10, 'C', '경기도');
INSERT INTO "student" VALUES (86, '김소희', 8, 'A', '서울시');
INSERT INTO "student" VALUES (87, '지선생', 10, 'A', '경기도');
INSERT INTO "student" VALUES (88, '장기하', 11, 'C', '강릉시');
INSERT INTO "student" VALUES (89, '원빈', 10, 'D', '서울시');
INSERT INTO "student" VALUES (90, '조인성', 10, 'C', '경기도');
INSERT INTO "student" VALUES (91, '산다라박', 11, 'B', '서울시');
INSERT INTO "student" VALUES (92, '김갑생', 9, 'C', '서울시');
INSERT INTO "student" VALUES (93, '김장', 12, 'A', '삼척시');
INSERT INTO "student" VALUES (94, '조여정', 11, 'D', '서울시');
INSERT INTO "student" VALUES (95, '이솜', 10, 'C', '경기도');
INSERT INTO "student" VALUES (96, '김별', 9, 'A', '경기도');
INSERT INTO "student" VALUES (97, '박막례', 10, 'B', '경기도');
INSERT INTO "student" VALUES (98, '조갑생', 11, 'C', '강릉시');
INSERT INTO "student" VALUES (99, '이하루', 10, 'D', '서울시');
INSERT INTO "student" VALUES (100, '김영광', 10, 'C', '경기도');
INSERT INTO "student" VALUES (101, '김국희', 11, 'B', '경기도');
view/index.ejs
<!DOCTYPE html>
<html>
<head>
<title>index</title>
<link rel='stylesheet' href='/stylesheets/style.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css' />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<h3>
currentPage : <%= paging.currentPage %><br>
currentSet : <%= paging.currentSet %><br>
startPage : <%= paging.startPage %><br>
endPage : <%= paging.endPage %><br>
</h3>
<div class="container">
<table class="table">
<thead>
<tr>
<th scope="col">idx</th>
<th scope="col">name</th>
<th scope="col">age</th>
<th scope="col">grade</th>
</tr>
</thead>
<tbody>
<!-- 게시글-->
<% for(let i=0; i<data.length; i++){ %>
<tr>
<th scope="row"><%= data[i].idx%></th>
<td><%= data[i].name %></td>
<td><%= data[i].age %></td>
<td><%= data[i].grade %></td>
</tr>
<% } %>
</tbody>
</table>
<nav aria-label="Page navigation example">
<ul class="pagination justify-content-center">
<!-- 뒤로가기 버튼 (1보다 작으면 무조건 뒤로가기 생성)-->
<% if(paging.currentSet > 1) {%>
<li class="page-item">
<a class="page-link" href="/?page=<%=paging.startPage-1%>" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<% } %>
<!--숫자 버튼-->
<% for(let i=paging.startPage; i<=paging.endPage; i++){
if(i > paging.totalPage){break;}
if(i == paging.currentPage){ %>
<tr>
<td>
<li class="page-item active"><a class="page-link" href='/?page=<%=i%>'><%=i%></a></li>
</td>
</tr>
<% } else {%>
<tr>
<td>
<li class="page-item"><a class="page-link" href='/?page=<%=i%>'><%=i%></a></li>
</td>
</tr>
<% }
} %>
<!--앞으로 버튼 (현재 세트가 토탈보다 작으면 생성)-->
<% if(paging.currentSet < paging.totalSet) {%>
<li class="page-item">
<a class="page-link" href="/?page=<%=paging.endPage+1%>" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
<% } %>
</ul>
</nav>
</div>
</body>
</html>
- 게시글들을 data란 변수에 담아
[
{ idx: 1, name: '김똘똘', age: 10, grade: 'B' },
{ idx: 2, name: '이장님', age: 9, grade: 'A' },
{ idx: 3, name: '홍길동\r\n', age: 11, grade: 'C' },
...
]
이러한 JSON 형태로 가져와서 반복문을 통해 각각의 컬럼에 맞는 값들을 넣어주었다.
- 숫자버튼을 출력할 때, 현재 페이지 번호 인지 판별하여, 현재 페이지번호일 때 active라는 클래스를 달아주었다.
routes/index.js
var express = require('express');
var router = express.Router();
let db = require('../db/index')
router.get('/', async function(req, res, next) {
let currentPage = req.query.page; // 현재 보여지는 페이지
if(!currentPage) currentPage = 1 // page 파라미터 값을 넘겨주지 않을 시, 1페이지로 설정
let pagePerSize = 10 // 한 페이지에 보여질 게시물 수
let pageBtnSize = 5 // 보여질 페이지 버튼의 개수
// 총 게시물 수
let totalPageCnt = await db.getStudentCount()
if (totalPageCnt < 0){
totalPageCnt = 1
}
let totalPage = Math.ceil(totalPageCnt / pagePerSize) // 전체 페이지 수
let totalSet = Math.ceil(totalPage / pageBtnSize) // 전체 세트 수
let currentSet = Math.ceil(currentPage / pageBtnSize) // 현재 버튼 세트 번호
let startPage = ((currentSet-1) * pageBtnSize) + 1 // 시작 페이지 번호
let endPage = (startPage + pageBtnSize) - 1 // 끝 페이지 번호
let startPost = '' // db
// DB에 들어갈 offset 설정
if(currentPage < 0){
startPost = 0
} else {
startPost = (currentPage - 1) * pagePerSize // 시작 게시글 번호
}
let data = await db.getStudentInfo(startPost, pagePerSize)
// console.log(data)
let paging = { // ejs로 전송하기위해 객체화
'startPage' : startPage,
'endPage' : endPage,
'currentSet' : currentSet,
'totalSet' : totalSet,
'totalPage' : totalPage,
'currentPage' : currentPage,
}
res.render('index', {'paging': paging, 'data': data})
});
module.exports = router;
- totalPageCnt를 db에서 가져왔다. 0인경우 에러처리를 해주었다.
페이지에 맞는 게시물을 db에서 가져올 때,
SELECT *
FROM STUDENT
LIMIT 10 /* 가져올 게시물 수 */
OFFSET 0 /*가져올 게시물의 첫번째 idx*/
이러한 쿼리를 쓴다. limt은 가져올 게시물의 갯수이고 offset은 어디부터 가져올건지를 설정해 줄 수 있다.
그래서 LIMIT은 pagePerSize로, OFFSET은 startPost로 설정해두었다.
db/index.js
let db = require('./config')
// student 개수를 반환하는 메서드
async function getStudentCount() {
let query = 'SELECT COUNT(*) FROM student'
let result = await db.query(query)
let data = result.rows[0].count
return data
}
// student row들을 리턴하는 메서드
async function getStudentInfo(startPost, pagePerSize) {
let query = `
SELECT *
FROM STUDENT
LIMIT ${pagePerSize}
OFFSET ${startPost}
`
let data = [] // 배열 만듦
let { rows } = await db.query(query)
for(let row of rows){ // 배열안에 각각의 객체 삽입
let node = {
'idx' : row['idx'],
'name' : row['name'],
'age' : row['age'],
'grade' : row['grade'],
}
data.push(node)
}
return data
}
module.exports = {
getStudentCount,
getStudentInfo
}
db/index.js에는 Student의 총 갯수를 가져오는 getStudentCount()와
해당 페이지의 게시물을 가져오는 getStudentInfo를 선언하였다.
getStudentInfo 메서드에서 data에 JSON 형태로 값들을 담아 반환하였다.
결과화면
소스코드 : https://github.com/datoybi/blog-posting/tree/main/paging-step3
GitHub - datoybi/blog-posting: code examples posted on my blog
code examples posted on my blog. Contribute to datoybi/blog-posting development by creating an account on GitHub.
github.com
'개발 > Node.js' 카테고리의 다른 글
[nodejs] 오류 처리 미들웨어 사용법 (비동기) (0) | 2022.01.19 |
---|---|
[nodejs] Middleware 미들웨어 개념, 종류, 사용법(에플리케이션 레벨 미들웨어, 라우터 레벨 미들웨어) 1 (0) | 2022.01.17 |
nodejs를 이용한 페이징 처리 (페이징 버튼 처리) Step2 (0) | 2021.11.22 |
nodejs를 이용한 페이징 처리 (버튼 누를시 게시글 갱신) Step1 (0) | 2021.11.16 |
Postgre와 nodejs(Express.js) 연동 - 2 (모듈화 및 데이터 추출) (0) | 2021.11.15 |