/root
|-- [-]models
|-- middlewares
|-- controller
|-- [-]service
|-- routes
|-- public
|-- views
|-- server.js
프로젝트의 규모가 커지고 복잡해질수록 라우트들은 수많은 줄로 이어질 수 있고
코드의 구조와 흐름을 한눈에 파악하기가 어려워집니다
라우터를 분리하는 것은 코드의 구조를 깔끔하게 정리하기 위해서이자,
유지보수가 편리하도록 하기 위함입니다
협업과정에서도 멤버 각각이 다른 모듈로 작업하게 되기 때문에
코드의 충돌 우려가 적어집니다
라우터를 분리하는 이유를 한줄요약하자면 '코드의 관리'를 위해서입니다
가장 일반적인 방법은 라우터를 관리할 routes
디렉토리와
각 라우터의 콜백함수를 관리할 controller
디렉토리로 나누는 것입니다
필요에 따라 미들웨어를 따로 관리하기 위한 middleware
디렉토리를 추가하기도 합니다
아래에 간단한 예를 들어보겠습니다
요청 URL이 / 일 경우, "Hello World!" 를 응답으로 보내는
라우터와 컨트롤러 코드는 다음과 같습니다
서버(Server)
서버는 클라이언트의 요청을 받아들이는 입구 역할을 합니다
[server.js]
const router = require("./routes");
app.use(router);
라우터(Router)
서버에 들어온 요청을 어떤 컨트롤러에게 전달할지 결정하는 역할을 합니다
[router.js]
router.get('/', hello)
module.exports = router
컨트롤러(Controller)
컨트롤러는 요청을 처리한 결과를 응답으로 보내는 역할을 합니다
[controller.js]
//module.exports 생략문법
exports.hello = (req, res) => {
res.send('Hello World!');
};
끝으로 미들웨어(Middleware)는 요청과 응답 사이에서 작동하는 함수입니다
요청을 처리하기 전에 요청에서 정보를 추출하거나,
응답을 생성한 후에 응답에 추가 정보를 삽입하는 등
요청과 응답 사이에서 어떤 추가적인 작업이 필요할 때의 역할을 담당합니다
아래와 같이 요청의 바디영역을 파싱하는 코드 역시 하나의 미들웨어입니다
app.use(express.urlencoded({extended: true}))
↓ 이제 이 난잡한 server.js 파일을 해체할 시간이 왔습니다
const express = require("express");
const nunjucks = require("nunjucks");
const app = express();
const PORT = process.env.SERVER_PORT || 3000;
let boardList = [];
const writeHandler = (req, res) => {
const boardItem = req.body;
boardList.push(boardItem);
const getTimeNow = (date) => {
let mm = date.getMonth() + 1; // 0 ~ 11
mm = (mm > 9 ? "" : "0") + mm; // 01 02...09 10 11
let dd = date.getDate(); // 1 ~ 31
dd = (dd > 9 ? "" : "0") + dd;
let yy = date.getFullYear();
let hr = date.getHours()
let min = date.getMinutes()
let sec = date.getSeconds()
return [yy, mm, dd].join("-")+"."+[hr, min, sec].join(".")
};
boardItem.date = getTimeNow(new Date());
boardItem.hit = -1;
boardItem.idx = boardList.length - 1;
res.redirect(`/view?index=${boardItem.idx}`);
};
const modifyHandler = (req, res) => {
const index = req.query.index;
const boardItem = boardList[index];
boardItem.subject = req.body.subject;
boardItem.writer = req.body.writer;
boardItem.content = req.body.content;
// 객체 속성을 한꺼번에 선택하는 신문법
// const {index, ...rest} = req.body
// boardList[index] = rest
res.redirect("/view?index=" + index);
};
app.set("view engine", "html");
nunjucks.configure("views", {
express: app,
});
app.use(express.static("public"));
app.use(express.urlencoded({ extended: true }));
app.get("/", (req, res) => {
const name = req.query.name;
res.render("index.html", { name });
});
app.post("/list", (req, res) => {
res.redirect("/list");
});
app.get("/list", (req, res) => {
//검색 기능 구현
const searchType = req.query.searchType || 'writer';
const search = req.query.search
const result = req.query.searchType === undefined
? boardList
: boardList.filter(obj => obj[searchType].includes(search));
const reversedList = [...result].reverse();
res.render("list.html", { boardList: reversedList });
// nunjucks 내장 기능으로 화면 그리기
// {% for item in Arr %}
// {{ loop.index0 }}: {{ item }}
// {% endfor %}
});
app.get("/write", (req, res) => {
res.render("write.html");
});
app.post("/write", writeHandler);
app.get("/view", (req, res) => {
const index = req.query.index;
if (index < 0 || index >= boardList.length) {
// 에러 방지용 빈 페이지 띄우기
return res.render("view.html", { boardItem: {} });
}
const boardItem = boardList[index];
boardItem.hit += 1;
res.render("view.html", { boardItem, boardList });
});
app.post("/modify", modifyHandler);
app.get("/modify", (req, res) => {
const index = req.query.index;
const boardItem = boardList[index];
res.render("modify.html", { boardItem, index });
});
app.post("/delete", (req, res) => {
const index = req.body.index;
boardList.splice(index, 1);
res.redirect("/list");
});
app.listen(PORT, () => {
console.log("server start");
});
1) route 디렉토리
[index.js]
index파일은 라우터끼리도 분기를 나눠야 할 경우가 생겼을 때
그 분기점을 결정할 최상위 라우터 역할을 합니다
const express = require('express')
const router = express.Router()
const board = require('./board.routes')
const gallery = require('./gallery.routes')
router.use("/board",board)
router.use("/gallery",gallery)
module.exports = router
[board.router.js]
const express = require('express')
const router = express.Router()
const controller = require('../controllers/board.controller')
router.get('/', controller.getIndex)
router.get('/list', controller.getList)
router.post('/list', controller.postList)
router.get('/write', controller.getWrite)
router.post('/write', controller.postWrite)
router.get('/view', controller.getView)
router.get('/modify', controller.getModify)
router.post('/modify', controller.postModify)
router.post('/delete', controller.postDelete)
module.exports = router
2) controller 디렉토리
[board.controller.js]
const boardList = []
exports.getIndex = (req, res)=>{
const name = req.query.name;
res.render("index.html", { name });
}
exports.getList = (req, res) => {
const searchType = req.query.searchType || 'writer';
const search = req.query.search
const result = req.query.searchType === undefined
? boardList
: boardList.filter(obj => obj[searchType].includes(search));
const reversedList = [...result].reverse();
res.render("z-board/list.html", { boardList: reversedList });
}
exports.getWrite = (req, res)=>{
res.render("z-board/write.html");
}
exports.getView = (req, res)=>{
const index = req.query.index;
if (index < 0 || index >= boardList.length) {
// 에러 방지용 빈 페이지 띄우기
return res.render("z-board/view.html", { boardItem: {} });
}
const boardItem = boardList[index];
boardItem.hit += 1;
res.render("z-board/view.html", { boardItem, boardList });
}
exports.getModify = (req, res) =>{
const index = req.query.index;
const boardItem = boardList[index];
res.render("z-board/modify.html", { boardItem, index });
}
exports.postList = (req, res)=>{
res.redirect("/board/z-board/list");
}
exports.postWrite = (req,res)=>{
const boardItem = req.body;
boardList.push(boardItem);
const getTimeNow = (date) => {
let mm = date.getMonth() + 1; // 0 ~ 11
mm = (mm > 9 ? "" : "0") + mm; // 01 02...09 10 11
let dd = date.getDate(); // 1 ~ 31
dd = (dd > 9 ? "" : "0") + dd;
let yy = date.getFullYear();
let hr = date.getHours()
let min = date.getMinutes()
let sec = date.getSeconds()
return [yy, mm, dd].join("-")+"."+[hr, min, sec].join(".")
};
boardItem.date = getTimeNow(new Date());
boardItem.hit = -1;
boardItem.idx = boardList.length - 1;
res.redirect(`/board/z-board/view?index=${boardItem.idx}`);
}
exports.postView = (req, res) =>{
}
exports.postModify = (req, res) =>{
const index = req.query.index;
const boardItem = boardList[index];
boardItem.subject = req.body.subject;
boardItem.writer = req.body.writer;
boardItem.content = req.body.content;
res.redirect("/board/z-board/view?index=" + index);
}
exports.postDelete = (req, res) =>{
const index = req.body.index;
boardList.splice(index, 1);
res.redirect("/board/z-board/list");
}
3) server 파일
[server.js]
const express = require("express");
const app = express();
const nunjucks = require("nunjucks");
const router = require("./routes")
const PORT = process.env.SERVER_PORT || 3000;
app.set("view engine", "html");
nunjucks.configure("views", {
express: app,
});
app.use(express.static("public"));
app.use(express.urlencoded({ extended: true }));
app.use(router)
app.listen(PORT, () => {
console.log("server start");
});
*서버와 라우터는 최대한 간결하게 작성할 것!