Node.js

[Node.js] for MacOS / VSCdoe + express + mysql + CRUD 예제

dev.mk 2022. 6. 5. 16:45
반응형

개요 

- Node.js의 Express 프레임 워크로 MySQL에 연동해서 서버를 구축

구축방법

 - Express 웹 서버 실행.

 - MySQL 데이터베이스 Configuration 설정

 - School 라는 샘플 모델 생성 후 컨트롤러 작성

 - CRUD 작업을 처리하기 위한 routes를 정의

 

1. 테이블 생성하기

CREATE TABLE `school_tb` (
  `id` int(11) NOT NULL,
  `nm` varchar(100) DEFAULT NULL,
  `age` varchar(100) DEFAULT NULL,
  `class` varchar(100) DEFAULT NULL,
  `grade` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`seq`)
)

 

 

2. 편한 방법으로 프로젝트 폴더 생성하기 

// mkdir로 생성해도 된다.

3. 프로젝트 폴더에서 npm init 실행

npm init

엔터를 계속 치면  프로젝트 내부에 package.json 파일이 생성된다.

 

4.  Express, mysql, body-parser 모듈을 설치

npm install express mysql body-parser --save

package-lock.json 파일이 생성되고 안에 의존성관련 내용들이 있다.

 

5. Express 웹 서버  세팅

server.js 파일을 생성 후 내용을 입력한다. 

const express = require("express");
const bodyParser = require("body-parser");

const app = express();

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

app.get("/", (req, res)=>{
    res.json({message: "Hello Node!"});
});

// 포트넘버 설정
app.listen(3000, ()=>{
    console.log("Server is running on port 3000.");
})

- Express, bodyParser 모듈 import. (Express: Restapi 구축을 위한 프레임워크 / Body-parser: request를 분석하고, routes에 엑세스 해야 하는 req.body 개체를 만들기 위해 사용)

- express app을 만든다음 app.use()를 사용해서 body-parser 미들웨어 추가

- 테스트 하기 쉽게 간단한 get 경로 정의

- 포트 3000에서 request 요청 수신

 

6. 실행 테스트

- 터미널 실행 테스트

//노드 실행
node server.js

//결과 console.log
Server is running on port 3000.

 

- 브라우저 실행 테스트

 http://localhost:3000/  

//출력 확인
{"message":"Hello Node!"}

 

7.MySQL configuration 작성 및 연동

- app/config 폴더를 생성후 안에 db.config.js파일을 생성한다. 그리고 데이터베이스 계정 접속 정보 내용을 추가한다. 

module.exports = {
    HOST: "localhost",
    USER: "root",
    PASSWORD: "1234",
    DB: "study"
};

 

8. model 정의

- app/model 폴더를 생성후  school.model.js 파일을 생성한다. 이 파일에는 학급 객체에 대한 생성자를 정의하고, 데이터베이스 연결을 사용해서 CRUD 기능일 실행한다.

 

작성할 CURD Function

1. 새 학생 생성

2. id로 학생 테이블 조회

3. 전체 테이블 조회

4. id로 학생 데이터 업데이트

5. id로 학생 데이터 삭제

6. 전체 고객 데이터 삭제

school.model.js 작성

const sql = require("./db.js");

//생성자 
const School = function(school){
    this.nm = school.nm;
    this.age = school.age;
    this.grade = school.grade;
    this.class = school.class;
};

// school 인서트
School.insert = (newSchool, result)=>{
    sql.query("INSERT INTO school SET ?", newSchool, (err, res)=>{

        if(err){
            console.log("error: ", err);
            result(err, null);
            return;
        }

        console.log("Insert school: ",{id:res.inseertId, ...newSchool });
        result(null, {id: res.inseertId, ...newSchool});
    });
};

// school id로 조회
School.findOne = (schoolID, result)=>{
    
    console.log("::::findOne "+schoolID);
    console.log("::::result "+result);

    sql.query('SELECT * FROM school WHERE id = ?',schoolID, (err, res)=>{
        if(err){
            console.log("error: ", err);
            result(err, null);
            return;
        }

        if(res.length){
            console.log("found school: ", res[0]);
            result(null, res[0]);
            return;
        }

        // 결과가 없을 시 
        result({kind: "not_found"}, null);
    });
};

// school 전체 조회
School.getAll = result =>{
    sql.query('SELECT * FROM school ', (err, res)=>{

        if(err){
            console.log("error: ", err);
            result(err, null);
            return;
        }

        console.log("school: ", res);
        result(null, res);
    });
};

// school id로 수정
School.update = (id, school, result)=>{


    console.log("::::update "+id);
    console.log("::::school "+school);

    sql.query('UPDATE school SET nm = ?, age = ?, grade = ?, class = ? WHERE id = ?', 
    [school.age, school.grade, school.class, id], (err, res)=>{
        if(err){
            console.log("error: ", err);
            result(err, null);
            return;
        }

        if(res.affectedRows ==0){
            // id 결과가 없을 시 
            result({kind: "not_found"}, null);
            return;
        }

        console.log("update school: ", {id:id, ... school});
        result(null, {id:id, ...school});
    });
};

// school id로 삭제
School.remove = (id, result)=>{

    console.log("::::remove "+id);
    console.log("::::result "+result);

    sql.query('DELETE FROM school WHERE id = ?',id, (err, res)=>{
        if(err){
            console.log("error: ", err);
            result(err, null);
            return;
        }

        if(res.affectedRows ==0){
            // id 결과가 없을 시 
            result({kind: "not_found"}, null);
            return;
        }

        console.log("deleted school with id: ", id);
        result(null, res);
    });
};

