백앤드/Node.js

[포스코x코딩온] 웹개발자 입문 과정 6주차 | MVC MySQL 연동

영최 2023. 4. 8. 02:26
728x90

1.Node.js -MySQL 연결

 이전까지의 MVC 포스팅에서는 MySQL을 연동하지 않았다.

2023.04.05 - [백앤드/Node.js] - [포스코x코딩온] 웹개발자 입문 과정 6주차 | MVC

 

[포스코x코딩온] 웹개발자 입문 과정 6주차 | MVC

1.MVC란? 한마디로 소프트 웨어 디자인 패턴이다. *디자인 패턴 : 상황에 따라 자주 쓰이는 설계 방법을 정리한 코딩 방법론 Model View Controller의 약자이다. 가. MVC를 이용한 웹프레임 워크 종류 MVC를

jayoung977.tistory.com

 이번 포스팅 부터는 MySQL을 연동하여 데이터 베이스에서 데이터를 가져온다.

 먼저 MySQL을 연동을 위해서는 프로젝트 파일에서 MySQL패키지를 설치해야한다.

 

 가. MySQL패키지 설치

cd 프로젝트 경로
npm install mysql

 이후 프로젝트 내 package.json의 "dependencise"에서 mysql설치를 확인한다.

 

 나. MySQL에서 DB 가져오는 방법

   1) DB 연결 (model/ Visitor.js)

//1. mysql 불러옴
const mysql = require("mysql");

//2. database 연결
const conn = mysql.createConnection({
  host: "localhost", // databse 가 설치된 ip 주소
  user: "user", // 데이터베이스 접속 계정명
  password: "1234", // 데이터베이스 접속 비번
  database: "codingon", // 사용할 데이터베이스 이름
});

      먼저 모델 단에서 mysql을 불러온 뒤 아래 처럼 database를 연결해준다.

      이때 user로 root 계정을 사용하지 않는 이유는 mysql이

      외부에서 root 계정으로 접속하는 것을 허용하지 않기 때문이다.

      이때문에 user라는 새로운 계정을 만들어서 외부에서 접근할 수 있도록 해야하는데

      아래가 계정을 생성하는 코드이다.

   2) user 계정 생성 (sql문)

-- 생성된 계정 정보 확인
SELECT * FROM mysql.user;
-- 사용자 추가 
CREATE USER 'user'@'%' IDENTIFIED WITH mysql_native_password BY '1234';
-- user 계정 권한 부여
GRANT ALL PRIVILEGES ON *.* TO 'user'@'%' WITH GRANT OPTION;
-- 현재 사용중인 mysql 캐시 지우고 새로 적용
FLUSH PRIVILEGES;

      이 때 CREATE USER 'user'@'%' IDENTIFIED BY '1234';  를 사용하는 대신

      CREATE USER 'user'@'%' IDENTIFIED WITH mysql_native_password BY '1234' ; 

      를 사용하는 이유는 mysql 버전이 바뀌면서 비밀번호 해싱방식이 변경되었고,

      연동하기 위해서는 예전 해싱방식인 mysql_native_password를 사용해야한다고 한다.

   3) CRUD (model/ Visitor.js) 

//(2) READ: 전체 조회   GET /visitor
exports.getVisitors = (callback) => {
  const sql = "SELECT * FROM visitor;";
  conn.query(sql, (err, rows) => {
    if (err) {
      throw err;
    }
    callback(rows);
  });
};

//(3) CREATE: 생성  POST /visitor/write
exports.postVisitor = (data, callback) => {
  const sql = `insert into visitor(name, comment) values('${data.name}', '${data.comment}');`;
  conn.query(sql, (err, rows) => {
    if (err) {
      throw err;
    }
    callback(rows.insertId);
  });
};

//(4) DELETE: 삭제 DELETE /visitor/delete

exports.deleteVisitor = (id, callback) => {
  const sql = `delete from visitor where id=${id};`;
  conn.query(sql, (err, rows) => {
    if (err) {
      throw err;
    }
    callback(true);
  });
};

//(5) READ: 하나 조회(수정을 위한)  GET /visitor/get
exports.getVisitor = (id, callback) => {
  const sql = `select * from visitor where id=${id};`;
  conn.query(sql, (err, rows) => {
    if (err) {
      throw err;
    }
    callback(rows[0]);
  });
};

