[실습]NodeJS + EXPRESS + MySQL 을 이용한 게시판 만들기 4(MVC)

수정하기, 삭제하기 만들기

필요한 모듈 설치

RESTful 하게 만드려니 nodejs 같은 경우 _method="PUT" 를 hidden 으로 넘겨주니 인식되지 않는다. 그래서 검색해보고 아래처럼 사용해야 한다는 걸 알고 모듈을 추가설치 한다.

npm install -s method_override

소스 수정

  • app.js

    소스 상단에 require 해 주고, 중간 쯤 app.use 있는 부분(라우터 위쪽)에 소스를 추가하자.

      ...whatever...
    
      const methodOverride = require('method-override');
    
      ...whatever...
    
      app.use(methodOverride('_method'));
    
      ...whatever...
  • app/views/posts/writeForm.pug - 실습하기 3에 소스 올려 둠

수정하기

  • app/controllers/postsController.js

      ...whatever...
    
      /**
       * 글 수정 - 폼
       *
       * @param req
       * @param res
       */
      exports.getEditForm = (req, res) => {
        let id = req.params.id;
    
        postsModel.getEdit(id, (result) => {
          if (result) {
            // console.log(result);
    
            res.render('posts/writeForm', {
              title: result.subject,
              mode: 'edit',
              post: result
            });
          }
        });
      };
    
      /**
       * 글 수정 - 프로세스
       *
       * @param req
       * @param res
       */
      exports.updateProcess = (req, res) => {
        let id = req.params.id;
    
        let item = {
          'id': id,
          'name': req.body.name,
          'email': req.body.email,
          'password': req.body.password,
          'subject': req.body.subject,
          'content': req.body.content,
          'ip': req.headers['x-forwarded-for'] || req.connection.remoteAddress,
          'tags': req.body.tags
        };
    
        postsModel.updateData(item, (result) => {
          if (result) {
            // console.log(result);
            if (result.affectedRows === 1) {
              res.redirect('/posts/'+ id);
            } else {
              res.redirect('/posts/' + id + '/edit');
            }
          } else {
            res.send('<script>alert("수정 실패");history.back();</script>');
          }
        });
      };
  • app/models/postsModel.js

      ...whatever...
    
      /**
       * 글 수정 폼
       *
       * 하나의 결과값만 리턴 할 경우 자체가 JSON 형식이라 따로 JSON.parse 안해줘도 됨
       *
       * id : 게시물 번호
       * cd : 콜백 함수
       *
       * @param id
       * @param cb
       */
      exports.getEdit = (id, cb) => {
        let sql = 'SELECT `id`, `name`, `email`, `subject`, `content` FROM posts WHERE id=? LIMIT 1';
        mysqlConn.query(sql, [id], (err, results, fields) => {
          if (err) {
            console.error('Error code : ' + err.code);
            console.error('Error Message : ' + err.message);
    
            throw new Error(err);
          } else {
            cb(results[0]);
          }
        });
      };
    
      /**
       * 글 수정 프로세스
       *
       * data : 업데이트 될 데이터
       * cb : 콜백 함수. 리턴값을 컨트롤러에 돌려준다.
       *
       * @param data
       * @param cb
       */
      exports.updateData = (data, cb) => {
        // 해시된 비밀번호를 찾아온다.(현재 비밀번호와 맞는지 확인 위해)
        let sql = 'SELECT password FROM posts WHERE id=? LIMIT 1';
        mysqlConn.query(sql, [data.id], (err, results, fields) => {
          if (err) throw new Error(err);
    
          let hash_password = results[0].password;
          if (hash_password) {
            // 비밀번호가 존재할 경우 비밀번호를 비교한다.
            bcrypt.compare(data.password, hash_password, (err, result) => {
              if (err) throw new Error(err);
    
              // 결과는 true, false 로 나온다.
              if (result) {
                let sql = 'UPDATE posts SET name=?, email=?, subject=?, content=?, ip=INET_ATON(?) WHERE id=?';
                let bindParam = [
                  data.name,
                  data.email,
                  data.subject,
                  data.content,
                  data.ip,
                  data.id
                ];
                mysqlConn.query(sql, bindParam, (err, results, fields) => {
                  if (err) throw new Error(err);
    
                  cb(JSON.parse(JSON.stringify(results)));
                });
              } else {
                // 비밀번호 대조에서 결과가 틀리다면 false 를 리턴한다.
                cb(false);
              }
            });
          } else {
            // 해시된 기존 비밀번호를 찾지 못할 경우 false 를 리턴한다.
            cb(false);
          }
        });
      };

