[Node.js] MVC(Model View Controller)

태연·2025년 2월 17일
0

공부

목록 보기
4/4

MVC란?

소프트웨어 설계와 관련된 디자인 패턴
MVC를 이용하는 웹 프레임워크

  • PHP
  • Django
  • Express
  • Angular 등

디자인 패턴이란? 상황에 따라 자주 쓰이는 설계 방법을 정리한 코딩 방법론

MVC의 장단점

장점

  • 패턴들을 구분해 개발
  • 유지보수 용이
  • 유연성 높음
  • 확장성 높음
  • 협업에 용이

단점

  • 완벽한 의존성 분리가 어려움
  • 설계 단계 복잡
  • 설계 시간 오래걸림
  • 클래스(단위)가 많아짐

여기서 완벽한 의존성 분리가 어려운 이유는 모델과 뷰 사이는 컨트롤러를 통해서 소통하기 때문에 완벽하게 의존성이 분리될 수 없기 때문이다.

MVC 흐름

  • Model: 데이터 처리
  • View: 사용자에게 보여지는 부분인 UI 관련된 것들을 처리하는 부분
  • Controller: View와 Model을 연결해주는 부분

view, browser는 프론트이고 나머진 다 백엔드

MVC 패턴 폴더 구조


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 Error

404 에러는 클라이언트가 잘못된 주소로 접속했을때 발생

app.get('*', (req, res) => {
	res.render('404');
});
  • 맨 마지막 라우트로 선언
  • *: 그 외 나머지 주소는 모두 잘못된 요청임을 사용자에게 알려야함
  • 클라이언트가 올바르지 않은 주소로 요청 시 Error 페이지 렌더링

주의할 점

만약 라우터 파일이 다음과 같이 되어있다고 하자

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;
profile
어서와

0개의 댓글