본문 바로가기

Node.js

Node.js(10) - express를 활용한 게시판 구현(CRUD) 및 Router 나누기

728x90
반응형

1) Node.js

   1-1) express를 활용한 게시판 구현(CRUD)

   1-2) Router 나누기

   1-3) 게시판 코드 실습 - Router 나누기

 

 

 

 

1) Node.js

1-1) express를 활용한 게시판 구현(CRUD)

"프레임워크"와 "라이브러리"의 차이
express는 실제로 "마이크로 프레임워크"지만 "라이브러리"에 가깝다고 볼 수 있다!


1. 프레임워크의 특징 : 디렉토리가 정해져 있음!

2. 라이브러리의 특징 : 디렉토리 구조가 없음

3. 프레임워크와 라이브러리의 공통점 : 둘 다 다른 사람들이 만들어 놓은 것을 가져다 쓰는 개념이다!

(단, 가져와서 쓸 때, 즉 사용법이 다르다는 차이가 있다!)

 

$ npm init -y #package.json 파일 생성
$ npm install express nunjucks #외장모듈인 express, nunjucks 설치 및 node_modules 디렉토리 생성

 

server.js

const express = require("express");
const nunjucks = require("nunjucks");
const app = express();

const items = [
  {
    subject: "첫번째 게시물",
    content: "content",
    name: "name...",
  },
];

app.use(express.urlencoded({ extended: false }));

app.set("view engine", "html");
nunjucks.configure("views", {
  express: app,
});

app.get("/", (req, res) => {
  res.render("index.html");
});

app.get("/list", (req, res) => {
  res.render("board/list.html", { items }); // path.join
});

app.get("/write", (req, res) => {
  res.render("board/write.html");
});

app.post("/write", (req, res) => {
  const { content, subject, name } = req.body;
  items.push({ content, subject, name });
  res.redirect(`/view?index=${items.length - 1}`);
});

app.get("/view", (req, res) => {
  const { index } = req.query;
  const item = {
    ...items[index],
    index,
  };
  res.render("board/view.html", { item });
});

app.get("/modify", (req, res) => {
  const { index } = req.query;
  const item = {
    ...items[index],
    index,
  };

  res.render("board/modify.html", { item });
});

app.post("/modify", (req, res) => {
  const { index, subject, content, name } = req.body;
  items[index].subject = subject;
  items[index].content = content;
  items[index].name = name;

  // 바로 위의 코드들을 간략히 표현한 코드(rest 활용)
  // const { index, ...rest } = req.body;
  // items[index] = rest;

  res.redirect(`/view?index=${index}`);
});

app.get("/delete", (req, res) => {
  const { index } = req.query;
  items.splice(index, 1);
  res.redirect("/list");
});

app.listen(3000, () => {
  console.log("server start");
});

 

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>hello world!</h1>
    <a href="/list">리스트 바로가기</a>
  </body>
</html>

 

views/board

list.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <table>
      <tr>
        <th>번호</th>
        <th>제목</th>
        <th>작성자</th>
        <th>작성일</th>
        <th>조회수</th>
      </tr>
      {% for item in items %}
      <tr>
        <td>{{loop.index - 1}}</td>
        <td><a href="/view?index={{loop.index - 1}}">{{item.subject}}</a></td>
        <td>{{item.name}}</td>
        <td>2022-12-20</td>
        <td>0</td>
      </tr>
      {% endfor %}
    </table>
    <a href="/write">글작성</a>
  </body>
</html>

 

write.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h2>write</h2>
    <form method="post" action="/write">
      <ul>
        <li>제목 : <input type="text" name="subject" /></li>
        <li>작성자 : <input type="text" name="name" /></li>
        <li>
          내용 : <br />
          <textarea name="content"></textarea>
        </li>
      </ul>
      <button type="submit">submit</button>
    </form>
  </body>
</html>

 

view.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h2>view page</h2>
    <ul>
      <li>제목 : {{item.subject}}</li>
      <li>작성자 : {{item.name}}</li>
      <li>내용 : {{item.content}}</li>
    </ul>

    <a href="/list">목록가기</a>
    <a href="/modify?index={{item.index}}">수정</a>
    <a href="/delete?index={{item.index}}">삭제</a>
  </body>
