ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Node.js] for MacOS / VSCdoe + express + mysql + CRUD 예제
    Node.js 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

    반응형

    댓글

Designed by Tistory.