//(5)-4 UPDATE: 수정  PATCH  /visitor/edit
exports.patchVisitor = (data, callback) => {
  const sql = `update visitor set  name='${data.name}', comment='${data.comment}' where id=${data.id};`;
  conn.query(sql, (err, rows) => {
    if (err) {
      throw err;
    }
    callback();
  });
};

    모델 단에서 CRUD는 위와 같고 아래처럼 동작하기 위해서는

    클라이언트단(ejs) 및 라우터 부분을 수정해야한다.

   •Create(생성) - 작성후[등록] 버튼 누르면 DB저장된다
   •Read(읽기) - [등록]내용이 아래Table 에 [바로]보인다.
   •Update(갱신) - [수정]누르면 방명록 수정가능하다.
   •Delete(삭제)  - [삭제]누르면 방명록이 삭제된다.

  주석에서의 괄호 번호 (ex.(2))는 아래 코드에서 같은 번호로 주석이 있을 경우

  동일한 부분 (ex.전체 조회) 을 담당한다.

 

 

2.클라이언트단,  라우터,  컨트롤러 수정 

 우선 프로젝트 구조는 아래와 같다.

 다 다루지는 않을 것이고, 주요한 부분인 클라이언트단, 라우터부분, 컨트롤러 부분만

 다뤄본다. 

프로젝트 구조

 가. 클라이언트단 (views/visitor.ejs)

   1) 생성 POST /visitor/write 폼 [등록] 버튼 클릭시 테이블 데이터 추가

      const tbody = document.querySelector("tbody");
      const buttonGroup = document.querySelector("#button-group");

      //(3) 생성 POST /visitor/write 폼 [등록] 버튼 클릭시 테이블 데이터 추가
      function createVisitor() {
        const form = document.forms["visitor-form"];

        axios({
          method: "POST",
          url: "/visitor/write",
          data: {
            name: form.name.value,
            comment: form.comment.value,
          },
        }).then((res) => {
          const newVisitor = `
            <tr id="tr_${res.data.id}">
              <td>${res.data.id}</td>
              <td>${res.data.name}</td>
              <td>${res.data.comment}</td>
              <td><button type="button" onclick="editVisitor(${res.data.id})">수정</button></td>
              <td><button type="button" onclick="deleteVisitor(this,${res.data.id})">삭제</button></td>
            </tr>`;

          // insertAdjacentHTML(): 특정 요소에 html 추가 , jQuery.append()와 동일
          // vs. innerHTML: 내부 코드 덮어씌움
          tbody.insertAdjacentHTML("beforeend", newVisitor);
        });
      }

   2) 삭제 DELETE /visitor/delete

      //(4) 삭제 DELETE /visitor/delete
      function deleteVisitor(obj, id) {
        console.log("obj", obj);
        console.log("id", id);
        //alert는 확인버튼만 confirm은 확인, 취소 버튼 2개
        // !false = true
        if (!confirm("정말 삭제하시겠습니까?")) {
          return;
        }

        // confirm에서 [확인] 버튼 클릭 시 실행할 코드
        axios({
          method: "DELETE",
          url: "/visitor/delete",
          data: {
            id: id, 
          },
        }).then((res) => {
          document.getElementById(`tr_${id}`).remove();

          //삭제하는 다른 방법
          //obj.parentElement.parentElement.remove();
          //obj.closest(`#tr_${id}`).remove(); //가장 가까운 선택자 찾아감
        });
      }

   3)조회(수정을 위한)  GET /visitor/get

      //(5) 조회(수정을 위한)  GET /visitor/get
      function editVisitor(id) {
        console.log(id);
        axios({
          method: "GET",
          url: "/visitor/get",
          params: {
            id: id,
          },
        }).then((res) => {
          //(5)-1 클릭한 값 조회
          console.log(res.data); //rows[0] { id: 10, name: '아리수', comment: '22' }

          //(5)-2 form input 값 넣기
          const form = document.forms["visitor-form"];
          form.name.value = res.data.name; //input[name='name']에 value 설정
          form.comment.value = res.data.comment; //input[name='comment']에 value 설정

          //(5)-3 [변경], [취소] 버튼 보여주기 (buttonGroup에 덮어씌움)
          const btns = `
          <button type='button' onclick='editDo(${id})'>변경</button>
          <button type='button' onclick='editCancel()'>취소</button>
          `;
          buttonGroup.innerHTML = btns;
        });
      }

   4) 수정PATCH  /visitor/edit 

      //(5)-4. PATCH  /visitor/edit [변경] 버튼 눌렀을 떄 데이터 수정
      async function editDo(id) {
        const form = document.forms["visitor-form"];
        await axios({
          method: "PATCH",
          url: "/visitor/edit",
          data: {
            id: id,
            name: form.name.value,
            comment: form.comment.value,
          },
        }).then((res) => {
          console.log(res.data);
          //(5)-4-1. 수정성공 메세지 띄우기
          alert(res.data);
          //(5)-4-2. 수정내용 반영
          const children = document.querySelector(`#tr_${id}`).children;
          // console.log(children); //[td, td, td, td, td]
          children[1].textContent = form.name.value;
          children[2].textContent = form.comment.value;
        });
      }

 

 나. 라우터 (routes/index.js)