// school 전체 삭제
School.removeAll = result =>{
    sql.query('DELETE FROM school',(err, res)=>{
        if(err){
            console.log("error: ", err);
            result(err, null);
            return;
        }

        if(res.affectedRows ==0){
            // id 결과가 없을 시 
            result({kind: "not_found"}, null);
            return;
        }

        console.log('deleted ${res.affectedRows} school ');
        result(null, res);
    });
};

module.exports = School;

 

 

9.Routes 정의

HTTP 요청(GET, POST, PUT, DELETE)을 받았을 때 어떻게 응답할지 route 정의하는 것

  • /school: GET, POST, DELETE
  • /school/:schoolID: GET, PUT, DELETE

app/routes 폴더 생성하고 school.routes.js 파일을 작성한다. 

module.exports = app =>{
    const school = require("../controllers/school.controller.js");

    // 인서트 
    app.post("/school", school.insert);

    // 전체 조회 
    app.get("/school", school.findAll);

    // id로 조회
    app.get("/school/:schoolId", school.findOne);

    // id로 수정
    app.put("/school/:schoolId", school.update);

    // id로 삭제
    app.delete("/school/:schoolId", school.delete);

    // 전체 삭제
    app.delete("/school", school.deleteAll);

};

작성한 routes.js 파일을 server.js에 포함시킨다.

server.js

const express = require("express");
const bodyParser = require("body-parser");

const app = express();

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

app.get("/", (req, res)=>{
    res.json({message: "Hello Node!"});
});

require("./app/routes/school.routes.js")(app);

// 포트넘버 설정
app.listen(3000, ()=>{
    console.log("Server is running on port 3000.");
})

 

 

10. Controller 작성

app/controller 폴더를 생성하고 school.controller.js 파일을 작성한다. 컨트롤레 안에 CRUD function을 구현할 것

const School = require("../models/school.model.js");

// 새 객체 생성
exports.insert = (req,res)=>{
    if(!req.body){
        res.status(400).send({
            message: "Content can not be empty!"
        });
    };

    const school = new School({
        nm: req.body.nm,
        age: req.body.age,
        grade: req.body.grade,
        class: req.body.class
    });

    // 데이터베이스에 저장
    School.insert(school, (err, data) =>{
        if(err){
            res.status(500).send({
                message:
                err.message || "Some error occured while creating th School."
            });
        }else {
          res.send("저장을 성공 하였습니다.");
        }
    })
};

// 전체 조회 
exports.findAll = (req,res)=>{
    School.getAll((err, data) => {
        if (err)
          res.status(500).send({
            message:
              err.message || "Some error occurred while retrieving school."
          });
        else res.send(data);
      });
};

// id로 조회
exports.findOne = (req,res)=>{
    School.findOne(req.params.schoolId, (err, data) => {
        if (err) {
          if (err.kind === "not_found") {
            res.status(404).send({
              message: `Not found School with id ${req.params.schoolId}.`
            });
          } else {
            res.status(500).send({
              message: "Error retrieving School with id " + req.params.schoolId
            });
          }
        } else res.send(data);
      });
};

// id로 갱신
exports.update = (req,res)=>{
    // Validate Request
  if (!req.body) {
    res.status(400).send({
      message: "Content can not be empty!"
    });
  }

  School.update(
    req.params.schoolId,
    new School(req.body),
    (err, data) => {
      if (err) {
        if (err.kind === "not_found") {
          res.status(404).send({
            message: `Not found School with id ${req.params.schoolId}.`
          });
        } else {
          res.status(500).send({
            message: "Error updating School with id " + req.params.schoolId
          });
        }
      } else res.send(data);
    }
  );
};

// id로 삭제
exports.delete = (req,res)=>{
    School.remove(req.params.schoolId, (err, data) => {
        if (err) {
          if (err.kind === "not_found") {
            res.status(404).send({
              message: `Not found School with id ${req.params.schoolId}.`
            });
          } else {
            res.status(500).send({
              message: "Could not delete School with id " + req.params.schoolId
            });
          }
        } else res.send({ message: `School was deleted successfully!` });
      });
};

// 전체 삭제
exports.deleteAll = (req,res)=>{
    School.removeAll((err, data) => {
        if (err)
          res.status(500).send({
            message:
              err.message || "Some error occurred while removing all school."
          });
        else res.send({ message: `All School were deleted successfully!` });
      });
};

 

11. API 테스트 (with postman)

VS code 터미널에서 다음 명령어를 입력해서 실행한다.

 node server.js   // npm start 도 가능.

 

#서버 구동시 아래의 에러 발생시 해결방법

Error: listen EADDRINUSE: address already in use :::3000

 

찾기

lsof -i :포트번호

ex)  lsof -i :3000 

 

//포트 목록이 나온다.

COMMAND  PID  USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME

node    2309 devmk   23u  IPv6 0xd4b4f63f02931517      0t0  TCP *:hbci (LISTEN)

 

kill하기 (pid 입력)

kill -9 PID번호

ex) kill -9 2309

 

PID입력하여 비정상으로 종료된 중복 포트를 제거한다.

 

다시 서버를 구동하면 아래의 메세지가 출력된다면 정상이다.

 

- POST /school  인서트

 

- GET /school  전체 칼럼 조회

 

- GET /school/:id 단건조회

 

- PUT /school/:id 단건수정

 

- DELETE /school/:id 단건삭제

 

- DELETE /school/ 전체삭제

 

 

 

본문의 출처

https://expressjs.com/ko/

https://1-day-1-coding.tistory.com/51

반응형