공부 저장소/Node.js

[생활코딩 Node.js+MySQL] 3. 글 상세보기 만들기

tipsygypsy 2022. 8. 10. 21:44

DB를 이용한 상세보기 기능 추가하기

목록을 불러왔으니 이제 제목을 클릭하면 내용이 나오도록 만들 차례이다. 내용은 TOPIC 테이블의 DESCRIPTION 컬럼의 값이다. 제목을 눌렀을 때 출력되는 화면의 코드는 path가 ‘/’이고 id값이 존재하는 경우의 조건문이다. 이 부분을 고쳐본다.

 

일단 상세보기 화면에서도 글목록은 출력되어야 하니까 홈 화면과 동일하게 SELECT * FROM TOPIC 쿼리를 날리는 것으로 시작한다. 그리고 여기서의 결과값은 여러 개의 제목들이니까 topics라고 하고(뭐라고 정하든 아무 상관없지만…), 에러를 throw 처리해준다. throw는 에러가 발생하면 아래의 내용을 무시하고 바로 에러 페이지를 띄우는 코드이다. 이 부분의 코드는 이렇게 된다.

db.query(`SELECT * FROM TOPIC`, function(err, topics){
        if(err){
          throw err;
        });

 

이제 내용을 불러와야 하기 때문에, 첫번째 db.query 안에 쿼리를 하나 더 넣어 준다.쿼리id값에 해당하는 DESCRIPTION을 조회하는 쿼리이다. 이 때, ID값에 바로 쿼리데이터 값을 넣게 되면 DB에 날아가는 쿼리문을 외부에서 마음대로 만들 수 있기 때문에 보안에 취약해진다. 따라서 쿼리문에서 조건을 받을 때는 직접 넣지 않고, 쿼리문 내부에는 변수를 ?(물음표)로 처리한 뒤 쉼표 뒤에 배열로 값을 넣어주는 형태를 사용한다.

db.query(`SELECT * FROM TOPIC`, function(err, topics){
        if(err){
          throw err;
        }
        db.query(`SELECT * FROM TOPIC WHERE ID = ?`,[queryData.id], function(err2, topic){
          if(err2){
            throw err2;
          }

 

그리고 이 부분에 HTML 템플릿을 넣는다. 두번째 쿼리문의 결과값을 topic이라고 명명했으니까 내용을 가져올 때는 topic[0].컬럼명 이라고 지정한다. 어차피 조건을 넣었기 때문에 한 row만 조회되겠지만 그래도 배열 부분을 꼭 넣어야 한다. 기존의 파일read 부분을 쿼리 결과값 호출로 적당히 바꿔 준 최종 수정본 코드는 다음과 같다.

else {
      db.query(`SELECT * FROM TOPIC`, function(err, topics){
        if(err){
          throw err;
        }
        db.query(`SELECT * FROM TOPIC WHERE ID = ?`,[queryData.id], function(err2, topic){
          if(err2){
            throw err2;
          }
          var title = topic[0].title;
          var description = topic[0].description;
          var list = template.list(topics);
          var html = template.HTML(title, list,
            `<h2>${title}</h2>${description}`,
            ` <a href="/create">create</a>
            <a href="/update?id=${queryData.id}">update</a>
            <form action="delete_process" method="post">
            <input type="hidden" name="id" value="${queryData.id}">
            <input type="submit" value="delete">
            </form>`
          );
          response.writeHead(200);
          response.end(html);
        });
      });
    }

조회해 보면 각 데이터가 잘 나오는 것을 확인할 수 있다.

 

 

전체보기(main.js)

더보기
var http = require('http');
var fs = require('fs');
var url = require('url');
var qs = require('querystring');
var template = require('./lib/template.js');
var path = require('path');
var sanitizeHtml = require('sanitize-html');
var mysql = require('mysql');
var db = mysql.createConnection({
  host     : 'localhost',
  user     : 'root',
  password : 'pass12',
  database : 'opentutorials'
});
db.connect();

var app = http.createServer(function(request,response){
  var _url = request.url;
  var queryData = url.parse(_url, true).query;
  var pathname = url.parse(_url, true).pathname;
  if(pathname === '/'){
    if(queryData.id === undefined){
      db.query(`SELECT * FROM TOPIC`, function(err, topics){
        var title = 'Welcome';
        var description = 'Hello, Node.js';
        var list = template.list(topics);
        var html = template.HTML(title, list,
          `<h2>${title}</h2>${description}`,
          `<a href="/create">create</a>`
        );
        response.writeHead(200);
        response.end(html);
      });
    } else {
      fs.readdir('./data', function(error, filelist){
        var filteredId = path.parse(queryData.id).base;
        fs.readFile(`data/${filteredId}`, 'utf8', function(err, description){
          var title = queryData.id;
          var sanitizedTitle = sanitizeHtml(title);
          var sanitizedDescription = sanitizeHtml(description, {
            allowedTags:['h1']
          });
          var list = template.list(filelist);
          var html = template.HTML(sanitizedTitle, list,
            `<h2>${sanitizedTitle}</h2>${sanitizedDescription}`,
            ` <a href="/create">create</a>
            <a href="/update?id=${sanitizedTitle}">update</a>
            <form action="delete_process" method="post">
            <input type="hidden" name="id" value="${sanitizedTitle}">
            <input type="submit" value="delete">
            </form>`
          );
          response.writeHead(200);
          response.end(html);
        });
      });
    }
  } else if(pathname === '/create'){
    fs.readdir('./data', function(error, filelist){
      var title = 'WEB - create';
      var list = template.list(filelist);
      var html = template.HTML(title, list, `
        <form action="/create_process" method="post">
        <p><input type="text" name="title" placeholder="title"></p>
        <p>
        <textarea name="description" placeholder="description"></textarea>
        </p>
        <p>
        <input type="submit">
        </p>
        </form>
        `, '');
        response.writeHead(200);
        response.end(html);
      });
    } else if(pathname === '/create_process'){
      var body = '';
      request.on('data', function(data){
        body = body + data;
      });
      request.on('end', function(){
        var post = qs.parse(body);
        var title = post.title;
        var description = post.description;
        fs.writeFile(`data/${title}`, description, 'utf8', function(err){
          response.writeHead(302, {Location: `/?id=${title}`});
          response.end();
        })
      });
    } else if(pathname === '/update'){
      fs.readdir('./data', function(error, filelist){
        var filteredId = path.parse(queryData.id).base;
        fs.readFile(`data/${filteredId}`, 'utf8', function(err, description){
          var title = queryData.id;
          var list = template.list(filelist);
          var html = template.HTML(title, list,
            `
            <form action="/update_process" method="post">
            <input type="hidden" name="id" value="${title}">
            <p><input type="text" name="title" placeholder="title" value="${title}"></p>
            <p>
            <textarea name="description" placeholder="description">${description}</textarea>
            </p>
            <p>
            <input type="submit">
            </p>
            </form>
            `,
            `<a href="/create">create</a> <a href="/update?id=${title}">update</a>`
          );
          response.writeHead(200);
          response.end(html);
        });
      });
    } else if(pathname === '/update_process'){
      var body = '';
      request.on('data', function(data){
        body = body + data;
      });
      request.on('end', function(){
        var post = qs.parse(body);
        var id = post.id;
        var title = post.title;
        var description = post.description;
        fs.rename(`data/${id}`, `data/${title}`, function(error){
          fs.writeFile(`data/${title}`, description, 'utf8', function(err){
            response.writeHead(302, {Location: `/?id=${title}`});
            response.end();
          })
        });
      });
    } else if(pathname === '/delete_process'){
      var body = '';
      request.on('data', function(data){
        body = body + data;
      });
      request.on('end', function(){
        var post = qs.parse(body);
        var id = post.id;
        var filteredId = path.parse(id).base;
        fs.unlink(`data/${filteredId}`, function(error){
          response.writeHead(302, {Location: `/`});
          response.end();
        })
      });
    } else {
      response.writeHead(404);
      response.end('Not found');
    }
  });
  app.listen(3000);