삭제하기

  • app/views/view.pug

    하단 수정 버튼 아래에 추가

      ...whatever...
    
      button.btn.red.pointer(type='button', onclick="document.getElementById('delForm').submit();") 삭제
      form(id='delForm', action='/posts/' + post.id + '?_method=DELETE', method='POST')
        input(type='password', name='password')
    
      ...whatever...
  • app/controllers/postsController.js

      /**
       * 글 삭제 - 프로세스
       *
       * @param req
       * @param res
       */
      exports.deleteProcess = (req, res) => {
        let item = {
          'id': req.params.id,
          'password': req.body.password
        };
        //console.log(item);
    
        postsModel.deleteData(item, (result) => {
          if (result) {
            if (result.affectedRows === 1) {
              res.redirect('/posts/');
            } else {
              res.redirect('/posts/' + item.id);
            }
          } else {
            res.send('<script>alert("삭제 실패");history.back();</script>');
          }
        });
      };
  • app/models/postsModel.js

      /**
       * 글 삭제 프로세스
       *
       * @param data
       * @param cb
       */
      exports.deleteData = (data, cb) => {
        // 해시된 비밀번호를 찾아온다.(현재 비밀번호와 맞는지 확인 위해)
        let sql = 'SELECT password FROM posts WHERE id=? LIMIT 1';
        mysqlConn.query(sql, [data.id], (err, results, fields) => {
          if (err) throw new Error(err);
    
          let hash_password = results[0].password;
          if (hash_password) {
            // 비밀번호가 존재할 경우 비밀번호를 비교한다.
            bcrypt.compare(data.password, hash_password, (err, result) => {
              if (err) throw new Error(err);
    
              // 결과는 true, false 로 나온다.
              if (result) {
                let sql = 'DELETE FROM posts WHERE id=?';
                mysqlConn.query(sql, [data.id], (err, results, fields) => {
                  if (err) throw new Error(err);
    
                  cb(JSON.parse(JSON.stringify(results)));
                });
              } else {
                // 비밀번호 대조에서 결과가 틀리다면 false 를 리턴한다.
                cb(false);
              }
            });
          } else {
            // 해시된 기존 비밀번호를 찾지 못할 경우 false 를 리턴한다.
            cb(false);
          }
        });
      };

느낀점

디테일하게 제작하지 못해 아쉽다.😋 (삭제시 비밀번호 창을 띄운다던지, 페이징이라던지...등등등등등...)

그래도 일단 만들어 본다는데 의의를 둔다.🤩

시간나면 더 다듬어서 공개해 보고 싶기도 하지만..🙄(먼산)

 

NodeJS든 PHP든 요즘은 어떤 모듈을 얼마나 많이 알고, 어떻게 조합하느냐에 따라 개발 속도가 상당하다는 것을 느낀다. (막간에 PhpStorm 설정한게 너무 맘에 듬)
회사 일만하다 저번 주 시간이 좀 남아 회사 프로그램에 적용해 볼 수 있을까 싶어 시작한게 이번 공부였다. 조금 더 공부하면 회사에 이득이 될만 하겠다.

 

mysql과의 연동에서 애를 먹었고, 아직 익숙지 못한 콜백에 그리고 자바스크립트의 새로운 문법들에 살짝(많이💢;;;) 당황했다. PUG 템플릿은 생각보다 간단했지만 깊게 사용하려면 더 배워야 한다.

개발일을 오래했지만 그리고 항상 새로운 기술이 나온다고 나름대로 공부📚한다고 했지만 역시 우물안의 개구리🐸였다.

 

늦은 나이🧓지만 계속해서 개발💻을 하기위해선 더 정진해야겠다. 초심으로 돌아가서...

+ Recent posts