Home 미니 블로그 만들기 - 04
Post
X

미니 블로그 만들기 - 04

서버 구현

미니 블로그의 글, 댓글 데이터를 관리할 서버를 구현해보겠습니다.

server 폴더를 만들고 npm init을 실행하여 npm을 사용할 수 있는 초기 환경을 설정합니다.


express + MVC

참고 글 : MVC 패턴

참고 글을 토대로 MVC 패턴을 활용해 구현해보겠습니다.

View 부분은 앞서 구현한 React를 활용하므로 Router, Controller, Model을 구현해보겠습니다.

  • 폴더 구성

    client

    src

    component

    ui

    server

    src

    config

    controllers

    models

    routes


body-parser 설정

server 폴더app.js 파일을 만들어 작성합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// app.js
import express from "express";
import bodyParser from "body-parser";
import "dotenv/config";

const app = express();

// 미들웨어
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

// 3000 포트로 서버 오픈
app.listen(3000, () => {
  console.log("express server on port 3000");
});

Router 설정

Routes 폴더route_post.js 파일을 만들어 express router를 작성합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
import express from "express";
import ctrl from "../controllers/controller_post.js";

const router = express.Router();

router.get("/post", ctrl.getPost); // 전체 글 조회
router.get("/post/:id", ctrl.getPostById); // 특정 글 조회
router.get("/comment/:id", ctrl.getComment); // 댓글 조회

router.post("/post", ctrl.addPost); // 글 추가
router.post("/comment/:id", ctrl.addComment); // 댓글 추가

export default router;

서버 파일인 app.js와 라우터 파일 route_post.js 파일을 미들웨어로 연결합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// app.js
import express from "express";
import bodyParser from "body-parser";
import "dotenv/config";
import postRouter from "./src/routes/route_post.js";

const app = express();

// Middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

// router
app.use("/board", postRouter);

app.listen(5000, () => {
  console.log("Server On");
});

DB 테이블 생성

먼저 기존에 data.json 파일에 작성해둔 글, 댓글 데이터를 기반으로 데이터 모델링을 해보겠습니다.

단계별 산출물(명세서)들을 간단하게 작성해보겠습니다.

  • 개념적 데이터 모델링

    • 개체 명세서

      mini-entity

    • 관계 명세서

      mini-relation

  • 논리적 데이터 모델링

    • 릴레이션 스키마

      mini-relation-schema

    • 테이블 명세서

      mini-table

    • 최종 ER 다이어그램

      mini-erd

  • 물리적 데이터 모델링

    Mysql에 EERD 모델을 만들어서 테이블을 생성합니다.

    mini-eerd


생성한 테이블에 데이터 추가

data.json 파일에 작성해둔 글, 댓글 데이터를 생성한 테이블에 추가해보겠습니다.

client 폴더의 data.json 파일을 server 폴더로 가져와 처리하겠습니다.

  • mysql2/promise 모듈의 createPool을 활용해 생성한 테이블을 연동해보겠습니다.

    참고 글 : Mysql2

  • ES 모듈에서 json파일을 import해서 사용할 떄는 assert{ type: "json" }을 붙여야만 모듈이 정상적으로 작동합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import mysql from "mysql2/promise";
import data from "./data.json" assert { type: "json" };
import "dotenv/config";

const pool = await mysql.createPool({
  host: process.env.DB_HOST, //실제로 연결할 데이터베이스의 위치
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: "posts", //데이터베이스 이름
  port: 3306,
  connectionLimit: 30,
});

const conn = await pool.getConnection(async (conn) => conn);

data.forEach(async (post, i) => {
  let { id: post_id, title, content: post_content, comments } = post;

  try {
    let [rows] = await conn.query(
      "INSERT INTO post (post_id, title, content) VALUES (?, ?, ?)",
      [post_id, title, post_content]
    );

    return rows;
  } catch (err) {
    console.log(err);
  } finally {
    conn.release();
  }

  comments.forEach(async (comment, i) => {
    let { id: comment_id, content: comment_content } = comment;

    try {
      let [rows] = await conn.query(
        "INSERT INTO comment (comment_id, content, post_id) VALUES (?, ?, ?)",
        [comment_id, comment_content, post_id]
      );

      return rows;
    } catch (err) {
      console.log(err);
    } finally {
      conn.release();
    }
  });
});

Controller 설정

controllers 폴더controller_post.js 파일을 만들어 작성하겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import postStorage from "../models/model_post.js";

export default {
  getPost: async (req, res) => {
    const data = await postStorage.getPosts();

    res.json(data);
  },

  getPostById: async (req, res) => {
    let postId = req.params.id;

    const data = await postStorage.getPostById(postId);

    res.json(data[0]);
  },
  addPost: async (req, res) => {
    let { title, content } = req.body;

    const data = await postStorage.addPost(title, content);

    res.json(data);
  },
  getComment: async (req, res) => {
    let postId = req.params.id;

    const data = await postStorage.getComments(postId);

    res.json(data);
  },
  addComment: async (req, res) => {
    let postId = req.params.id;
    let content = req.body.content;

    const data = await postStorage.addComment(postId, content);

    res.json(data);
  },
};

Models 설정

Model은 Controller로 부터 요청을 받아 DB에 접근해 CRUD 로직을 처리합니다.

models 폴더model_post.js 파일을 만들고 작성해보겠습니다.

  • 위에서 데이터 추가할 때 작성한 mysql2/promise 모듈로 커넥션 풀을 생성하고 연동하는 부분은 config 폴더에 따로 빼주고 import해서 사용하겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import conn from "../config/db_pool.js";

class postStorage {
  static async getPosts() {
    try {
      const [rows] = await conn.query("SELECT * FROM post");

      return rows;
    } catch (err) {
      console.log(err);
    } finally {
      conn.release();
    }
  }

  static async getPostById(postId) {
    try {
      const [rows] = await conn.query("SELECT * FROM post WHERE post_id = ?", [
        postId,
      ]);

      return rows;
    } catch (err) {
      console.log(err);
    } finally {
      conn.release();
    }
  }

  static async addPost(title, content) {
    try {
      const [rows] = await conn.query(
        "INSERT INTO post (title, content) VALUE (?,?)",
        [title, content]
      );

      return rows;
    } catch (err) {
      console.log(err);
    } finally {
      conn.release();
    }
  }

  static async getComments(postId) {
    try {
      const [rows] = await conn.query(
        "SELECT (content) FROM comment WHERE post_id = ?",
        [postId]
      );

      return rows;
    } catch (err) {
      console.log(err);
    } finally {
      conn.release();
    }
  }

  static async addComment(postId, content) {
    try {
      const [rows] = await conn.query(
        "INSERT INTO comment (content, post_id) VALUE (?, ?)  ",
        [content, postId]
      );

      return rows;
    } catch (err) {
      console.log(err);
    } finally {
      conn.release();
    }
  }
}

export default postStorage;

결과 테스트

  • post 테이블에서 글 번호, 제목, 내용 데이터 모두 얻어오기

    mini-postman-01

    mini-postman-02

  • comment 테이블에서 주어진 글 번호에 맞는 댓글 데이터 모두 얻어오기

    mini-postman-03

    mini-postman-04

응답이 잘 오는 것을 확인했습니다.

다음 포스트에서는 React에서 Server에 요청해서 받은 데이터들로 출력하도록 구현해보겠습니다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.