</html>

 

modify.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h2>modify page</h2>
    <form method="post" action="/modify">
      <input type="hidden" name="index" value="{{item.index}}" />
      <ul>
        <li>
          제목 : <input type="text" name="subject" value="{{item.subject}}" />
        </li>
        <li>
          작성자 : <input type="text" name="name" value="{{item.name}}" />
        </li>
        <li>
          <textarea name="content">
                      {{item.content}}
                  </textarea
          >
        </li>
      </ul>
      <button type="submit">submit</button>
    </form>
  </body>
</html>

 

 

 

 

1-2) Router 나누기("[x]" 현재는 구현 안 한 directory를 의미함)

/root
|-- [x]models
|-- middlewares
|-- controllers
|-- [x]services
|-- routes
|-- public
|-- views
|-- server.js

app.get('/', (req, res) => {});


Router 안에 들어간 "callback(미들웨어)" 함수는 "요청 객체"와 "응답 객체"를 주는 함수들이다!!

const modifyController = (req, res) => {
  const index = req.query.index;
  // 데이터 조작
  items[index].subject = ...;
  res.render('modify.html');
}
app.get('/modify', modifyController);

 

app.get('/', (req, res) => {});
app.get('/list', (req, res) => {});
app.get('/write', (req, res) => {});
app.get('/view', (req, res) => {});
app.get('/modify', (req, res) => {});
app.get('/delete', (req, res) => {});

 

const express = require('express');
const router = express.Router();


게시판이 3가지 형태(board, notice, gallery)가 있다고 가정함!
/board/list
/board/write
/board/view
/board/modify
/board/delete

/notice/list
/notice/write
/notice/view
/notice/modify
/notice/delete

/gallery/list
/gallery/write
/gallery/view
/gallery/modify
/gallery/delete


$ npm init -y
$ npm install express

 

app.use(
  "/board/",
  router.get("/list", (req, res) => {
    res.send("/ page");
  })
)

// 위의 코드의 동작 방식 표현
if (req.path.include("/board")) {
  if (req.method === "GET" && req.path="/board/list") {
    res.send("/ page");
  }
}


app.get('/', (req, res) => {
  res.send('hello world');
})

// 위의 코드의 동작 방식 표현
if (req.method === "GET" && req.path === "/") {
  res.send('hello world');
}

 

 

server.js

const express = require("express");
const app = express();
// const board = require("./routes/board.route");
// const notice = require("./routes/notice.route");
// const gallery = require("./routes/gallery.route");
const router = require("./routes");
const nunjucks = require("nunjucks");
const { login } = require("./middlewares/index");

app.set("view engine", "html");
nunjucks.configure("views", {
  express: app,
});

app.use(express.static("public"));
app.use(express.urlencoded({ extended: false }));
app.use(login);

/*
// /board/list
app.get("/board/list", (req, res) => {
  res.send("/ page");
});
*/

/*
{
    method: "get",
    path: "list",
    callback: (req, res) => {
        res.send("/ page")
    }
}
*/

/*
// localhost:3000/board/list
router.get("/board/list", (req, res) => {
  res.send("/ page");
}); // 등록형태(router를 쉽게 만들어 줄 수 있는 객체임을 의미함!)
*/

// app.use(router); // 앞서 router를 통해 등록한 것이 실제 실행은 여기서 이루어짐!

/*
router.get("/list", (req, res) => {
  res.send("/ list");
});

router.get("/write", (req, res) => {
  res.send("/ write");
});

router.get("/modify", (req, res) => {
  res.send("/ modify");
});
*/

// app.use("/board", board); // board/list, write, modify
// app.use("/notice", notice); // notice/list, write, modify
// app.use("/gallery", gallery); // gallery/list, write, modify

app.use(router);

// app.get("/", (req, res) => {
//   res.send("/ page");
// });

app.listen(3000, () => {
  console.log("server start");
});

 

routes

index.js

const express = require("express");
const router = express.Router();
const board = require("./board.route");
const notice = require("./notice.route");
const gallery = require("./gallery.route");

router.use("/board", board);
router.use("/notice", notice);
router.use("/gallery", gallery);