const express = require("express");
const controller = require("../controller/Cvisitor");
const router = express.Router();
// (1) GET /
router.get("/", controller.main);

// (2) GET /visitor
router.get("/visitor", controller.getVisitors); //'s' 전체 조회

// (3) 생성 POST /visitor/write
router.post("/visitor/write", controller.postVisitor); // 하나 추가

// (4) 삭제 DELETE /visitor/delete
router.delete("/visitor/delete", controller.deleteVisitor); //하나 삭제

// (5) 조회(수정을 위한)  GET /visitor/get
router.get("/visitor/get", controller.getVisitor); //하나 조회

// (5)-4 수정  PATCH  /visitor/edit
router.patch("/visitor/edit", controller.patchVisitor); //하나 수정

module.exports = router;

 

 다. 컨트롤러(controller/Cvisitor.js)

// Comment = {getComments: ()=>{}}
const Visitor = require("../model/Visitor");

// (1) GET /
exports.main = (req, res) => {
  res.render("index");
};

// (2) 조회 GET /visitor
exports.getVisitors = (req, res) => {
  //[after] mysql 연결
  // rows -> result
  Visitor.getVisitors((result) => {
    console.log("(2).Cvisitor.js >> ", result);
    //[{},{}]
    res.render("Visitor", { data: result });
  });
};

// (3) 생성 POST /visitor/write
exports.postVisitor = (req, res) => {
  console.log("(3)-1. Cvisitor.js >>", req.body);

  Visitor.postVisitor(req.body, (result) => {
    console.log("(3)-2. Cvisitor.js >>", result); //model 코드에서 데이터를 추가한 결과인 row.insertId
    res.send({ id: result, name: req.body.name, comment: req.body.comment });
  });
};

// (4) 삭제 DELETE /visitor/delete
exports.deleteVisitor = (req, res) => {
  console.log("(4)-1. Cvisitor.js >>", req.body); //{id:n}
  Visitor.deleteVisitor(req.body.id, (result) => {
    console.log("(4)-2. Cvisitor.js >>", result);
    res.send("삭제 성공!!");
  });
};

// (5) 조회(수정을 위한)  GET /visitor/get
exports.getVisitor = (req, res) => {
  console.log("(5)-1. Cvisitor.js >>", req.query); //{id:n}

  Visitor.getVisitor(req.query.id, (result) => {
    console.log("(5)-2. Cvisitor.js >>", result); //model 코드에서 callback에 넘긴 rows[0]
    res.send(result); //{ id: 10, name: '아리수', comment: '22' }
  });
};

// (5)-4 수정  PATCH  /visitor/edit
exports.patchVisitor = (req, res) => {
  console.log("(5)-4-1. Cvisitor.js >>", req.body);
  Visitor.patchVisitor(req.body, () => {
    res.send("수정 성공!");
  });
};

 

 

3. 전체 코드

https://github.com/jayoung977/web/tree/main/BackEnd/20230405-20230406/13_mvc_mysql

728x90