소프트웨어 설계와 관련된 디자인 패턴
MVC를 이용하는 웹 프레임워크
디자인 패턴이란? 상황에 따라 자주 쓰이는 설계 방법을 정리한 코딩 방법론
여기서 완벽한 의존성 분리가 어려운 이유는 모델과 뷰 사이는 컨트롤러를 통해서 소통하기 때문에 완벽하게 의존성이 분리될 수 없기 때문이다.
view, browser는 프론트이고 나머진 다 백엔드
controller: view와 model을 연결하는 부분
model: 데이터 처리하는 부분(나중에 DB랑 연결되면 테이블을 저장)
routes: 경로 설정하는 부분
views: UI 관련 처리
모델 -> 컨트롤러 -> 라우터 -> app.js -> views
models폴더/userModel.js -> 배열 안에 객체를 저장함(DB 대신 더미 데이터)
// 데이터 모델 만들거임//
// 간단한 데이터 모델 생성
const users = [
{ id: 1, name: "마루", email: "maru@naver.com" },
{ id: 2, name: "강아지", email: "dog@naver.com" },
];
// 유저 데이터 전부 가지고 오기
const getAllUser = () => {
return users;
};
// id로 해당하는 유저 찾기
const getUserById = (id) => {
//(매개변수 string으로 들어옴)
return users.find((user) => user.id === parseInt(id));
};
// 다른 곳에서도 쓸 수 있게끔 내보냄(리액트에서도 내보내는거 있음)
// 해당 파일에서 만든 함수 내보내기(모듈화)
module.exports = { getAllUser, getUserById };
controllers폴더/userController.js -> 경로와 연결될 함수 내용 정의(경로와 연결되는 함수이므로 req객체와 res객체 사용), 컨트롤러와 모델 연결
// 가져오기
const userModel = require("../models/userModel");
// 유저 전부 가져오는 컨트롤러
const getUsers = (req, res) => {
// 전체 유저를 가지고 있음
const users = userModel.getAllUsers();
res.render("users/index", { users });
};
// 해당하는 유저 가져오기
const getUser = (req, res) => {
// get요청이니까 params에 담김
const user = userModel.getUserById(req.params.id);
if (user) {
// 프론트에서 보여주려면 그 데이터 던져줘야 함
res.render("users/show", { user });
} else {
res.statusCode = 404;
return res.send("해당하는 아이템이 없습니다.");
}
};
module.exports = { getUsers, getUser };
routes폴더/userRoutes.js -> 경로를 controller와 연결
// 쓴다고 명시
const express = require("express");
const router = express.Router();
const userController = require("../controllers/userController");
// 유저 전부 가져오기를 하는 라우터(app.get했던거)(앞에 users가 앞에 있음->use로 생략함)
router.get("/", userController.getUsers);
// 해당하는 유저 가져오기를 하는 라우터(url뒤에 id가 붙어서 날라옴)
router.get("/:id", userController.getUser);
module.exports = router;
app.js -> router 불러오는 부분(특정 시작 url의 역할 구분 가능)
const express = require("express");
const app = express();
const port = 3000;
// 라우팅 파일 불러오기
const userRouters = require("./routes/userRoutes");
// body-parser
// x-www-form-urlencoded 방식, 객체 형태로 결과가 나옴(객체형태: {})
app.use(express.urlencoded({ extended: true }));
// json
app.use(express.json());
app.use("/public", express.static("public"));
// users경로에 대한 라우팅 처리(/users경로로 들어감)
app.use("/users", userRouters); // '/users'에 대한 요청은 userRoutes로 처리
app.set("view engine", "ejs");
app.set("views", "./views");
// 기본 홈 라우트
app.get("/", (req, res) => {
res.render("index", { title: "MVC 패턴" });
});
app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});
views/index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>MVC 패턴 연습</h1>
<!-- 파일주소가 아니라 요청 -->
<a href="/users">유저 리스트로 가기</a>
</body>
</html>
a태그 누름 -> users로 요청보냄(url) -> app.js -> 라우터 -> 컨트롤러 -> 모델
404 에러는 클라이언트가 잘못된 주소로 접속했을때 발생
app.get('*', (req, res) => {
res.render('404');
});
만약 라우터 파일이 다음과 같이 되어있다고 하자
const express = require("express");
const router = express.Router();
const ItemController = require("../controllers/itemController");
// 아이템 전부 가져오기를 하는 라우터
router.get("/", ItemController.getItems);
// 해당하는 아이템 가져오기를 하는 라우터
router.get("/:id", ItemController.getItem);
// 가장 비싼 아이템 가져오기를 하는 라우터
router.get("/price", ItemController.getPrice);
module.exports = router;
그러면 /price 요청을 보냈을때 원하는 결과가 나올까?
답은... NO!!!
왜냐하면 /:id에서 /밑에 오는건 다 id라고 인식하기 때문에 /price에서 price를 id로 인식하게 된다. 그래서 앞에 "/item/:id" 이런식으로 명시해주어야한다(혼동이 없도록).
const express = require("express");
const router = express.Router();
const ItemController = require("../controllers/itemController");
// 아이템 전부 가져오기를 하는 라우터
router.get("/", ItemController.getItems);
// 해당하는 아이템 가져오기를 하는 라우터
router.get("/item/:id", ItemController.getItem);
// 가장 비싼 아이템 가져오기를 하는 라우터
router.get("/price", ItemController.getPrice);
module.exports = router;