module.exports = router;

 

board.route.js

// router
const express = require("express");
const router = express.Router(); // {}
const controller = require("../controllers/board.controller");

router.get("/list", controller.list);

router.get("/write", controller.write);

router.get("/view", (req, res) => {
  res.send("board/ view 입니다.");
});

router.get("/delete", (req, res) => {
  res.send("board/ delete 입니다.");
});

module.exports = router;

 

notice.route.js

// router
const express = require("express");
const router = express.Router(); // {}

router.get("/list", (req, res) => {
  res.send("notice/ list 입니다.");
});

router.get("/write", (req, res) => {
  res.send("notice/ write 입니다.");
});

router.get("/view", (req, res) => {
  res.send("notice/ view 입니다.");
});

router.get("/delete", (req, res) => {
  res.send("notice/ delete 입니다.");
});

module.exports = router;

 

gallery.route.js

// router
const express = require("express");
const router = express.Router(); // {}

router.get("/list", (req, res) => {
  res.send("gallery/ list 입니다.");
});

router.get("/write", (req, res) => {
  res.send("gallery/ write 입니다.");
});

router.get("/view", (req, res) => {
  res.send("gallery/ view 입니다.");
});

router.get("/delete", (req, res) => {
  res.send("gallery/ delete 입니다.");
});

module.exports = router;

 

 

controllers

board.controller.js

const items = [];

exports.list = (req, res) => {
  res.send("list page");
};

exports.write = (req, res) => {
  res.send("write page");
};

exports.modify = (req, res) => {
  res.send("modify page");
};

 

middlewares

index.js

exports.login = (req, res, next) => {
  req.login = "web7722";
  next();
};

 

 

 

 

1-3) 게시판 코드 실습 - Router 나누기

server.js

const express = require("express");
const router = require("./routes");
const app = express();
const nunjucks = require("nunjucks");

app.set("view engine", "html");
nunjucks.configure("views", {
  express: app,
});

app.use(express.static("public"));
app.use(express.urlencoded({ extended: false }));

app.use(router);

app.get("/", (req, res) => {
  res.render("index.html");
});

app.listen(3000, () => {
  console.log("server start");
});

 

 

views(board와 notice 디렉토리를 나눠서 구현했지만 각 html의 내용이 거의 유사하므로 board만 소개하기로 함!!)

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="/css/index.css" />
    <script src="/js/index.js" type="text/javascript"></script>
  </head>
  <body>
    <h1>hello~~!!</h1>
    <a href="/board/list">board 리스트 바로가기</a>
    <a href="/notice/list">notice 리스트 바로가기</a>
  </body>
</html>

 

board

list.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <table>
      <tr>
        <th>번호</th>
        <th>제목</th>
        <th>작성자</th>
        <th>작성일</th>
        <th>조회수</th>
      </tr>
      {% for item in items %}
      <tr>
        <td>{{loop.index}}</td>
        <td>
          <a href="/board/view?index={{loop.index - 1}}">{{item.subject}}</a>
        </td>
        <td>{{item.name}}</td>
        <td>2022-12-20</td>
        <td>0</td>
      </tr>
      {% endfor %}
    </table>
    <a href="/board/write">글작성</a>
  </body>
</html>

 

write.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h2>write page</h2>
    <form method="post" action="/board/write">
      <ul>
        <li>제목 : <input type="text" name="subject" /></li>
        <li>작성자 : <input type="text" name="name" /></li>
        <li>
          내용 : <br />
          <textarea name="content"></textarea>
        </li>
      </ul>
      <button type="submit">submit</button>
    </form>
  </body>
</html>

 

view.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <ul>
      <li>제목 : {{item.subject}}</li>
      <li>작성자 : {{item.name}}</li>
      <li>내용 : {{item.content}}</li>
    </ul>

    <a href="/board/list">리스트 가기</a>
    <a href="/board/modify?index={{item.index}}">수정</a>
    <a href="/board/delete?index={{item.index}}">삭제</a>
  </body>
</html>

 

modify.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h2>modify page</h2>
    <form method="post" action="/board/modify">
      <input type="hidden" name="index" value="{{item.index}}" />
      <ul>
        <li>
          제목 : <input type="text" name="subject" value="{{item.subject}}" />
        </li>
        <li>
          작성자 : <input type="text" name="name" value="{{item.name}}" />
        </li>
        <li>
          <textarea name="content">
                      {{item.content}}
                  </textarea
          >
        </li>
      </ul>
      <button type="submit">submit</button>
    </form>
  </body>
</html>

 

 

public

css

index.css

* {
  margin: 0;
  padding: 0;
}

body {
  background: #beb;
}

 

js

index.js

alert("welcome to our board~~");

 

 

routes

index.js

const express = require("express");
const router = express.Router();
const board = require("./board.route");
const notice = require("./notice.route");

router.use("/board", board);
router.use("/notice", notice);

module.exports = router;

 

board.route.js

// router
const express = require("express");
const router = express.Router(); // {}
const controller = require("../controllers/board.controller");

router.get("/list", controller.list);
router.get("/write", controller.getWrite);
router.post("/write", controller.postWrite);
router.get("/view", controller.view);
router.get("/modify", controller.getModify);
router.post("/modify", controller.postModify);
router.get("/delete", controller.delete);

module.exports = router;

 

notice.route.js

const express = require("express");
const router = express.Router();
const controller = require("../controllers/notice.controller");

router.get("/list", controller.list);
router.get("/write", controller.getWrite);
router.post("/write", controller.postWrite);
router.get("/view", controller.view);
router.get("/modify", controller.getModify);
router.post("/modify", controller.postModify);
router.get("/delete", controller.delete);

module.exports = router;

 

 

controllers

board.controller.js

const items = [
  {
    subject: "첫번째 게시물",
    content: "content",
    name: "name...",
  },
];

exports.list = (req, res) => {
  res.render("board/list.html", { items });
};

exports.getWrite = (req, res) => {
  res.render("board/write.html");
};

exports.postWrite = (req, res) => {
  const { content, subject, name } = req.body;
  items.push({ content, subject, name });
  res.redirect(`view?index=${items.length - 1}`);
};

exports.view = (req, res) => {
  const { index } = req.query;
  const item = {
    ...items[index],
    index,
  };
  res.render("board/view.html", { item });
};

exports.getModify = (req, res) => {
  const { index } = req.query;
  const item = {
    ...items[index],
    index,
  };

  res.render("board/modify.html", { item });
};

exports.postModify = (req, res) => {
  const { index, subject, content, name } = req.body;
  items[index].subject = subject;
  items[index].content = content;
  items[index].name = name;

  // 바로 위의 코드들을 간략히 표현한 코드(rest 활용)
  // const { index, ...rest } = req.body;
  // items[index] = rest;

  res.redirect(`view?index=${index}`);
};

exports.delete = (req, res) => {
  const { index } = req.query;
  items.splice(index, 1);
  res.redirect("list");
};

 

notice.controller.js

const items = [
  {
    subject: "첫번째 게시물",
    content: "content",
    name: "name...",
  },
];

exports.list = (req, res) => {
  res.render("notice/list.html", { items });
};

exports.getWrite = (req, res) => {
  res.render("notice/write.html");
};

exports.postWrite = (req, res) => {
  const { content, subject, name } = req.body;
  items.push({ content, subject, name });
  res.redirect(`view?index=${items.length - 1}`);
};

exports.view = (req, res) => {
  const { index } = req.query;
  const item = {
    ...items[index],
    index,
  };
  res.render("notice/view.html", { item });
};

exports.getModify = (req, res) => {
  const { index } = req.query;
  const item = {
    ...items[index],
    index,
  };

  res.render("notice/modify.html", { item });
};

exports.postModify = (req, res) => {
  const { index, subject, content, name } = req.body;
  items[index].subject = subject;
  items[index].content = content;
  items[index].name = name;

  res.redirect(`view?index=${index}`);
};

exports.delete = (req, res) => {
  const { index } = req.query;
  items.splice(index, 1);
  res.redirect("list");
};

 

※ 자세한 코드는 여기 제 github 저장소(https://github.com/sangbeomhwang/board_express.git)를 참조해주시기 바랍니다.